| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1353 人关注过本帖, 1 人收藏
标题:[求助]求neosdk里面nsound 的详细资料-->baidu转移
只看楼主 加入收藏
qingfen
Rank: 1
等 级:新手上路
帖 子:53
专家分:0
注 册:2005-12-23
收藏(1)
 问题点数:0 回复次数:4 
[求助]求neosdk里面nsound 的详细资料-->baidu转移
现在我在用neosdk写一个播放程序,但是neosdk库里面没有提供单个音频数据的播放,现在我想要一些关于neosdk里面nsoud.h里面对dsp控制的详细资料!!!
谢谢!!!
搜索更多相关主题的帖子: neosdk里面 baidu nsound dsp 详细资料 
2006-07-21 15:07
jig
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
帖 子:530
专家分:242
注 册:2005-12-27
收藏
得分:0 

其实很简单,只是对声卡DSP芯片个端口的操作而已,这方面的资料的确很少,我这几天也在研究它,希望真的用小内存做出播发任意长度的文件,还想自己做个语音识别的程序。

其实控制声卡DSP芯片播发声音(这里只指播发WAV格式)有两种方式,第一是直接以块的方式,即把声音信息一并送入DSP芯片交给DSP芯片处理,这样的好处是播发流畅,而且不用操心采样率,直接交给DSP芯片就完了,而且在程序中表现想是多线程,即声音播放的同时,其实程序已经跑后面去了,所以很适合在游戏用到他,可不足之处就是因为DOS无大内存给你使用,所以播放的声音长度也就限制了,只能是64K以内,NEO中即使用此种方法。

第二中方法就是,你自己写一个模块实现采样率,再逐个把数据送入DSP芯片,这样的好处是(当然是你先修改时钟出发频率,然后自己设置一个中断,以几数的方式来实现以指定时间间隔往DSP芯片送数据为前提)可以播放任意长度的声音文件,可他的不足就是:因为你是以CPU来模拟实现采样率,所以在此线程中是先播发完文件才能执行后面的代码,最致命的就是播放声音可能不流畅,因为你是自己用实现的修改时钟出发频率,然后自己设置一个中断,进而记数来实现间隔,那在这个过程中你很难保证间隔是一直恒定的(比如要是另个程序当机,很可能回影响到你自己播放程序)......但我鼓励大家可以一试来实现本方法,有挑战些。

下面我给出第一法的一个程序,写的很好,董凯给的,不知道是他些的否?风格很好,很容易看懂

#include <dos.h>
#include <stdio.h>

#ifndef FP_OFF
#define FP_OFF(fp) ((unsigned)(fp))
#endif
#ifndef FP_SEG
#define FP_SEG(fp) ((unsigned)((unsigned long)(fp) >> 16))
#endif

#define DIGI_AUTODETECT 1 /* 让 Allegro 来选择一个数字声音驱动设备*/
#define DIGI_NONE 0 /* 无数字声音*/
#define DIGI_SB 100 /* Sound Blaster (自动检测类型)*/
#define DIGI_SB10 110 /* SB 1.0 (8 位单声道 单一发射 dma)*/
#define DIGI_SB15 115 /* SB 1.5 (8 位单声道 单一发射 dma)*/
#define DIGI_SB20 120 /* SB 2.0 (8 位单声道 自动初始化 dma)*/
#define DIGI_SBPRO 108 /* SB Pro (8 位立体声)*/
#define DIGI_SB16 116 /* SB16 (16 位立体声)*/
#define DIGI_AUDIODRIVE 200 /* ESS AudioDrive*/
#define DIGI_SOUNDSCAPE 300 /* Ensoniq Soundscape*/

/*midi_card 应当是以下值中的一个*/
#define MIDI_AUTODETECT 1 /* 让 Allegro 挑选一个 MIDI 声音驱动程序*/
#define MIDI_NONE 0 /* 无 MIDI 声音*/
#define MIDI_ADLIB /* Adlib 或 SB FM 混合 (自动检测型号)*/
#define MIDI_OPL2 /* OPL2 混合 (单声道, 在 Adlib 和 SB 下使用)*/
#define MIDI_2XOPL2 /* 双 OPL2 混合 (立体声, 在 SB-Pro-I 下使用)*/
#define MIDI_OPL3 /* OPL3 混合 (立体声, SB Pro-II 及以上)*/
#define MIDI_SB_OUT /* SB MIDI 界面*/
#define MIDI_MPU /* MPU-401 MIDI 界面*/
#define MIDI_DIGMID /* 基于采样的软件波表播放器*/
#define MIDI_AWE32

#define PCM_HEAD_LONG 50
#define PLAY_DELAY 100


typedef struct WaveData
{
unsigned short sample_lenth;
unsigned short rate;
unsigned short channels;
unsigned char time_constant;
char bit_res;

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]; /*过渡字节*/
};

unsigned short g_base; /*声卡基址*/
unsigned short g_port;

void write_dsp( unsigned char value );
short ResetDSP ( unsigned short Test );
void set_mixer_reg(short index, char value);
short install_sound(short digi_card, short midi_card, char *cfg_path);
short play_sample(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)

main()
{
SAMPLE *wav;
install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);set_mixer_reg(0, 0);
wav = load_wav("act.wav");set_mixer_reg(0x26, 0x0);
play_sample(wav, 255, 128, 1000, 1); getch();destroy_sample(wav);
wav = load_wav("win.wav");set_mixer_reg(0x26, 0x0f);
play_sample(wav, 255, 128, 1000, 1); getch();destroy_sample(wav);
wav = load_wav("down.wav");set_mixer_reg(0x26, 0);
play_sample(wav, 255, 128, 1000, 1); getch();destroy_sample(wav);
wav = load_wav("sound.wav");set_mixer_reg(0x26, 0xaa);
play_sample(wav, 255, 128, 1000, 1); getch();destroy_sample(wav);
wav = load_wav("levup.wav");set_mixer_reg(0x26, 0x55);
play_sample(wav, 255, 128, 1000, 1); destroy_sample(wav);
getch();
remove_sound();
}

short install_sound(short digi_card, short midi_card, char *cfg_path)
{
if (digi_card)
{
if ( ResetDSP (0x220) )
{
/*基址为210h*/
g_port = 0x220;
}
else if (ResetDSP (0x230))
{
/*基址为220h*/
g_port = 0x230;
}
else if (ResetDSP (0x240))
{
/*基址为240h*/
g_port = 0x240;
}
else
{
/*基址检测失败*/
g_port = -1;
return 0;
}
}
if (midi_card)
{}
cfg_path += 0; /*只是为了不报警*/
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);
}


void set_mixer_reg(short index, char value)
{
outportb (g_port + 4, index);
outportb (g_port + 5, 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)
{
printf ("Can't open the file: %s\n", filename);
return (NULL);
}
voice = (SAMPLE *)malloc(sizeof(SAMPLE));
if ( voice == NULL)
{ printf ( " Not mem!\n" );
return NULL;
}

/*读取文件头部*/
fread ( &t_header, sizeof(t_header), 1, wav_file );
/*检查RIFF头*/
if ( t_header.riff != 0x46464952)
{
printf ( " Not a wave file!\n" );
return ( NULL );
}
/*检查通道*/
if ( t_header.Channels != 1 )
{
printf ( "Not a MONO wave file!\n" );
return ( NULL );
}
/*检查采样位数*/
if ( t_header.sample_bits != 8 )
{
printf ( "Not an 8-bit wave file!\n" );
return ( NULL );
}

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)
{
printf ( " Not mem!!\n" );
fclose ( wav_file ); /*关闭文件*/
return NULL;
}
/*fseek(wav_file, 57L, SEEK_SET);*/
/*读取采样数据流*/
fread ( voice->sample, voice->sample_lenth + 1, 1, wav_file );
fclose ( wav_file ); /*关闭文件*/
return voice;
}


short play_sample(SAMPLE *spl, short vol, short pan, short freq, short loop)
{

vol += 0;
pan += 0;
freq+= 0;
loop+= 0;

if (spl)
{
/*开始回放*/
play_back(spl);
delay(PLAY_DELAY);
/*停止 DMA 传送*/
write_dsp(0xD0);
return 1;
}
return 0;
}


void stop_sample(SAMPLE *spl)
{
/* 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();
}


第二方法,我这也有个代码,可是错的,根本编译不通过。
我本是早想写个声卡DSP的专题文章,就是因为一直没去把第二法实现所以一直没发,可能过两日我回发给这样的专题,好好的介绍一下声卡的控制......
(当然,我自己也在摸索阶段,因为基本没有关于DSP声卡芯片个端口具体详实的介绍,所以有时候很为难,我们大家也只好尽力而为)


个人网站 -  http://.h001.
2006-07-21 20:16
qingfen
Rank: 1
等 级:新手上路
帖 子:53
专家分:0
注 册:2005-12-23
收藏
得分:0 
我写的程序就是要用到第二种方法控制它的播放进度,我现在也正在尝试.所以谢谢你给的资料~~~!!!
对了我在其它资料里看的dsp控制播放的指令为0x10的,怎么上面用的是0x14呢.
2006-07-22 21:01
jig
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
帖 子:530
专家分:242
注 册:2005-12-27
收藏
得分:0 
0X14即第一法,是一块的形式把一段数据送往DSP芯片


0X10即是第二种方法,是逐个的将数据送往DSP芯片


先前说要播放长文件需使用第二法,可我现在已经用第一法写出了,可以播放任意长度的文件的例子,而且可以播放流畅,比第二发要好许多,因为也是采用整块读取,唯一不足就是块块的接口处总有点小杂音,。。。。。。

我 会在论坛写片文章详细介绍此法的过程,LZ若感兴趣就关注吧

[此贴子已经被作者于2006-7-23 5:32:42编辑过]


个人网站 -  http://.h001.
2006-07-23 02:48
qingfen
Rank: 1
等 级:新手上路
帖 子:53
专家分:0
注 册:2005-12-23
收藏
得分:0 

哦这样呀,那就小弟
谢谢了!!!!!

2006-07-29 20:12
快速回复:[求助]求neosdk里面nsound 的详细资料-->baidu转移
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.011832 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved