一 . 介紹
ALSA 標準是一個先進的 linux 聲音體系。它包含核心驅動集合, API 庫和工具對 Linux 聲音進行支援。 ALSA 包含一系列核心驅動對不同的音效卡進行支援,還提供了 libasound 的 API 庫。用這些進行寫程式不需要開啟裝置等操作,所以編程人員在寫程式的時候不會被底層的東西困擾。與此相反 OSS/Free 驅動在核心層次調用,需要指定裝置名稱和調用 ioctl 。為提供向後相容, ALSA 提供核心模組模仿 OSS/Free 驅動,所以大多數的程式不需要改動。 ALSA 擁有調用外掛程式的能力對新裝置提供擴充,包括那些用軟體類比出來的虛擬設備。 ALSA 還提供一組命令列工具包括 mixer, sound file player 和工具控制一些特別的音效卡的特別的作用。
二 .ALSA 體系:
ALSA API 被主要分為以下幾種介面:
l 控制介面:提供靈活的方式管理註冊的音效卡和對存在的音效卡進行查詢。
l PCM 介面:提供管理數字音訊捕捉和回放。
l 原始 MIDI 介面 : 支援 MIDI (Musical Instrument Digital Interface), 一種標準電子音樂指令集。 這些 API 提供訪問音效卡上的 MIDI 匯流排。這些原始借口直接工作在 The MIDI 事件上,程式員只需要管理協議和時間。
l 記時介面 : 為支援聲音的同步事件提供訪問音效卡上的定時器。
l 音序器介面:一個比原始 MIDI 介面進階的 MIDI 編程和聲音同步高層介面。它可以處理很多的 MIDI 協議和定時器。
l 混音器介面:控制發送訊號和控制聲音大小的音效卡上的裝置。
三 . 音效卡的緩衝和資料的傳輸:
一塊音效卡有一個音效卡記憶體用來儲存記錄的樣本。當它被寫滿時就產生中斷。核心驅動就使用 DMA 將資料轉送到記憶體中。同樣地,當在播放時就將記憶體中的聲音樣本使用 DMA 傳到音效卡的記憶體中。
音效卡的緩衝是環狀的,這裡只討論應用程式中的記憶體結構: ALSA 將資料分成連續的片段然後傳到按單元片段傳輸。
四:典型的聲音程式結構:
open interface for capture or playback
set hardware parameters
(access mode, data format, channels, rate, etc.)
while there is data to be processed:
read PCM data (capture)
or write PCM data (playback)
close interface
五 . 一些例子: 1. 顯示一些 PCM 的類型和格式 :
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
std::cout << "ALSA library version: " << SND_LIB_VERSION_STR << std::endl;
std::cout << "PCM stream types: " << std::endl;
for (int val=0; val <= SND_PCM_STREAM_LAST; ++val)
std::cout << snd_pcm_stream_name((snd_pcm_stream_t)val) << std::endl;
std::cout << std::endl;
std::cout << "PCM access types: " << std::endl;
for (int val=0; val <= SND_PCM_ACCESS_LAST; ++val)
std::cout << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;
std::cout << std::endl;
std::cout << "PCM subformats: " << std::endl;
for (int val=0; val <= SND_PCM_SUBFORMAT_LAST; ++val)
std::cout << snd_pcm_subformat_name((snd_pcm_subformat_t)val) << " (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;
std::cout << std::endl;
std::cout << "PCM states: " << std::endl;
for (int val=0; val <= SND_PCM_STATE_LAST; ++val)
std::cout << snd_pcm_state_name((snd_pcm_state_t)val) << std::endl;
std::cout << std::endl;
std::cout << "PCM formats: " << std::endl;
for (int val=0; val <= SND_PCM_FORMAT_LAST; ++val)
std::cout << snd_pcm_format_name((snd_pcm_format_t)val) << " (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;
std::cout << std::endl;
}
2. 開啟 PCM 裝置和設定參數
#include <iostream>
#include <alsa/asoundlib.h>
int main()
{
int rc;
snd_pcm_t* handle;
snd_pcm_hw_params_t* params;
unsigned int val, val2;
int dir;
snd_pcm_uframes_t frames;
if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
std::cerr << "unable to open pcm devices: " << snd_strerror(rc) << std::endl;
exit(1);
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
if ( (rc = snd_pcm_hw_params(handle, params)) < 0)
{
std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;
exit(1);
}
std::cout << "PCM handle name = " << snd_pcm_name(handle) << std::endl;
std::cout << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)) << std::endl;
snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *)&val);
std::cout << "access type = " << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;
snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)(&val));
std::cout << "format = '" << snd_pcm_format_name((snd_pcm_format_t)val) << "' (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;
snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val);
std::cout << "subformat = '" <<
snd_pcm_subformat_name((snd_pcm_subformat_t)val) << "' (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;
snd_pcm_hw_params_get_channels(params, &val);
std::cout << "channels = " << val << std::endl;
snd_pcm_hw_params_get_rate(params, &val, &dir);
std::cout << "rate = " << val << " bps" << std::endl;
snd_pcm_hw_params_get_period_time(params, &val, &dir);
std::cout << "period time = " << val << " us" << std::endl;
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
std::cout << "period size = " << static_cast<int>(frames) << " frames" << std::endl;
snd_pcm_hw_params_get_buffer_time(params, &val, &dir);
std::cout << "buffer time = " << val << " us" << std::endl;
snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val);
std::cout << "buffer size = " << val << " frames" << std::endl;
snd_pcm_hw_params_get_periods(params, &val, &dir);
std::cout << "periods per buffer = " << val << " frames" << std::endl;
snd_pcm_hw_params_get_rate_numden(params, &val, &val2);
std::cout << "exact rate = " << val/val2 << " bps" << std::endl;
val = snd_pcm_hw_params_get_sbits(params);
std::cout << "significant bits = " << val << std::endl;
snd_pcm_hw_params_get_tick_time(params, &val, &dir);
std::cout << "tick time = " << val << " us" << std::endl;
val = snd_pcm_hw_params_is_batch(params);