使用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编程. ...
随机推荐
- 如何防止SQL注入式攻击
一.什么是SQL注入式攻击? 所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或 ...
- RTL Compiler之synthesis steps
1 synthesis steps 1) Search Paths rc:/> set_attribute lib_search_path path / rc:/> set_attribu ...
- C# 定时无操作则退出登陆,回到登陆界面。
有时候根据需求需要为程序添加在规定的时间内无操作则退出当前的登陆程序的功能,如下代码模拟描述的需求功能. using System; using System.Collections.Generic; ...
- (转) SolrCloud之分布式索引及与Zookeeper的集成
http://blog.csdn.net/ebay/article/details/46549481 作者:Wang, Josh 一.概述 Lucene是一个Java语言编写的利用倒排原理实现的文本检 ...
- Redis 之order set有序集合结构及命令详解
1.zadd key score1 value1 score2 value2 添加元素 2.zrem key value1 value2 .. 删除集合中的元素 3.zremrangebyscor ...
- Git学习总结一(下载、初始化、添加文件)
Git下载地址 安装完成后,还需要最后一步设置,在命令行输入: $ git config --global user.name "Your Name" $ git config - ...
- 在引入的css或者js文件后面加参数的作用
有时候可能会遇到js或者css文件引用后传递参数: css和js带参数(形如.css?v=与.js?v=) <script type=”text/javascript” src=”jb51.js ...
- CF51F Caterpillar (边双+树形DP)
题目传送门 题目大意:给你一张n个点m条边的图.每次操作可以把两个点合并成一个(与之相连的边也都要连到新点上).求把图中每个联通块都变成“毛毛虫”的最小操作次数.“毛毛虫”必须是一棵树(可以存在自环) ...
- 关于Spring的69个问题
Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring ...
- lambda表达式与委托与线程初步谈论-基于刘铁锰视频观后操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...