📄 nsound.h
字号:
/*NEO SDK V2.1.90 For DOS
Copyleft Cker Home 2003-2006.
Open Source Obey NEO_PL.TXT.
http://neo.coderlife.net
ckerhome@yahoo.com.cn
文件名称 : nsound.h
摘 要 : 本头文件中包含了NEO SDK里有关音频播放的函数、结构、全局变量的声明定义
目前支持格式:标准波形文件wav(PCM 8位 单/双声道)
当前版本 : V0.67
作 者 : 董凯
完成日期 : 2006.01.18
取代版本 : V0.66
原 作 者 : 董凯
完成日期 : 2005.12.29
*/
#ifndef __NSOUND_H__
#define __NSOUND_H__
#ifndef NEO_sound_unused
#define PCM_HEAD_LONG 50
#define PLAY_DELAY 100
typedef struct WaveData
{
FILE *fp;
long pos; /*当前WAV文件播放进度*/
unsigned short sample_lenth; /*音频缓冲块的尺寸*/
unsigned short rate;
unsigned short channels;
unsigned char time_constant;
char loop;
char *sample;
}SAMPLE;
struct HeaderType
{
long riff; /*RIFF类资源文件头部*/
unsigned long file_len; /*文件长度*/
char wave[4]; /*"WAVE"标志*/
char fmt [4]; /*"fmt"标志*/
char NI1 [4]; /*过渡字节*/
unsigned short format_type;/*格式类别(10H为PCM形式的声音数据)*/
unsigned short Channels; /*Channels 1 = 单声道; 2 = 立体声*/
long frequency; /*采样频率*/
long trans_speed;/*音频数据传送速率*/
char NI2 [2]; /*过渡字节*/
short sample_bits;/*样本的数据位数(8/16)*/
char data[4]; /*数据标记符"data"*/
unsigned long wav_len; /*语音数据的长度*/
char NI3 [4]; /*过渡字节*/
};
/*char g_last_wav[PATH_LENGTH] = {'\0'}; */
unsigned short g_base; /*声卡基址*/
unsigned short g_port;
/*long sb_hw_dsp_ver = -1;*/
SAMPLE *g_sample;
void write_dsp( unsigned char value );
short ResetDSP ( unsigned short Test );
void _sb_set_mixer(short index, char value);
short install_sound(void);
short play_sample_ex(SAMPLE *spl, short vol, short pan, short freq, short loop);
SAMPLE *load_wav(char *filename);
char play_back (SAMPLE *wave);
void stop_sample(SAMPLE *spl);
void destroy_sample(SAMPLE *spl);
void remove_sound(void);
/*为兼容以前版本而增置*/
#define reset_dsp() ResetDSP(g_port)
#define play_sample(mode) play_sample_ex(SAMPLE *g_sample, 255, 255, 0, mode)
#define clear_digi_buffer()
#define set_port(port)
#define set_irq(irq)
#define set_dma(dma)
short install_sound(void)
{
/*if (digi_card)
{*/
if ( ResetDSP (0x220) )
{
/*基址为220h*/
g_port = 0x220;
}
else if (ResetDSP (0x230))
{
/*基址为230h*/
g_port = 0x230;
}
else if (ResetDSP (0x240))
{
/*基址为240h*/
g_port = 0x240;
}
else
{
/*基址检测失败*/
g_port = -1;
return 0;
}
/*}
if (midi_card)
{}*/
g_routines |= 64;
return 1;
}
/****************************************************************************
检查一个声卡基址是否存在,如果存在则将声卡复位 *
****************************************************************************/
short ResetDSP(unsigned short Test)
{
/*重置DSP*/
outportb (Test + 0x6, 1);
delay(50);
outportb (Test + 0x6, 0);
delay(50);
/*如果重置成功则检查*/
if (( (inportb(Test + 0xE) & 0x80) == 0x80) && (inportb(Test + 0xA) == 0xAA))
{
/*DSP被找到*/
g_base = Test;
return (1);
}
else
{ /*找不到DSP*/
return (0);
}
}
/****************************************************************************
** 发送一个字节到声卡的DSP(数字信号处理芯片:Digital Signal Processor) **
****************************************************************************/
void write_dsp(unsigned char value)
{
/*等待DSP接收一个字节*/
while ((inportb(g_base + 0xC) & 0x80) == 0x80);
/*发送字节*/
outportb (g_base + 0xC, value);
}
/****************************************************************************
** 播放内存中的部分音频流 **
****************************************************************************/
char play_back (SAMPLE *wave)
{
long LinearAddress;
unsigned short page, offset;
if ((!wave) || (!wave->sample))
{
printf("no sample!");
return 0;
}
/*开启声卡*/
write_dsp( 0xD1 );
write_dsp( 0x40 ); /*DSP第40h号命令 :设置采样频率*/
write_dsp( wave -> time_constant ); /*Write time constant*/
/*将音频流指针转换成线性地址*/
LinearAddress = FP_SEG ( wave -> sample );
LinearAddress = ( LinearAddress << 4 ) + FP_OFF ( wave->sample );
page = LinearAddress >> 16; /*计算页*/
offset = LinearAddress & 0xFFFF; /*计算页偏移*/
/*注意 :这个操作只能工作于DMA的第一通道*/
outportb (0x0A, 5); /*Mask 锁DMA通道一*/
outportb (0x0C, 0); /*清除DMA内部翻转标志*/
outportb (0x0B, 0x49); /*设置成回(播)放模式*/
/*
模式由下面几项组成:
0x49 = 二进制 01 00 10 01
| | | |
| | | +- DMA通道 01
| | +---- 读操作 (从内存到DSP)
| +------- 单一周期方式
+---------- 块方式
*/
outportb ( 0x02, offset & 0x100); /*将偏移量写入DMA控制器*/
outportb ( 0x02, offset >> 8);
outportb ( 0x83, page); /*将页面写入DMA控制器*/
outportb ( 0x03, wave->sample_lenth & 0x100);
outportb ( 0x03, wave->sample_lenth >> 8);
outportb ( 0x0A, 1 ); /*激活DMA通道一*/
write_dsp( 0x14 ); /*DSP第14h号命令 :单一周期回放*/
write_dsp( wave -> sample_lenth & 0xFF );
write_dsp( wave -> sample_lenth >> 8);
return 1;
}
/****************************************************************************
** 将音频文件读入内存 **
** 这个例程能操作标准的PCM文件头部 **
** 它覆行了许多错误检查 **
****************************************************************************/
SAMPLE *load_wav(char *filename)
{
struct HeaderType t_header;
FILE *wav_file;
SAMPLE *voice;
/*如果打不开文件...*/
wav_file = fopen(filename, "rb");
if (wav_file == NULL)
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", NO_FILE, 1};
throw_error(error);
#endif
return (NULL);
}
voice = (SAMPLE *)malloc(sizeof(SAMPLE));
if ( voice == NULL)
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", NO_MEMORY, 1};
throw_error(error);
#endif
return NULL;
}
/*if ((strnicmp(g_last_wav, filename, strlen(bmpfile) ) != 0)
{*/
/*读取文件头部*/
fread ( &t_header, sizeof(t_header), 1, wav_file );
/*检查RIFF头*/
if ( t_header.riff != 0x46464952L)
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", ERR_FILE_TYPE, 1};
throw_error(error);
#endif
return ( NULL );
}
/*检查通道*/
if ( t_header.Channels != 1 )
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", "Not a MONO wave file!", 1};
throw_error(error);
#endif
return ( NULL );
}
/*检查采样位数*/
if ( t_header.sample_bits != 8 )
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", "Not an 8 bits wav file!", 1};
throw_error(error);
#endif
return ( NULL );
}
/*strcpy(g_last_wav,filename);
}*/
voice->sample_lenth = (unsigned short)(t_header.file_len - PCM_HEAD_LONG);
voice->time_constant= 256 - (1000000L / ( (voice->rate=t_header.frequency) * (voice->channels=t_header.Channels) ));
if ( t_header.file_len - PCM_HEAD_LONG >= 0xffff )
{
voice->sample_lenth = 0xfffe;
}
if (voice->sample_lenth == 0) voice->sample_lenth = 1;
voice->sample = (char *) malloc ( voice->sample_lenth + 1);/*申请内存*/
if ( voice->sample == NULL)
{
#ifndef NEO_sys_report_error_unused
Errinfo_t error = {"load_wav", NO_MEMORY, 1};
throw_error(error);
#endif
fclose ( wav_file ); /*关闭文件*/
return NULL;
}
voice->pos = voice->sample_lenth;
/*fseek(wav_file, 57L, SEEK_SET);*/
/*读取采样数据流*/
fread ( voice->sample, voice->sample_lenth + 1, 1, wav_file );
fclose ( wav_file ); /*关闭文件*/
g_sample = voice;
return voice;
}
short play_sample_ex(SAMPLE *spl, short vol, short pan, short freq, short loop)
{
vol += 0;
pan += 0;
freq+= 0;
spl->loop |= loop;
if (spl)
{
/*开始回放*/
play_back(spl);
delay(PLAY_DELAY);
/*停止 DMA 传送*/
write_dsp(0xD0);
return 1;
}
return 0;
}
void stop_sample(SAMPLE *spl)
{ spl+=0;
/* SAMPLE stop;
char sam[10];
stop.sample = sam;
stop.sample_lenth = 9;
stop.time_constant= 9;
play_back(&stop);*/
}
void destroy_sample(SAMPLE *spl)
{
if (spl)
{
free(spl->sample);
spl->sample = NULL;
free(spl);
spl = NULL;
}
}
void remove_sound(void)
{
/*关闭声卡*/
write_dsp(0xD3);
/*重置DSP*/
reset_dsp();
g_routines &= 191;
}
#endif
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -