本文转载自: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编写自己的音频程序【转】的更多相关文章

  1. 搭建java开发环境、使用eclipse编写第一个java程序

    搭建java开发环境.使用eclipse编写第一个java程序 一.Java 开发环境的搭建 1.首先安装java SDK(简称JDK). 点击可执行文件 jdk-6u24-windows-i586. ...

  2. Java基础-接口中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产。请编写一个java应用程序描述上述的体制现象。 要求如下: (1)该应用程序中有一个“党中央”接口:CentralPartyCommittee,该接口中 有个“坚持党的领导”方法:void partyLeader() (2)该应用程序中有一个“国务院”抽象类:StateCouncil,

    36.中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产.请编写一个java应用程序描述上述的体制现象. 要求如下: (1)该应用程序中有一个“党中央”接口 ...

  3. Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。

    #29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类T ...

  4. java基础,继承类题目:编写一个Java应用程序,该程序包括3个类:Monkey类、People类和主类 E

    21.编写一个Java应用程序,该程序包括3个类:Monkey类.People类和主类 E.要求: (1) Monkey类中有个构造方法:Monkey (String s),并且有个public vo ...

  5. 编写高性能Web应用程序的10个技巧

    这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...

  6. Xamarin iOS编写第一个应用程序创建工程

    Xamarin iOS编写第一个应用程序创建工程 在Xcode以及Xamarin安装好后,就可以在Xamarin Studio中编写程序了.本节将主要讲解在Xamarin Studio中如何进行工程的 ...

  7. 编写简单的Mapreduce程序并部署在Hadoop2.2.0上运行

    今天主要来说说怎么在Hadoop2.2.0分布式上面运行写好的 Mapreduce 程序. 可以在eclipse写好程序,export或用fatjar打包成jar文件. 先给出这个程序所依赖的Mave ...

  8. 【ZZ】C 语言中的指针和内存泄漏 & 编写高效的C程序与C代码优化

    C 语言中的指针和内存泄漏 http://www.ibm.com/developerworks/cn/aix/library/au-toughgame/ 本文讨论了几种在使用动态内存分配时可以避免的陷 ...

  9. 使用Playground编写第一个Swift程序

    从控制台输出“HelloWorld”是我学习C语言的第一步,也是我人生中非常重要的一步.多年后的今天,我仍希望以HelloWorld作为第一步,与大家共同开启一个神奇.瑰丽的世界——Swift编程. ...

随机推荐

  1. ansj --词性说明

    背景 Ansj 是一个开源的 Java 中文分词工具,基于中科院的 ICTCLAS 中文分词算法,比其他常用的开源分词工具(如mmseg4j)的分词准确率更高.工具支持词性标注,所以就可以依据词性进行 ...

  2. Javascript实现导航锚点滚动效果实例

    本篇文章主要介绍了Javascript实现页面滚动时导航智能定位,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 常见的开发页面中可能会有这么一个需求,页面中会有多个模块,每个模块对应一个导航,当页 ...

  3. html5——DOM扩展

    元素获取 1.document.getElementsByClassName ('class') 通过类名获取元素,以类数组形式存在. 2.document.querySelector(‘div’) ...

  4. 配置tfs2017的agent

    tfs支持四种验证方式,分别是:PAT.Negotiate.Integrated.Alternate 我们使用Negotiate方式 首先,登录tfs服务器,设置iis的身份验证  添加一个Negot ...

  5. inline-block兼容IE7

    { display:inline-block; *display:inblock; *zoom:1 }

  6. 浅谈jQuery宽高及其应用

    [前言] 今天讲了讲jQuery各种元素宽高的获取和设置,下面简单总结下,希望对各位小伙伴有所帮助 [主体] 补充知识点: (1)width()返回结果无单位,css("width" ...

  7. js 随机数范围

    Math.floor(Math.random()*(high-low+1) +low)

  8. 图的连通性问题之连通和最小环——Floyd算法

    Floyd 判断连通性 d[i][j]仅表示i,j之间是否联通 ;k<=n;k++) ;i<=n;i++) ;j<=n;j++) dis[i][j]=dis[i][j]||(dis[ ...

  9. SDOI2018退役记

    在NOIp2017中,我意识到自己啥也不会.如今SDOI2018快来了,自己还是啥也不会.高一两次考试注定以打两次酱油告终.还是记录一下,到NOIp之后如果还没有退役的话,那这个博客可能还会继续更新吧 ...

  10. python爬虫12 | 爸爸,他使坏,用动态的 Json 数据,我要怎么搞?

    在前面我们玩了好多静态的 HTML 想必你应该知道怎么去爬这些数据了 但还有一些常见的动态数据 比如 商品的评论数据 实时的直播弹幕 岛国动作片的评分 等等 这些数据是会经常发生改变的 很多网站就会用 ...