程序作用:播放WAV声音。DOS播放任意长度WAV音乐。
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <mem.h>
#include <dos.h>
/* 以下是 PC 机的 DMA 控制器端口的常量定义 */
#define DMA8_CMD_PORT 0x08 /* 8位DMA写命令寄存器端口 */
#define DMA8_STATU_PORT 0x08 /* 8位DMA独状态寄存器端口 */
#define DMA8_REQUEST_PORT 0x09 /* 8位DMA写请求寄存器端口 */
#define DMA8_MASK_PORT 0x0A /* 8位DMA屏蔽寄存器端口(只写)*/
#define DMA8_MODE_PORT 0x0B /* 8位DMA写模式寄存器端口 */
#define DMA8_CLRPTR_PORT 0x0C /* 8位DMA清先后状态寄存器端口 */
#define DMA8_RESET_PORT 0x0D /* 8位DMA写复位命令端口 */
/* 以下是 PC 机 DMA 的 7 个通道的地址寄存器、计数寄存器和页面寄存器的端口常量定义 */
/* 其中通道 0-3 用于 8 位的 DMA,通道 4-7 用于 16 位 DMA */
/* PC机中,规定通道 2 用于进行软盘的 DMA 传输,其余通道可供用户使用 */
#define DMA0_ADDR_PORT 0x00 /* 通道0的地址寄存器 */
#define DMA0_COUNT_PORT 0x01 /* 通道0的计数寄存器 */
#define DMA0_PAGE_PORT 0x87 /* 通道0的页面寄存器 */
#define DMA1_ADDR_PORT 0x02 /* 通道1的地址寄存器 */
#define DMA1_COUNT_PORT 0x03 /* 通道1的计数寄存器 */
#define DMA1_PAGE_PORT 0x83 /* 通道1的页面寄存器 */
#define DMA3_ADDR_PORT 0x06 /* 通道3的地址寄存器 */
#define DMA3_COUNT_PORT 0x07 /* 通道3的计数寄存器 */
#define DMA3_PAGE_PORT 0x82 /* 通道3的页面寄存器 */
#define DMA5_ADDR_PORT 0xC4 /* 通道5的地址寄存器 */
#define DMA5_COUNT_PORT 0xC6 /* 通道5的计数寄存器 */
#define DMA5_PAGE_PORT 0x8B /* 通道5的页面寄存器 */
#define DMA6_ADDR_PORT 0xC8 /* 通道6的地址寄存器 */
#define DMA6_COUNT_PORT 0xCA /* 通道6的计数寄存器 */
#define DMA6_PAGE_PORT 0x89 /* 通道6的页面寄存器 */
#define DMA7_ADDR_PORT 0xCC /* 通道7的地址寄存器 */
#define DMA7_COUNT_PORT 0xCE /* 通道7的计数寄存器 */
#define DMA7_PAGE_PORT 0x8A /* 通道7的页面寄存器 */
/* DSP 定义 */
#define DSP_RESET_DELAY 10
#define DSP_READY 0xAA
#define DSP_GET_VERSION 0xE1
#define DSP_SET_BLK_SIZE 0x48
#define DSP_START_DMA8 0x1C
#define DSP_PAUSE_DMA8 0xD0
#define DSP_SET_SAM_RATE 0x40
#define PIC_PORT_21H 0x21
#define PIC_PORT_20H 0x20
#define PIC_EOI 0x20
/*数据块大小必须<51199*/
#define DMA_BUFFER_SIZE 51198
#define TRUE 1
#define FALSE 0
typedef struct
{
unsigned short wavetype; /* WAVE的类别 */
unsigned short channel; /* 通道数 */
unsigned short samplerate; /* 采样频率 */
unsigned short samplebits; /* 采样位数 */
long int datalen; /* 数据长度 */
long int leftdatalen; /* 剩余数据长度 */
int loops; /* 播放次数 */
FILE *fp;
} WAVE, *PWAVE;
typedef struct
{
char dspenvstr[128];
unsigned short dspversion;
unsigned short dspbaseioport;
unsigned short resetport;
unsigned short writedataport;
unsigned short writestatusport;
unsigned short readdataport;
unsigned short readstatusport;
unsigned short mixerbaseioport;
unsigned short mpu401baseioport;
unsigned char dspirqnum;
unsigned char dspdma8;
unsigned char dspdma16;
} DSP, *PDSP;
/* WAVE 文件结构定义 */
typedef struct
{
char RIFF[4]; /* RIFF */
unsigned long int filelen; /* 文件长度 */
char WAVEfmt[8]; /* WAVEfmt */
unsigned long int reserved; /* 保留 */
unsigned short wavetype; /* WAVE的类别 */
unsigned short channel; /* 通道数目 */
unsigned short sampling; /* 采样频率 */
unsigned long int transpeed; /* 数据传输速率 */
unsigned short blkalign; /* 调整数据块 */
unsigned short sampbits; /* 采样位数 */
char data[4]; /* data */
unsigned long int datalen; /* 语音数据长度 */
unsigned char *pdata; /* 数据区 */
} WAVEFILE, *PWAVEFILE;
int initsound(void);
void closesound(void);
int loadwave(PWAVE pwave, char *file);
void destroywave(PWAVE pwave);
void playwave(PWAVE pwave);
void stopwave(PWAVE pwave);
void pausewave(PWAVE pwave);
int initpic(int irqnum);
void closepic(int irqnum);
void picintdone(void);
int initdsp(PDSP pdsp);
void writedsp(PDSP pdsp, unsigned char byte);
void setdspblocksize(PDSP pdsp, unsigned short blksize);
void dspstartdma8(PDSP pdsp);
void dsppausedma8(PDSP pdsp);
void dspsetsamplerate(PDSP pdsp, unsigned short rate);
int initdma8(int channel, unsigned char far *addr, int size);
void closedma8(int channel);
void interrupt (*old_dsp_int_handle)(void) = NULL;
void interrupt new_zhong_duan(void);
void an_zhuang_zhong_duan(void);
void del_zhong_duan(void);
DSP cursbdsp = {0};
PWAVE pcurwave = NULL;
int dma_buf_flag = NULL;
unsigned char far *sound_dma_buf = NULL;
int parse_sb_envstr(char *envstr, char id);
int initdma8(int channel, unsigned char far *addr, int size)
{
unsigned long phyaddr = FP_SEG(addr) * 0x10L + FP_OFF(addr);
unsigned char page = (unsigned char)(phyaddr >> 16);
unsigned short offset = (unsigned short)(phyaddr >> 0);
outportb(DMA8_MASK_PORT, channel | (1 << 2)); /* 屏蔽该通道 */
outportb(DMA8_MODE_PORT, channel | (1 << 4) | (2 << 2)); /* 请求方式+自动初始化+读传送 */
outportb(DMA8_CLRPTR_PORT, 0);
outportb(DMA1_COUNT_PORT, (size - 1)& 0x00FF);
outportb(DMA1_COUNT_PORT, (size - 1) >> 8);
outportb(DMA1_ADDR_PORT, (offset)& 0x00FF);
outportb(DMA1_ADDR_PORT, (offset) >> 8);
outportb(DMA1_PAGE_PORT, page);
outportb(DMA8_MASK_PORT, channel);
return TRUE;
}
void closedma8(int channel)
{
if (channel > 3 || channel == 2) return;
outportb(DMA8_MASK_PORT, channel | (1 << 2)); /* 屏蔽该通道 */
}
int parse_sb_envstr(char *envstr, char id)
{
char buf[32] = "0x";
int i;
int j;
for (i = 0; envstr[i] != id && envstr[i] != '\0' && i < 128; i++);
if (envstr[i] == '\0' || i == 128) return 0;
else i++;
for (j = 2; j < 32 && envstr[i] != ' '; j++) buf[j] = envstr[i++];
return (int)strtoul(buf, NULL, 0);
}
/* 函数实现 */
int initdsp(PDSP pdsp)
{
if (!getenv("BLASTER")) return FALSE;
strupr(strcpy(pdsp->dspenvstr, getenv("BLASTER")));
pdsp->dspbaseioport = parse_sb_envstr(pdsp->dspenvstr, 'A');
pdsp->resetport = pdsp->dspbaseioport + 0x06; /*复位端口*/
pdsp->writedataport = pdsp->dspbaseioport + 0x0C; /*写数据端口*/
pdsp->writestatusport = pdsp->dspbaseioport + 0x0C; /*写状态端口*/
pdsp->readdataport = pdsp->dspbaseioport + 0x0A; /*读数据端口*/
pdsp->readstatusport = pdsp->dspbaseioport + 0x0E; /*读状态端口*/
pdsp->dspirqnum = parse_sb_envstr(pdsp->dspenvstr, 'I');
pdsp->dspdma8 = parse_sb_envstr(pdsp->dspenvstr, 'D');
pdsp->dspdma16 = parse_sb_envstr(pdsp->dspenvstr, 'H');
pdsp->mixerbaseioport = parse_sb_envstr(pdsp->dspenvstr, 'M');
pdsp->mpu401baseioport = parse_sb_envstr(pdsp->dspenvstr, 'P');
writedsp(pdsp, DSP_GET_VERSION);
return TRUE;
}
void writedsp(PDSP pdsp, unsigned char byte)
{
outportb(pdsp->writedataport, byte);
}
void setdspblocksize(PDSP pdsp, unsigned short blksize)
{
writedsp(pdsp, DSP_SET_BLK_SIZE);
writedsp(pdsp, (blksize - 1) &0x00FF);
writedsp(pdsp, (blksize - 1) >> 8);
}
void dspstartdma8(PDSP pdsp)
{
writedsp(pdsp, DSP_START_DMA8);
}
void dsppausedma8(PDSP pdsp)
{
writedsp(pdsp, DSP_PAUSE_DMA8);
}
void dspsetsamplerate(PDSP pdsp, unsigned short rate)
{
unsigned short timeconst = (unsigned short)(65536L - (256000000L / rate));
writedsp(pdsp, DSP_SET_SAM_RATE);
writedsp(pdsp, timeconst >> 8);
}
int initpic(int irqnum)
{
unsigned char mask;
mask = inportb(PIC_PORT_21H);
mask &= ~(1 << irqnum);
outportb(PIC_PORT_21H, mask);
}
void closepic(int irqnum)
{
unsigned char mask;
mask = inportb(PIC_PORT_21H);
mask |= (1 << irqnum);
outportb(PIC_PORT_21H, mask);
}
void picintdone(void)
{
outportb(PIC_PORT_20H, PIC_EOI); /* 写中断结束命令 */
}
int initsound(void)
{
sound_dma_buf = (unsigned char far *)malloc(DMA_BUFFER_SIZE);
if (!sound_dma_buf) return FALSE;
initdsp(&cursbdsp);
setdspblocksize(&cursbdsp, DMA_BUFFER_SIZE / 2);
initdma8(cursbdsp.dspdma8, sound_dma_buf, DMA_BUFFER_SIZE);
initpic(cursbdsp.dspirqnum);
an_zhuang_zhong_duan();
return TRUE;
}
void closesound(void)
{
del_zhong_duan();
closepic(cursbdsp.dspirqnum);
closedma8(cursbdsp.dspdma8);
if (sound_dma_buf) free((void*)sound_dma_buf);
}
/* 装载WAVE 文件到 WAVE 对象 */
int loadwave(PWAVE pw, char *file)
{
WAVEFILE wf;
pw->fp = fopen(file,"rb");
if (!pw->fp) return FALSE;
fread(&wf, sizeof(wf), 1, pw->fp);
pw->wavetype = wf.wavetype;
pw->channel = wf.channel;
pw->samplerate = wf.sampling;
pw->samplebits = wf.sampbits;
pw->datalen = wf.filelen - sizeof(wf) - 14;
pw->leftdatalen = wf.filelen - sizeof(wf) - 14;
fseek(pw->fp, 14, SEEK_CUR);
return TRUE;
}
/* 销毁 WAVE 对象 */
void destroywave(PWAVE pw)
{
fclose(pw->fp);
pw->fp = NULL;
}
void playwave(PWAVE pwave)
{
pcurwave = pwave;
dma_buf_flag = FALSE;
fread((void*)sound_dma_buf, DMA_BUFFER_SIZE, 1, pcurwave->fp);
initdma8(cursbdsp.dspdma8, sound_dma_buf, DMA_BUFFER_SIZE);
dspsetsamplerate(&cursbdsp, pcurwave->samplerate*pcurwave->channel);
dspstartdma8(&cursbdsp);
}
void stopwave(PWAVE pwave)
{
dsppausedma8(&cursbdsp);
fseek(pcurwave->fp, sizeof(WAVEFILE) + 14, SEEK_SET);
pwave->leftdatalen = pwave->datalen;
}
void pausewave()
{
dsppausedma8(&cursbdsp);
}
/* 内部函数实现 */
void interrupt new_zhong_duan(void)
{
pcurwave->leftdatalen -= DMA_BUFFER_SIZE / 2;
fread((void*)(sound_dma_buf + dma_buf_flag * DMA_BUFFER_SIZE / 2),1, DMA_BUFFER_SIZE / 2, pcurwave->fp);
dma_buf_flag = ! dma_buf_flag;
picintdone();
sleep(1);
}
void an_zhuang_zhong_duan(void)
{
old_dsp_int_handle = getvect(cursbdsp.dspirqnum + 8);
setvect(cursbdsp.dspirqnum + 8, new_zhong_duan);
}
void del_zhong_duan(void)
{
setvect(cursbdsp.dspirqnum + 8, old_dsp_int_handle);
old_dsp_int_handle = NULL;
}
main()
{
WAVE mywave = {0};
initsound();
loadwave(&mywave, "test.wav");
mywave.loops = -1;
playwave(&mywave);
getch();
destroywave(&mywave);
closesound();
}
成功解决C语言中断占用CPU问题~
哈哈,乱说的。只是用SLEEP函数把程序挂起。没办法WINDWOS操作系统支持的不是很好。
我发现添加个SLEEP函数后,杂音没了!
添加个键盘中断,想控制。没成功。开始是在main函数中动手脚,添加个判断:while(sigh) printf("1");
sigh初始值是1,判断键盘按下后值为0,但是,在main中循环时间只是从DMA一个块播放完毕就不循环了。应该是被SLEEP挂起了。
纠结!
在键盘中断服务程序中禁止中断:
int initpic((int)&new_zhong_duan);
未成功。
程序总是无法自己结束。({dy}个块播放之后按)
有时间继续。。。睡觉。
键盘中断代码:
void keyboard(void) //设置中断
{
oldint = getvect(9);
setvect(9,newint);
}
void interrupt newint() //服务程序
{
}
void huifu()
{
setvet(9,oldint);
}