ALSA(Advanced Linux Sound Architecture)是由内核驱动,标准的API库和一系列实用程序组成.因为涉及到版权和BUG的问题Linux 2.6内核抛弃了旧的OSS,ALSA作为声音编程的生力军被作为了合并到了内核中.

数字音频基础:

音频是由电器设备(麦克风等)将空气的变化转化成的电信号.模数转换器(A/D)将模拟电压转化成一系列不连续的值称之为采样,然后将采样值送往数模转化器(D/A)从而将声音还原.采样的频率是影响数字声音质量的一个关键因素,由Nyquist采样定理知,采样的频率至少是信号中最高频率的2倍方能的还原原始信号.

ALSA基础知识:

ALSA由许多声卡的声卡驱动程序组成,同时它也提供一个称为libasound的API库。应用程序开发者应该使用libasound而不是内核中的ALSA接口。因为libasound提供最高级并且编程方便的编程接口。并且提供一个设备逻辑命名功能,这样开发者甚至不需要知道类似设备文件这样的低层接口。相反,OSS/Free驱动是在内核系统调用级上编程,它要求开发者提供设备文件名并且利用ioctrl来实现相应的功能。为了向后兼容,ALSA提供内核模块来模拟OSS,这样之前的许多在OSS基础上开发的应用程序不需要任何改动就可以在ALSA上运行。另外,libaoss库也可以模拟OSS,而它不需要内核模块。ALSA包含插件功能,使用插件可以扩展新的声卡驱动,包括完全用软件实现的虚拟声卡。ALSA提供一系列基于命令行的工具集,比如混音器(mixer),音频文件播放器(aplay),以及控制特定声卡特定属性的工具.

ALSA接口:

控制接口:用来管理已注册的声卡并检查其可用的设备

PCM接口:用来管理数字音频的录音和回放,这是一个用的最广泛的接口,我们将在下文中着重介绍.

原始 MIDI 接口:支持标准MIDI(Musical Instrument Digital Interface),提供了访问声卡MIDI的接口.

时间接口:用来声卡的计时声音事件的同步

Sequencer接口:高级MIDI和声音合成接口,可以处理更多的MIDI协议

混音接口:用来声卡设备的信号处理和音量,建立在控制接口之上

设备命名:

API库使用逻辑设备名而不是设备文件。设备名字可以是真实的硬件名字也可以是插件名字。硬件名字使用hw:i,j这样的格式。其中i是卡号,j是这块声卡上的设备号。第一个声音设备是hw:0,0.这个别名默认引用第一块声音设备并且在本文示例中一直会被用到。插件使用另外的唯一名字。比如plughw:,表示一个插件,这个插件不提供对硬件设备的访问,而是提供像采样率转换这样的软件特性,硬件本身并不支持这样的特性。

声音缓存和数据传输:

每个声卡都有一个硬件缓存区来保存记录下来的样本。当缓存区足够满时,声卡将产生一个中断。内核声卡驱动然后使用直接内存(DMA)访问通道将样本传送到内存中的应用程序缓存区。类似地,对于回放,任何应用程序使用DMA将自己的缓存区数据传送到声卡的硬件缓存区中。

这样硬件缓存区是环缓存。也就是说当数据到达缓存区末尾时将重新回到缓存区的起始位置。ALSA维护一个指针来指向硬件缓存以及应用程序缓存区中数据操作的当前位置。从内核外部看,我们只对应用程序的缓存区感兴趣,所以本文只讨论应用程序缓存区。

应用程序缓存区的大小可以通过ALSA库函数调用来控制。缓存区可以很大,一次传输操作可能会导致不可接受的延迟,我们把它称为延时(latency)。为了解决这个问题,ALSA将缓存区拆分成一系列周期(period)(OSS/Free中叫片断fragments).ALSA以period为单元来传送数据。

一个周期(period)存储一些帧(frames)。每一帧包含时间上一个点所抓取的样本。对于立体声设备,一个帧会包含两个信道上的样本。图1展示了分解过程:一个缓存区分解成周期,然后是帧,然后是样本。图中包含一些假定的数值。图中左右信道信息被交替地存储在一个帧内。这称为交错(interleaved)模式。在非交错模式中,一个信道的所有样本数据存储在另外一个信道的数据之后。

设置参数,参数设置不当将会导致音频设备无法正常工作。在设置参数前,我们需要了解一下各个参数的含义以及一些基本概念。

样本长度(sample):样本是记录音频数据最基本的单位,常见的有8位和16位。

通道数(channel):该参数为1表示单声道,2则是立体声。

桢(frame):桢记录了一个声音单元,其长度为样本长度与通道数的乘积。

采样率(rate):每秒钟采样次数,该次数是针对桢而言。

周期(period):音频设备一次处理所需要的桢数,对于音频设备的数据访问以及音频数据的存储,都是以此为单位。

一个典型的应用程序:

一个典型的声音程序使用PCM的程序通常类似下面的伪代码:

打开回放或录音接口

设置硬件参数(访问模式,数据格式,信道数,采样率,等等)

while(有数据要被处理)

{

读PCM数据(录音)或 写PCM数据(回放)

}

关闭接口

下面我们介绍声音回放和,录音的例子程序作为对以上内容的总结

/*

alsa_pcm_playback.c

从标准的声音输入设备中声音并写到默认的PCM设备中

*/

#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main()

{

long loops;

int rc;

int size;

snd_pcm_t *handle;

snd_pcm_hw_params_t *params;

unsigned int val;

int dir;

snd_pcm_uframes_t frames;

char *buffer;

/* 打开PCM设备用来回放 */

rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_PLAYBACK, 0);

if (rc < 0)

{

fprintf(stderr,

"unable to open pcm device: %s\n",

snd_strerror(rc));

exit(1);

}

/* Allocate a hardware parameters object. */

snd_pcm_hw_params_alloca(&params);

/* Fill it in with default values. */

snd_pcm_hw_params_any(handle, params);

/* Set the desired hardware parameters. */

/* Interleaved mode */

snd_pcm_hw_params_set_access(handle, params,

SND_PCM_ACCESS_RW_INTERLEAVED);

/* Signed 16-bit little-endian format */

snd_pcm_hw_params_set_format(handle, params,

SND_PCM_FORMAT_S16_LE);

/* Two channels (stereo) */

snd_pcm_hw_params_set_channels(handle, params, 2);

/* 44100 bits/second sampling rate (CD quality) */

val = 44100;

snd_pcm_hw_params_set_rate_near(handle, params,

&val, &dir);

/* Set period size to 32 frames. */

frames = 32;

snd_pcm_hw_params_set_period_size_near(handle,

params, &frames, &dir);

/* Write the parameters to the driver */

rc = snd_pcm_hw_params(handle, params);

if (rc < 0) {

fprintf(stderr,

"unable to set hw parameters: %s\n",

snd_strerror(rc));

exit(1);

}

/* Use a buffer large enough to hold one period */

snd_pcm_hw_params_get_period_size(params, &frames,

&dir);

size = frames * 4; /* 2 bytes/sample, 2 channels */

buffer = (char *) malloc(size);

/* We want to loop for 5 seconds */

snd_pcm_hw_params_get_period_time(params,

&val, &dir);

/* 5 seconds in microseconds divided by

* period time */

loops = 5000000 / val;

while (loops > 0) {

loops--;

rc = read(0, buffer, size);

if (rc == 0) {

fprintf(stderr, "end of file on input\n");

break;

} else if (rc != size) {

fprintf(stderr,

"short read: read %d bytes\n", rc);

}

rc = snd_pcm_writei(handle, buffer, frames);

if (rc == -EPIPE) {

/* EPIPE means underrun */

fprintf(stderr, "underrun occurred\n");

snd_pcm_prepare(handle);

} else if (rc < 0) {

fprintf(stderr,

"error from writei: %s\n",

snd_strerror(rc));

}  else if (rc != (int)frames) {

fprintf(stderr,

"short write, write %d frames\n", rc);

}

}

snd_pcm_drain(handle);

snd_pcm_close(handle);

free(buffer);

return 0;

}

/*

Example 4 - Simple sound recording

alsa_pcm_record.c

读PCM设备到标准的输出中

This example reads from the default PCM device

and writes to standard output for 5 seconds of data.

*/

/* Use the newer ALSA API */

#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main() {

long loops;

int rc;

int size;

snd_pcm_t *handle;

snd_pcm_hw_params_t *params;

unsigned int val;

int dir;

snd_pcm_uframes_t frames;

char *buffer;

/* Open PCM device for recording (capture). */

rc = snd_pcm_open(&handle, "default",

SND_PCM_STREAM_CAPTURE, 0);

if (rc < 0) {

fprintf(stderr,

"unable to open pcm device: %s\n",

snd_strerror(rc));

exit(1);

}

/* Allocate a hardware parameters object. */

snd_pcm_hw_params_alloca(&params);

/* Fill it in with default values. */

snd_pcm_hw_params_any(handle, params);

/* Set the desired hardware parameters. */

/* Interleaved mode */

snd_pcm_hw_params_set_access(handle, params,

SND_PCM_ACCESS_RW_INTERLEAVED);

/* Signed 16-bit little-endian format */

snd_pcm_hw_params_set_format(handle, params,

SND_PCM_FORMAT_S16_LE);

/* Two channels (stereo) */

snd_pcm_hw_params_set_channels(handle, params, 2);

/* 44100 bits/second sampling rate (CD quality) */

val = 44100;

snd_pcm_hw_params_set_rate_near(handle, params,

&val, &dir);

/* Set period size to 32 frames. */

frames = 32;

snd_pcm_hw_params_set_period_size_near(handle,

params, &frames, &dir);

/* Write the parameters to the driver */

rc = snd_pcm_hw_params(handle, params);

if (rc < 0) {

fprintf(stderr,

"unable to set hw parameters: %s\n",

snd_strerror(rc));

exit(1);

}

/* Use a buffer large enough to hold one period */

snd_pcm_hw_params_get_period_size(params,

&frames, &dir);

size = frames * 4; /* 2 bytes/sample, 2 channels */

buffer = (char *) malloc(size);

/* We want to loop for 5 seconds */

snd_pcm_hw_params_get_period_time(params,

&val, &dir);

loops = 5000000 / val;

while (loops > 0) {

loops--;

rc = snd_pcm_readi(handle, buffer, frames);

if (rc == -EPIPE) {

/* EPIPE means overrun */

fprintf(stderr, "overrun occurred\n");

snd_pcm_prepare(handle);

} else if (rc < 0) {

fprintf(stderr,

"error from read: %s\n",

snd_strerror(rc));

} else if (rc != (int)frames) {

fprintf(stderr, "short read, read %d frames\n", rc);

}

rc = write(1, buffer, size);

if (rc != size)

fprintf(stderr,

"short write: wrote %d bytes\n", rc);

}

snd_pcm_drain(handle);

snd_pcm_close(handle);

free(buffer);

return 0;

}

./listing4 > sound.raw

./listing3 < sound.raw

http://blog.csdn.net/spygg/article/details/7824750

alsa 编程的更多相关文章

  1. 【转】Alsa音频编程【精华】

    一.前序 这里了解一下各个参数的含义以及一些基本概念. 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语. 样本长度(sample):样本是记录音频数据最基本的单位,计算机对每 ...

  2. ubuntu alsa

    今天要在linux下搞音频编程,在网上查阅了一下资料,网上很多资料都是在linux下直接对/dev/dsp进行编程的,因为在以往的linux系统中,我们是可以通过cat  xxx.wav /dev/d ...

  3. Linux音频编程

    1. 背景 在<Jasper语音助理介绍>中, 介绍了Linux音频系统, 本文主要介绍了Linux下音频编程相关内容. 音频编程主要包括播放(Playback)和录制(Record), ...

  4. ALSA安装编程指南

     ALSA全指南 一.什么是ALSA ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(Mu ...

  5. Linux音频编程(一)ALSA介绍

    Linux下的音频编程中有OSS和ALSA,本篇文章将对ALSA进行相关介绍.ALSA提供一系列基于命令行的工具集,比如混音器(mixer),音频文件播放器(aplay),以及控制特定声卡特定属性的工 ...

  6. Linux ALSA音频PCM播放编程

    使用ALSA播放两个频率的单音,并使用GNU Radio中的Audio Source和FFT来观测声音的频谱. #include <alsa/asoundlib.h> #include & ...

  7. ALSA声音编程

    1. ALSA设备驱动将ALSA设备描述分为四层,从上到下为: default default:0 plughw:0,0 hw:0,0 不同的层次,对设备的控制权限不同,比如hardware para ...

  8. alsa 用户空间编程【转】

    本文转载自:http://blog.csdn.net/sjin_1314/article/details/12872581 /**alsa play test *ALSA用户空间编译,ALSA驱动的声 ...

  9. Linux音频编程--使用ALSA库播放wav文件

    在UBUNTU系统上使用alsa库完成了对外播放的wav文件的案例. 案例代码: /** *test.c * *注意:这个例子在Ubuntu 12.04.1环境下编译运行成功. * */ #inclu ...

随机推荐

  1. 泛域名Wildcard Domain

    泛域名Wildcard Domain 泛域名Wildcard Domain是一种特殊的域名形式.它使用星号作为域名的一级.例如,*.baidu.com就是使用星号作为域名的二级部分.在域名解析中,一个 ...

  2. android 什么时候call super.onDestory()等

    Methods you override that are part of component creation (onCreate(), onStart(), onResume(), etc.), ...

  3. luogu P2066 机器分配

    题目背景 无 题目描述 总公司拥有高效设备M台,准备分给下属的N个分公司.各分公司若获得这些设备,可以为国家提供一定的盈利.问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值.其中M≤15 ...

  4. Android获取状态栏和标题栏的高度

    版权声明:本文为博主原创文章,未经博主允许不得转载. 1.获取状态栏高度: decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个 ...

  5. Opencv 最小外接矩形合并拼接

    前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的 如图1是一个信号的雨图,被矩形框分割成了多个小框: 需要合并矩形框达到的效果: 主要思想: 扫描两 ...

  6. mysql序列号发生器

    mysql序列号发生器 学习了:http://www.jquerycn.cn/a_14577 还可以这样啊:

  7. d3js 添加数据

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  8. xcode 5.0 以上去掉icon高亮方法&amp;iOS5白图标问题

    之前的建议方法是把在xxx.info.plist文件里把 icon already includes gloss and bevel effects 设置YES 在Xcode5下,重复实现不成功,今天 ...

  9. webpack实用配置总结

    1.webpack.config.js配置文件为: //处理共用.通用的js var webpack = require('webpack'); //处理html模板 var htmlWebpackP ...

  10. 错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file

    问题:错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file 解答:加入include路径:E:\env\Anaconda2x6 ...