Linux錄音詳解

來源:互聯網
上載者:User

from : http://blog.163.com/tongfangyuan0000@126/blog/static/43041855200921272753720/

1)查看音效卡:

tong@tfylaptop:~/Documents/機器人舞蹈/程式/MIT/linux/tapping3(NEW)$ arecord -l

**** List of CAPTURE Hardware Devices ****
card 0: Intel [HDA Intel], device 0: STAC92xx Analog [STAC92xx Analog]
Subdevices: 3/3
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2

或者:

查看音效卡驅動驅動安裝狀況:

tong@tfylaptop:~/Documents/機器人舞蹈/程式/MIT/linux/tapping3(NEW)$ cat /dev/sndstat
Sound Driver:3.8.1a-980706 (ALSA v1.0.16 emulation code)
Kernel: Linux tfylaptop 2.6.24-16-generic #1 SMP Thu Apr 10 13:23:42 UTC 2008 i686
Config options: 0

Installed drivers:
Type 10: ALSA emulation

Card config:
HDA Intel at 0xfe9fc000 irq 20

Audio devices:
0: STAC92xx Analog (DUPLEX)

Synth devices: NOT ENABLED IN CONFIG

Midi devices: NOT ENABLED IN CONFIG

Timers:
7: system timer

Mixers:
0: SigmaTel STAC9228

oss預設安轉目錄是 /usr/lib/oss

2)錄音(時間長度為10s,儲存錄音檔案為0.wav,plughw:0表示第一塊音效卡)

tong@tfylaptop:~/Documents/機器人舞蹈/程式/MIT/linux/tapping3(NEW)$ arecord -d 10 -D plughw:0 0.wav
Recording WAVE '0.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono

3)

Linux下錄音:

Linux的音頻輸入輸出是通過/dev/dsp裝置的,但對於這些聲音訊號的處理則是通過/dev/mixer裝置來完成的

對Mixer檔案操作所用的一些變數

可通過看linux/soundcard.h檔案來擷取這些變數,這裡列一些基本的常用的變數
SOUND_MIXER_WRITE_VOLUME = 0xc0044d00
SOUND_MIXER_WRITE_BASS = 0xc0044d01
SOUND_MIXER_WRITE_PCM = 0xc0044d04
SOUND_MIXER_WRITE_LINE = 0xc0044d06
SOUND_MIXER_WRITE_MIC = 0xc0044d07
SOUND_MIXER_WRITE_RECSRC = 0xc0044dff
SOUND_MIXER_LINE = 7
SOUND_MASK_LINE = 64
這些變數名都是在soundcard.h中 可以查到的,通過名稱即可看出其用途,後面的賦值在該標頭檔中則並不是這樣定義的,而是通過調用一些函數返回出來的,應該是音效卡上對應的地址。在應用程式 中可通過ioctl(fd,cmd,arg)來對這些變數進行賦值。其中fd即為一個開啟/dev/mixer的檔案指標,cmd為上面所列的這些變 量,arg既是對這些變數進行操作所需賦給的結構體或變數。

參考網站: http://www.cndw.com/tech/server/2006040534091.asp

6.3 yc2440 錄放音的軟硬體設定

以下涉及到的開發運行環境均為(Yc2440板上的utu-linux作業系統)選擇的語言為C。選用的交叉編譯器為armv4l-unknown-linux-gcc。
6.3.1 錄音硬體(uda1341音效卡)

Uda1341是市面上應用比較廣的音效卡晶片支援PCM硬體編碼以及放音和錄音功能。UDA1341支援IIS匯流排資料格式,採用位元流轉換技術進行訊號處理,具有可程式化增益放大器(PGA)和數字自動增益控制器(AGC)。 UDA1341對外提供兩組音頻訊號輸入介面,每組包括左右2個聲道。由於IIS匯流排只處理音頻資料,因此UDA1341還內建用於傳輸控制訊號的L3匯流排介面。L3介面相當於混音器控制介面,可以控制輸入/輸出音頻訊號的低音及音量大小等。而且這些功能可以通過程式調用utu-linux提供的上層介面函數很好的實現,更方便的支援特定需求的錄放。
6.3.2 軟體平台(utu-linux)

Utulinux作業系統是yc2440開發版提供的嵌入式linux系列操作,其核心為2.6.13版本。這樣對於編程和開發來說就可以直接基於linux作業系統,而無需發太多的時間去考慮底層硬體的工作機制,很大程度上提高了工作效率。用linux系列的作業系統的一個優點就是在pc版linux上編譯通過的程式,基本上在板載linux上也能測試通過。另外就是基於linux系統的大部分技術均為開源項目,可以很好的學習別人的成果。所以我們目前選擇了utulinux而非wince。
6.3.3 音效卡驅動

Linux上的音效卡驅動分兩種,一種為OSS系列,另外一種為ALSA系列。
ALSA (Advanced Linux Sound Architecture(進階Linux聲音體系)的縮寫) 是為音效卡提供驅動的Linux核心組件。 一部分的目的是支援音效卡的自動設定,以及完美的處理系統中的多個聲音裝置,這些目的大多都已達到。另一個聲音架構JACK使用 ALSA 提供低延遲的專業級音頻編輯和混音能力。ALSA是一個完全開放原始碼的音頻驅動程式集,而且完全相容OSS。
OSS(Open Sound System)是 linux 平台上一個統一的音頻介面, 即只要音頻處理應用程式按照OSS的API來編寫,那麼在移植到另外一個平台時,只需要重新編譯即可。值得注意的是OSS只是部分開源。
無論是選擇ALSA還是OSS都是為了一個目的:將音效卡抽象為一個統一的裝置供linux程式員使用。我們前期測試選用的OSS系列。
6.3.3.2 安裝音效卡驅動

驅動來源程式使用的是廠商附帶的uda1341.c檔案。
a、將該檔案放置到sound/oss/目錄下。 將bitfield.h放到include/asm-arm/plat-yc24xx/目錄
b、在該目錄下的Makfile檔案的適當部位(和別的obj一起的地方)添加:
Obj-$(CONFIG_yC2440_UDA1341)+= yc2440_uda1341.o
以便能選擇編譯該檔案。
c、在該目錄下的kconfig檔案的頭部添加:
config yC2410_SND_UDA1341
tristate "yC2440 UDA1341 driver (yC2440)"
depends on SOUND_PRIME && SOUND && ARCH_yC2440
help
The UDA1341 can be found in Samsung's yC24XX
platforms. If you have a board based on one
of these. Say Y or Nhere.
If unsure, say N.
以便能在menuconfig的時候能選擇到這個音效卡。
d、在arch/arm/mach-yc2440/mach-smdk2440.c檔案中添加iss的platform_device( 預設已經有了 )
static struct platform_device *smdk2440_devices[] __initdata = {
....
....
&s3c_device_iis,
....
....
};
e、make menuconfig 選擇driver->sound->oss->uda1341 ,選擇對音效卡的支援。編譯完畢,下載到yc2440開發板,使用madplay播放mp3檔案。
6.3.3.3 測試音效卡驅動是否安裝成功

在linux上測試音效卡是否正常非常方便,用兩個簡單的命令即可實現:
cat /dev/dsp >test.wav 將聲音錄為PCM資料
cat test.wav >/dev/dsp 將PCM資料播放
6.4 yc2440開發板下錄音的實現機制

錄音實現的大體流程:
A 測試音效卡是否正常工作
B 通過mixer調節音效卡輸入和輸出時的音量大小及各種效果(比較重要)
C 開啟音效卡裝置 預設目錄為/dev/dsp
D 開啟音效檔
E 將wav頭資訊讀入音效檔
F 從dsp音效卡裝置中讀入pcm資料
G 關閉裝置及儲存音效檔
大體流程的虛擬碼分兩部分給出,一部分為基於mixer編程的專門負責調節音效卡的錄音效果,第二部分為錄音程式。
mixer混音編程
6.4.1.1 常用命令簡介

音效卡上的混音器由多個混音通道組成,它們可以通過驅動程式提供的裝置檔案/dev/mixer進行編程。對混音器的操作是通過ioctl系統調用來完成的,並且所有控制命令都由SOUND_MIXER或者MIXER開頭,表1列出了常用的幾個混音器控制命令:
名 稱 作 用
SOUND_MIXER_VOLUME 主音量大小
SOUND_MIXER_BASS 低音控制
SOUND_MIXER_TREBLE 高音控制
SOUND_MIXER_SYNTH FM 合成器
SOUND_MIXER_PCM 主D/A轉換器
SOUND_MIXER_SPEAKER PC喇叭
SOUND_MIXER_LINE 音頻線輸入
SOUND_MIXER_MIC 麥克風輸入
SOUND_MIXER_CD CD 輸入
SOUND_MIXER_IMIX 回放音量
SOUND_MIXER_ALTPCM 從D/A 轉換器
SOUND_MIXER_RECLEV 錄音音量
SOUND_MIXER_IGAIN 輸入增益
SOUND_MIXER_OGAIN 輸出增益
SOUND_MIXER_LINE1 音效卡的第1輸入
SOUND_MIXER_LINE2 音效卡的第2輸入
SOUND_MIXER_LINE3 音效卡的第3輸入
6.4.1.2 錄音編程

Mixer部分比較簡單現將代碼及注釋附下:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/soundcard.h>
/* 用來儲存所有可用混音裝置的名稱 */
const char *sound_device_names[] = SOUND_DEVICE_NAMES;
int fd; /* 混音裝置所對應的檔案描述符 */
int devmask, stereodevs; /* 混音器資訊對應的位元影像掩碼 */
char *name;
/* 顯示命令的使用方法及所有可用的混音裝置 */
void usage()
{
int i;
fprintf(stderr, "usage: %s <device> <left-gain%%> <right-gain%%>\n"
" %s <device> <gain%%>\n\n"
"Where <device> is one of:\n", name, name);
for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
if ((1 << i) & devmask) /* 只顯示有效混音裝置 */
fprintf(stderr, "%s ", sound_device_names[i]);
fprintf(stderr, "\n");
exit(1);
}
int main(int argc, char *argv[])
{
int left, right, level; /* 增益設定 */
int status; /* 系統調用的傳回值 */
int device; /* 選用的混音裝置 */
char *dev; /* 混音裝置的名稱 */
int i;
name = argv[0];
/* 以唯讀方式開啟混音裝置 */
fd = open("/dev/mixer", O_RDONLY);
if (fd == -1) {
perror("unable to open /dev/mixer");
exit(1);
}
/* 獲得所需要的資訊 */
status = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
if (status == -1)
perror("SOUND_MIXER_READ_DEVMASK ioctl failed");
status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);
if (status == -1)
perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");
/* 檢查使用者輸入 */
if (argc != 3 && argc != 4)
usage();
/* 儲存使用者輸入的混音器名稱 */
dev = argv[1];
/* 確定即將用到的混音裝置 */
for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
if (((1 << i) & devmask) && !strcmp(dev, sound_device_names[i]))
break;
if (i == SOUND_MIXER_NRDEVICES) { /* 沒有找到匹配項 */
fprintf(stderr, "%s is not a valid mixer device\n", dev);
usage();
}
/* 尋找到有效混音裝置 */
device = i;
/* 擷取增益值 */
if (argc == 4) {
/* 左、右聲道均給定 */
left = atoi(argv[2]);
right = atoi(argv[3]);
} else {
/* 左、右聲道設為相等 */
left = atoi(argv[2]);
right = atoi(argv[2]);
}
/* 對非立體聲裝置給出警告資訊 */
if ((left != right) && !((1 << i) & stereodevs)) {
fprintf(stderr, "warning: %s is not a stereo device\n", dev);
}
/* 將兩個聲道的值合到同一變數中 */
level = (right << 8) + left;
/* 設定增益 */
status = ioctl(fd, MIXER_WRITE(device), &level);
if (status == -1) {
perror("MIXER_WRITE ioctl failed");
exit(1);
}
/* 獲得從驅動返回的左右聲道的增益 */
left = level & 0xff;
right = (level & 0xff00) >> 8;
/* 顯示實際設定的增益 */
fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right);
/* 關閉混音裝置 */
close(fd);
return 0;
}
用mixer調節音效卡輸入和輸出時的聲音效果
用armv4l-unknown-linux-gcc編譯好上面的程式之後,下載到yc2440開發版,先不帶任何參數執行一遍,此時會列出音效卡上所有可用的混音通道:
[nnliubin@localhost sound]$ ./mixer
usage: ./mixer <device> <left-gain%> <right-gain%>
./mixer <device> <gain%>
Where <device> is one of:
vol pcm speaker line mic cd igain line1 phin video
之後就可以很方便地設定各個混音通道的增益大小了,例如下面的命令就能夠將麥克風輸入的左、右聲道的增益分別設定為80%和90%:
[nnliubin@localhost sound]$ ./mixer mic 80 90
cd gain set to 80% / 90%
6.4.2 錄音儲存

因為錄音部分程式比較長,所以將使用部分代碼加文字的方式進行描述,並且錄成的格式均為wav。
在程式前就最基本的東西明確一下。音效卡上的DSP裝置進行聲音錄製和回放的基本架構,它的功能是先錄製幾秒種音頻資料,將其存放在記憶體緩衝區中,然後再進行回放,其所有的功能都是通過讀寫/dev/dsp裝置檔案來完成的。(詳見核心代碼)
這樣錄音程式就完成了,按8000hz,8位進行採樣錄音時間設定的為30秒,調用的為OSS的ioctl介面。
運行如下命令看效果
Cd 目錄名
armv4l-unknown-linux-gcc -o soundrec sound.c
把soundrec檔案下載到yc2440開發板
運行./soundrec 就能進入錄音介面了
6.5 yc2440開發板下放音的實現機制6.5.1 放音編程

為了更好的進一步檢測我們的錄音資料的正確性和錄音效果決定寫一專門播放wav檔案的控制台播放器。其實錄音功能實現以後,
放音功能的實現就可以類比實現了,只不過將過程反過來具體流程如下:
A 讀wav檔案的頭,將各部分參數儲存
B 通過ioctl來設定各個參數
C 將pcm資料讀入/dev/dsp
完成以上功能以後,就能開發板上播放任何一首wav格式的音效檔了,以下為縮減版代碼(一些和錄音相當的部分就略去了)
將程式用交叉編譯器編譯成二進位可執行檔後,下載到yc2440開發版,就可以開始享受放音程式了。
6.6 核心代碼1 .PCM 到wav

// 8k hz,量化 16bit (也可能是8bit),單聲道
//標頭檔
#include <iostream>
#include <string>
#include <iostream>
#include <fstream>
#include "stdio.h"
using namespace std;//unsigned long = DWORD,unsigned short = WORD
//wav頭的結構如下所示:
//RIFF chunk
typedef struct { /*前面已經提到,這裡省略*/
}HEADER;
//fmt sub-chunk
typedef struct { /*內容在此略去*/
}FMT;
//"data" sub-chunk
typedef struct { /*內容略去*/
}DATA;

int main()
{
//2008.8.8補充,對IMA ADPCM 的處理,把資料轉化為二進位儲存狀態
//開啟輸入檔案和輸出檔案
ifstream fin;
fin.open("ADPCM16.txt",ios::binary);
ofstream fout;
fout.open("ADPCM.txt",ios::binary);
char ADPCM16[2];
int TWO_ADPCM_BYTE//高4位和低4位放到一個位元組裡,
ADPCM1,ADPCM2;//分別儲存高位元組和低位元組;
int i =0;
//輸入10進位資料轉化為二進位儲存,以下為轉化演算法:
while(fin>>ADPCM16[1]>>ADPCM16[2])
{
if((int)ADPCM16[1]>81) //為a,b,c,d,e,f
ADPCM1=int(ADPCM16[1])-87;
else
ADPCM1=int(ADPCM16[1])-int('0');
if((int)ADPCM16[2]>81) //為a,b,c,d,e,f
ADPCM2=int(ADPCM16[2])-87;
else
ADPCM2=int(ADPCM16[2])-int('0');
TWO_ADPCM_BYTE = ADPCM1*16 + ADPCM2;
fout.write((char*)(&TWO_ADPCM_BYTE),1);
}
fin.close();
fout.close();*/
//2008.7.17加頭程式
HEADER pcmHEADER;
FMT pcmFMT;
DATA pcmDATA;
//unsigned short m_pcmData;
char m_pcmData;
FILE *fp/*開啟PCM檔案*/,*fpCpy/*開啟輸出檔案*/;
//HEADER部分;
strcpy(pcmHEADER.fccID,"RIFF");
strcpy(pcmHEADER.fccType,"WAVE");
if(fseek(fpCpy,sizeof(HEADER),SEEK_SET))//跳過HEADER的長度,以便下面繼續寫入wav檔案的資料;
exit(0);
//初始化FMT成員資料並寫入輸出檔案;
strcpy(pcmFMT.fccID,"fmt ");
fwrite(&pcmFMT,sizeof(FMT),1,fpCpy);
//DATA部分;
strcpy(pcmDATA.fccID,"data");
//跳過DATA的長度,開始寫pcm資料部分,同時計算出資料量的大小;
fseek(fpCpy,sizeof(DATA),1);
//註:每次讀入一個PCM資料(我們用的是16bit,也即2 bytes)
fread(&m_pcmData,sizeof(unsigned short),1,fp); //從.pcm中讀入資料
//採樣8 bit 時:
// fread(&m_pcmData,sizeof(char),1,fp); //從.pcm中讀入資料
pcmDATA.dwSize=0;
//讀入並儲存資料
while(!feof(fp))
{
pcmDATA.dwSize+=2; //計算資料的長度;每讀入一個資料,長度就加2;
//參考:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
fwrite(&m_pcmData,sizeof(unsigned short),1,fpCpy);
fread(&m_pcmData,sizeof(unsigned short),1,fp);
//音頻採樣大小為8 bit 時
//pcmDATA.dwSize+=1;
//fwrite(&m_pcmData,sizeof(char),1,fpCpy);
//fread(&m_pcmData,sizeof(char),1,fp);
}
fclose(fp); //關閉檔案
pcmHEADER.dwSize=36+pcmDATA.dwSize;
rewind(fpCpy); //將fpCpy變為.wav的頭,以便於寫入HEADER和DATA;
fwrite(&pcmHEADER,sizeof(HEADER),1,fpCpy); //寫入HEADER
fseek(fpCpy,sizeof(FMT),1); //跳過FMT,因為FMT已經寫入
fwrite(&pcmDATA,sizeof(DATA),1,fpCpy); //寫入DATA;
fclose(fpCpy); //關閉檔案
return 0;

2 .yc2440開發板下錄音

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#include <string.h>
#define LENGTH 30 /* 錄音時間 */
#define RATE 8000 /* 採樣頻率 */
#define SIZE 8 /* 採樣位元 */
#define CHANNELS 1 /* 聲道數*/

/* 用於儲存數字音頻資料的記憶體緩衝區 */
unsigned char buf[LENGTH*RATE*SIZE/8];
typedef struct{/*以下代碼已略去*/
//用該結構來儲存wav頭部分裡面的前10個位元組
}HEADER;
//fmt 部分
typedef struct {/*以下代碼已略去*/
//用該結構來儲存wav頭部分裡面的fmt塊
}FMT;
typedef struct {/*以下代碼已略去*/
//用該結構來儲存wav頭部分裡面的data塊
}DATA;
int main()
{
int fd; /* 聲音裝置的檔案描述符 */
int arg; /* 用於ioctl調用的參數*/
int status; /* 系統調用的傳回值*/
FILE* out; /* 輸出的音效檔*/
int saveSize=LENGTH*RATE*SIZE/8; /* 資料大小*/
HEADER pcmHEADER;
FMT pcmFMT;
DATA pcmDATA;
//unsigned short m_pcmData;
char m_pcmData;
/* 開啟聲音裝置 */
fd = open("/dev/dsp", O_RDWR);
if (fd < 0) {
perror("open of /dev/dsp failed");
exit(1);
}
/* 設定採樣時的量化位元*/
arg = SIZE;
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
// printf("MIC gain is at %d %%\n",vol);
if (status == -1)
perror("SOUND_PCM_WRITE_BITS ioctl failed :");
if (arg != SIZE)
perror("unable to set sample size");
/* 設定採樣時的聲道數 */
arg = CHANNELS;
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != CHANNELS)
perror("unable to set number of channels");
/* 設定採樣時的採樣頻率*/
arg = RATE;
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_WRITE ioctl failed");
printf("Say something:\n");
status = read(fd, buf, sizeof(buf)); /* 將資料讀入緩衝區 */
if (status != sizeof(buf))
perror("read wrong number of bytes");
printf("Save as test.wav:\n");
if((out=fopen("./test.wav","wb"))==NULL)
{ printf("cannot open outfile\n");}
//初始化header部分
/*該部分代碼以略去*/
if(fseek(out,sizeof(HEADER),SEEK_SET))
exit(0);
//初始化Fmt部分
/*該部分代碼已略去*/
//將FMT寫入wav檔案中
fwrite(&pcmFMT,sizeof(FMT),1,out);
//DATA部分初始化
/*該部分代碼已略去*/
fwrite(buf, sizeof(char),saveSize,out); /*存至wav中*/
rewind(out); /*將檔案指標定位到檔案頭*/
fwrite(&pcmHEADER,sizeof(HEADER),1,out); /*寫入header部分*/
fseek(out,sizeof(FMT),1);
fwrite(&pcmDATA,sizeof(DATA),1,out); /*寫入data部分*/
fclose(out);
close(fd); /*關閉裝置錄音結束*/
}

3 yc2440開發板下放音

#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include <linux/soundcard.h>
#define BUFSIZE 512 //定義緩衝區大小
/*和錄音一樣定義 header,fmt data 三種資料結構來
儲存wav的頭資訊 */
int main(int argc, char *argv[])
{
/*定義所需的各種變數與錄音類似*/
struct RIFF_Header riff_header;
struct Chunk_Header fmt_chunk, data_chunk;
struct Wave_Format wavfmt;

char buf[BUFSIZE];
FILE * fwave;
//和錄音一樣定義各种放音參數
int sndfd, status, arg, readbytes, writebytes, writed;
if( argc < 2 ){ //如果沒有帶命令列參數報錯
fprintf(stderr, "Usage: wavplay <filename>\n");
exit(-1);
}
fwave = fopen( argv[1], "r"); //以寫的方式開啟命令列參數裡所帶的音效檔
if( fwave == NULL ){
fprintf(stderr, "Can't open file %s\n", argv[1]);
exit(-1);
}
fread(&riff_header, 1, sizeof(struct RIFF_Header), fwave);
if( strncmp(riff_header.RIFF_ID, "RIFF", 4) || strncmp(riff_header.RIFF_Format, "WAVE",4)){ 如果不滿足wav檔案的標準定義這裡顯示不可識別的檔案形式
fprintf(stderr, "Unknown file format.\n");
exit(-1);
}
sndfd = open("/dev/dsp", O_RDWR);
if (sndfd < 0) { //以讀寫方式開啟聲音裝置
perror("open of /dev/dsp failed");
exit(-1);
}
fread(&fmt_chunk, 1, sizeof(struct Chunk_Header), fwave);
if( !strncmp(fmt_chunk.Chunk_ID, "fmt ", 4) ){
//將fmt chunk部分參數讀進來並儲存
/*該部分代碼因與錄音類似以略去*/
}else{ //如果不是標準的格式報錯
fprintf(stderr, "Can't find fmt chunk.\n");
exit(-1);
}
while( fread(&data_chunk, 1, sizeof(struct Chunk_Header), fwave) != 0 )
if( !strncmp(data_chunk.Chunk_ID, "data", 4) ){
//讀wav檔案裡面的PCM資料
printf("Begin Play\n");
/* data chunk */
writed = 0;
while(writed < data_chunk.Chunk_Size){
//當pcm資料未處理完時繼續處理
readbytes = fread(buf, 1, BUFSIZE, fwave); //從音效檔讀資料
writebytes = write(sndfd, buf, readbytes); //將資料寫入sndfd音效卡裝置實施放音
if( writebytes != readbytes )
perror("wrote wrong number of bytes");
writed += readbytes;
}
}else{
/* 格式不對掠過 */
fseek(fwave, data_chunk.Chunk_Size + fmt_chunk.Chunk_Size%2, SEEK_CUR);
}
fclose(fwave); //關閉各裝置
close(sndfd);
return 0;
}
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.