- 论坛徽章:
- 0
|
在坛里也放了几篇关于linux下音频编程方面的帖子,我知道对这方面感兴趣的人不多。但一个月的心血终有小成,欣慰之余,也愿意将自己的收获与大家分享。
关于音频编程其实不外乎这么几个方面:播放音频文件,从mic或line录制wave stream,内录,播放音量的调节,播放进度的控制等。下面就从这几个方面和大家探讨。
也许很多人试过这样的命令:cat xxx.au >;/dev/dsp,回车后就能听到声音,但声音的质量却太让人不敢恭维,为什么?因为没有设置播放参数,驱动程序是按照缺省设置来放音的,下面给出一段演示程序:
……………………
#define PCM_WAVE_FORMAT 1
#define DEFAULT_START 0
#define RECORD_RATE 48000
#define RECORD_SIZE 16
#define RECORD_CHANNELS 2
……………………
dfd = open("/dev/dsp", O_RDWR);
if(dfd == -1)
{
perror("Unable to open /dev/dsp(are you root?)\n" ;
return FALSE;
}
status = ioctl(dfd, SNDCTL_DSP_SETFMT, &arg);
if (status == -1)
{
perror("SOUND_PCM_WRITE_BITS ioctl failed" ;
return FALSE;
}
if (arg != RECORD_SIZE)
{
perror("unable to set sample size" ;
return FALSE;
}
status=ioctl(dfd,SNDCTL_DSP_SETFMT,&format);
if(status == -1)
{
perror("SNDCTL_DSP_SETFMT fail" ;
return FALSE;
}
if(format!=AFMT_S16_LE)
{
perror("unable to set format of sample" ;
return FALSE;
}
arg = RECORD_CHANNELS;
status = ioctl(dfd, SNDCTL_DSP_CHANNELS, &arg);
if (status == -1)
{
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed" ;
return FALSE;
}
if (arg != RECORD_CHANNELS)
{
perror("unable to set number of channels" ;
return FALSE;
}
arg = RECORD_RATE;
status = ioctl(dfd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1)
{
perror("SOUND_PCM_WRITE_WRITE ioctl failed" ;
return FALSE;
}
if(arg!=RECORD_RATE)
{
perror("unable to set Rate" ;
return FALSE;
}
return TRUE;
上面的各项参数代表什么意思,为什么这么设在网上有很多这样的文章,大家可以去查。初始化完音频设备后,这时我们再write音频数据到/dev/dsp,效果将会有明显的好转。
在linux下录制声音,主要就是录音设备的选择,输入输出增益的调节,同时还要控制好不要被非当前用来录音的录音设备干扰。
进行到这一步,我们必须对linux下声卡驱动有所了解。当前最有名的当数OSS(open sound system)和ALSA(Advanced Linux Sound Architecture),相对而言,oss是商业
组织开发和维护的,对硬件的支持较好,较成熟,但对于商业用途的要收费。ALSA是自由者维护的自由项目,具有更加友好的编程接口,且完全兼容于OSS,对应用程序员来讲无疑是一个更佳的选择。
这里主要是基于OSS的开发。oss对混音通道(包括mic,line,cd等等)的管理,详情见http://www.opensound.com/pguide/oss.pdf。
要选择录音源,首先需获得当前设备状态,有那些能作为录音源。看下面的代码:
int currentRecmask = 0, newrecmask = 0;
if((ioctl(dfd, SOUND_MIXER_READ_RECMASK, ¤tRecmask)) == -1)
{
return FALSE;
}
if(!((1 << device) & currentRecmask))
{
return FALSE;
}
输出currentRecmask:7356865(并不一定就是它了,它只是我当前系统的值)
转化为二进制为:11100000100000111000001。
这个值是什么意思呢?原来,oss 为每一个混音通道都定义了一个Macro,详见/usr/include/linux/soundcard.h,从0到25
上面这个二进制数从右往左就是通道宏从0到25能否用来录音的状态,1表示能,0则不能。device则表示0-25的序号,观察一下
soundcard.h,相信你能马上从混音通道的名字得到这个序号。
newrecmask |= (1 << device);
/*change record source*/
if (ioctl(dfd, SOUND_MIXER_WRITE_RECSRC, &newrecmask) == -1)
{
return FALSE;
}
上面这段代码则是设置device为录音源,ex,mic的device为7,但在soundcard.h却排在8,所以将1左移7为就搞好在那个位置了。
在录音时要注意应用程序的Buffer不应大于内核的Buffer,同时,应是采样频率的正整数倍,以前我因为没注意到这点,基本上
录不到声音。好了,设置录音源讲到这,再来看看怎么设置音量。看如下的代码:
int value = 0;
value = left | (right << ;
if((ioctl(dfd, MIXER_WRITE(device), &value)) == -1)
{
perror("Set volumn fail!" ;
return FALSE;
}
return TRUE;
对于只有一个混音通道的单声道设备来说,返回的增益大小保存在低位字节中。而对于支持多个混音通道的双声道设备来说,返回的增益大小实际上包括两个部分,分别代表左、右两个声道的值,
其中低位字节保存左声道的音量,而高位字节则保存右声道的音量。device值同上。 |
评分
-
查看全部评分
|