使用ALSA编写自己的音频程序【转】
本文转载自:http://blog.csdn.net/beyondioi/article/details/6994548
Alsa是Linux高级音频接口。面对众多的音频设备,Alsa为Linux音频开发人员提供了一套标准的访问机制,使得音频开发变得十分容易。不信?下面我们就利用它编写一个简单的录音/播音程序,不过这需要你有一定的计算机语言基础。
一个典型的音频程序应该具有以下结构:
打开音频设备
为设备设置读写参数
向音频设备读/写音频数据
关闭设备
Alsa库为我们实现这些操作提供了丰富的接口。
首先让我们封装一个打开音频设备的函数:
snd_pcm_t *pcm_handle;
bool device_open(int mode){
if (snd_pcm_open (&pcm_handle, “default” , mode , 0) < 0)
return false;
return true;
}
snd_pcm_open是Alsa库提供的打开设备调用函数,这里我们指定打开缺省的音频设备,并根据参数mode将设备置为录音或是播放状态,如果设备打开成功,pcm_handle便指向该设备句柄,我们用全局变量保存起来,方便以后使用。
第二步是设置参数,参数设置不当将会导致音频设备无法正常工作。在设置参数前,我们需要了解一下各个参数的含义以及一些基本概念。
样本长度(sample):样本是记录音频数据最基本的单位,常见的有8位和16位。
通道数(channel):该参数为1表示单声道,2则是立体声。
桢(frame):桢记录了一个声音单元,其长度为样本长度与通道数的乘积。
采样率(rate):每秒钟采样次数,该次数是针对桢而言。
周期(period):音频设备一次处理所需要的桢数,对于音频设备的数据访问以及音频数据的存储,都是以此为单位。
交错模式(interleaved):是一种音频数据的记录方式,在交错模式下,数据以连续桢的形式存放,即首先记录完桢1的左声道样本和右声道样本(假设为立体声格式),再开始桢2的记录。而在非交错模式下,首先记录的是一个周期内所有桢的左声道样本,再记录右声道样本,数据是以连续通道的方式存储。不过多数情况下,我们只需要使用交错模式就可以了。
明白了各参数含义及关系后,我们开始设置参数:
int bit_per_sample; //样本长度(bit)
int period_size; //周期长度(桢数)
int chunk_byte; //周期长度(字节数)
snd_pcm_hw_params_t *params; //定义参数变量
bool device_setparams(){
snd_pcm_hw_params_t *hw_params;
snd_pcm_hw_params_malloc (&hw_params); //为参数变量分配空间
snd_pcm_hw_params_malloc (¶ms);
snd_pcm_hw_params_any ( pcm_handle, hw_params ); //参数初始化
snd_pcm_hw_params_set_access ( pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); //设置为交错模式
snd_pcm_hw_params_set_format( pcm_handle, hw_params, SND_FORMAT_S16_LE); //使用用16位样本
snd_pcm_hw_params_set_rate_near( pcm_handle, hw_params, 44100, 0); //设置采样率为44.1KHz
snd_pcm_hw_params_set_channels( pcm_handle, hw_params, 2); //设置为立体声
snd_pcm_hw_params_get_period_size( hw_params, &period_size); //获取周期长度
bit_per_sample = snd_pcm_hw_format_physical_width( hw_params.format ); //获取样本长度
chunk_byte = period_size * bit_per_sample * hw_params.channels / 8; //计算周期长度(字节数(bytes) = 每周期的桢数 * 样本长度(bit) * 通道数 / 8 )
snd_pcm_hw_params( pcm_handle, hw_params); //设置参数
params = hw_params; //保存参数,方便以后使用
snd_pcm_hw_params_free( hw_params); //释放参数变量空间
return true;
}
这里先使用了Alsa提供的一系列snd_pcm_hw_params_set_函数为参数变量赋值。最后才通过snd_pcm_hw_params将参数传递给设备。需要说明的是正式的开发中需要处理参数设置失败的情况,这里仅做为示例程序而未作考虑。
设置好参数后便可以开始录音了。录音过程实际上就是从音频设备中读取数据信息并保存。
char *wave_buf;
int wave_buf_len;
bool device_capture( int dtime /*录音长度(单位:秒)*/){
wave_buf_len = dtime * params.rate * bit_per_sample * params.channels / 8 ; //计算音频数据长度(秒数 * 采样率 * 桢长度)
char *data = wave_buf = (char*)malloc( wave_buf_len ); //分配空间
int r = 0;
while ( data ?C wave_buf <= wave_buf_len ?C chunk_size ){
r = snd_pcm_readi( pcm_handle, data , chunk_size);
if ( r>0 ) data += r * chunk_byte;
else
return false
}
return true;
}
形参dtime用来确定录音时间,根据录音时间分配数据空间,再调用snd_pcm_readi从音频设备读取音频数据,存放到wave_buf中。
同样的原理,我们再添加一个播放函数,向音频设备写入数据:
bool device_play(){
char *data = wave_buf;
int r = 0;
while ( data ?C wave_buf <= wave_buf_len ?C chunk_size ){
r = snd_pcm_writei( pcm_handle, data , chunk_size);
if ( r>0 ) data += r * chunk_byte;
else
return false
}
return true;
}
最后我们给这个示例程序加上main函数
#include
bool device_open( int mode);
bool device_setparams();
bool device_capture( int dtime );
bool device_play();
char *wave_buf;
int wave_buf_len;
int bit_per_sample;
int period_size;
int chunk_byte;
int chunk_size;
snd_pcm_hw_params_t *params;
int main( int , char** ){
//录音
if (!device_open(SND_PCM_STREAM_CAPTURE ) return 1;
if (!device_setparams()) return 2;
if (!device_capture( 3 )) return 3; //录制3秒
snd_pcm_close( pcm_handle );
//播放
if (!device_open( SND_PCM_STREAM_PLAYBACK ) return 4;
if (!device_setparams()) return 5;
if (!device_play()) return 6;
snd_pcm_close( pcm_handle );
return 0;
}
这样,我们便完成了一个具有录音,播音的功能的音频程序,因为使用了alsa库,如果你使用的是gcc编译器,最后链接时记得要带上参数——lasound 。
限于篇幅,Alsa接口提供的强大功能不仅于此,有兴趣的读者可以参阅ALSA HOWTO,那上面你一定能够发现Alsa的强大之处。
使用ALSA编写自己的音频程序【转】的更多相关文章
- 搭建java开发环境、使用eclipse编写第一个java程序
搭建java开发环境.使用eclipse编写第一个java程序 一.Java 开发环境的搭建 1.首先安装java SDK(简称JDK). 点击可执行文件 jdk-6u24-windows-i586. ...
- Java基础-接口中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产。请编写一个java应用程序描述上述的体制现象。 要求如下: (1)该应用程序中有一个“党中央”接口:CentralPartyCommittee,该接口中 有个“坚持党的领导”方法:void partyLeader() (2)该应用程序中有一个“国务院”抽象类:StateCouncil,
36.中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产.请编写一个java应用程序描述上述的体制现象. 要求如下: (1)该应用程序中有一个“党中央”接口 ...
- Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。
#29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类T ...
- java基础,继承类题目:编写一个Java应用程序,该程序包括3个类:Monkey类、People类和主类 E
21.编写一个Java应用程序,该程序包括3个类:Monkey类.People类和主类 E.要求: (1) Monkey类中有个构造方法:Monkey (String s),并且有个public vo ...
- 编写高性能Web应用程序的10个技巧
这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...
- Xamarin iOS编写第一个应用程序创建工程
Xamarin iOS编写第一个应用程序创建工程 在Xcode以及Xamarin安装好后,就可以在Xamarin Studio中编写程序了.本节将主要讲解在Xamarin Studio中如何进行工程的 ...
- 编写简单的Mapreduce程序并部署在Hadoop2.2.0上运行
今天主要来说说怎么在Hadoop2.2.0分布式上面运行写好的 Mapreduce 程序. 可以在eclipse写好程序,export或用fatjar打包成jar文件. 先给出这个程序所依赖的Mave ...
- 【ZZ】C 语言中的指针和内存泄漏 & 编写高效的C程序与C代码优化
C 语言中的指针和内存泄漏 http://www.ibm.com/developerworks/cn/aix/library/au-toughgame/ 本文讨论了几种在使用动态内存分配时可以避免的陷 ...
- 使用Playground编写第一个Swift程序
从控制台输出“HelloWorld”是我学习C语言的第一步,也是我人生中非常重要的一步.多年后的今天,我仍希望以HelloWorld作为第一步,与大家共同开启一个神奇.瑰丽的世界——Swift编程. ...
随机推荐
- Android基础TOP4:Tost的使用
Activity: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xm ...
- [ Java ] [ UT ] [ Mock ] [ JUnit ] 單元測試的撰寫
最近新的專案用到很多的單元測試,對於單元測試有多了一歇的了解. 先寫下大綱,後面分篇寫出總結心得. 1. 單元測試要隔離對外部的關聯 2. Mock, spy 的用法時機差異 3. JUnit 4, ...
- 转载:使用FileReader对象的readAsDataURL方法来读取图像文件
文章转载自:http://blog.okbase.net/jquery2000/archive/1296.html: FileReader对象的readAsDataURL方法可以将读取到的文件编码成D ...
- 【译】x86程序员手册05 - 2.3寄存器
2.3 Registers 寄存器 The 80386 contains a total of sixteen registers that are of interest to the applic ...
- java web项目和java项目的区别(看清IDE本质)
想必大家在使用MyEclipse时对这两个概念不去深究.只知道是Java EE类的基本都是Web项目,而Java应用程序就是Java项目.而且很多人都愿意使用MyEclipse作为开发工具,且不说大家 ...
- (转)Hibernate的一级缓存
http://blog.csdn.net/yerenyuan_pku/article/details/70148567 Hibernate的一级缓存 Hibernate的一级缓存就是指Session缓 ...
- iOS UIWebView 访问https绕过证书验证的方法
@implementation NSURLRequest (NSURLRequestWithIgnoreSSL) + (BOOL)allowsAnyHTTPSCertificateForHost:(N ...
- 一台电脑同时使用多个Git账号
参照 https://my.oschina.net/u/3578363/blog/2209781
- UpdateData
UpdateData 类似于C语言的scanf printf函数 管理控件与关联变量之间的数据更新. updatedata(true)把界面输入的数值更新到关联变量中,updatedata(false ...
- SQL With As 用法Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介
Sql 四大排名函数(ROW_NUMBER.RANK.DENSE_RANK.NTILE)简介 排名函数是Sql Server2005新增的功能,下面简单介绍一下他们各自的用法和区别.我们新建一张O ...