版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
Linux下音頻設(shè)備編程8.1音頻信號基礎(chǔ)音頻信號是一種連續(xù)變化的模擬信號,但電腦只能處理和記錄二進位的數(shù)字信號,而由自然音源得到的音頻信號必須經(jīng)過一定的變換,成為數(shù)字音頻信號之後,才能送到電腦中做進一步的處理。數(shù)字音頻信號模擬音頻信號數(shù)位化的典型方法是對時間座標(biāo)按相等的時間間隔做採樣,對振幅做量化,單位時間內(nèi)的採樣次數(shù)稱為採樣頻率。這樣,一段聲波被數(shù)位化後就可以變成一串?dāng)?shù)值,每個數(shù)值對應(yīng)相應(yīng)抽樣點的振幅值,按順序?qū)⑦@些數(shù)字排列起來就是數(shù)字音頻信號了。這就是模擬-數(shù)字轉(zhuǎn)化(ADC)過程。數(shù)字-模擬轉(zhuǎn)化(DAC)過程則相反,將連續(xù)的數(shù)字按採樣時的頻率和順序轉(zhuǎn)換成對應(yīng)的電壓。通俗一點講,音頻ADC/DAC就是錄音/放音。放音是數(shù)字音頻信號轉(zhuǎn)換成模擬音頻信號,以驅(qū)動耳機、功放等模擬設(shè)備,而錄音則是要將麥克風(fēng)等產(chǎn)生的模擬音頻信號轉(zhuǎn)換成數(shù)字音頻信號,並最終轉(zhuǎn)換成電腦可以處理的通用音頻檔格式。採樣就是每隔一定時間讀一次聲音信號的幅度,而量化則是將採樣得到的聲音信號幅度轉(zhuǎn)換為數(shù)字值。從本質(zhì)上講,採樣是時間上的數(shù)位化,而量化則是幅度上的數(shù)位化。採樣頻率的選擇應(yīng)該遵循奈奎斯特(Nyquist)採樣理論:採樣頻率高於輸入信號最高頻率的兩倍,就能從採樣信號序列重構(gòu)原始信號。為了保證聲音不失真,採樣頻率應(yīng)該在40kHz左右。常用的音頻採樣頻率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果採用更高的採樣頻率,還可以達(dá)到DVD的音質(zhì)。量化是對模擬音頻信號的幅度進行數(shù)位化,量化位數(shù)決定了模擬信號數(shù)位化以後的動態(tài)範(fàn)圍,常用的有8位、12位和16位。量化位越高,信號的動態(tài)範(fàn)圍越大,數(shù)位化後的音頻信號就越接近原始信號,但所需要的存儲空間也越大。聲道數(shù)是反映音頻數(shù)位化品質(zhì)的另一個重要因素,它有單聲道、雙聲道和多聲道之分。雙聲道又稱為身歷聲,在硬體中有兩條線路,音質(zhì)和音色都要優(yōu)於單聲道,但數(shù)位化後佔據(jù)的存儲空間的大小要比單聲道多一倍。多聲道能提供更好的聽覺感受,不過佔用的存儲空間也更大。音頻檔格式1.MP3MP3的全稱應(yīng)為MPEG1Layer-3音頻檔。MPEG(MovingPictureExpertsGroup)在漢語中譯為活動圖像專家組,特指活動影音壓縮標(biāo)準(zhǔn),MPEG音頻檔是MPEG1標(biāo)準(zhǔn)中的聲音部分,也叫MPEG音頻層,它根據(jù)壓縮品質(zhì)和編碼複雜程度劃分為三層,即Layer-1、Layer-2、Layer-3,且分別對應(yīng)MP1、MP2、MP3這三種聲音檔,並根據(jù)不同的用途,使用不同層次的編碼。MPEG音頻編碼的層次越高,編碼器越複雜,壓縮率也越高,MP1和MP2的壓縮率分別為4:1和6:1~8:1,而MP3的壓縮率則高達(dá)10:1~12:1,也就是說,一分鐘CD音質(zhì)的音樂,未經(jīng)壓縮需要10MB的存儲空間,而經(jīng)過MP3壓縮編碼後只有1MB左右。不過MP3對音頻信號採用的是有損壓縮方式,為了降低聲音失真度,MP3採取了“感官編碼技術(shù)”,即編碼時先對音頻檔進行頻譜分析,然後用篩檢程式濾掉噪音電平,接著通過量化的方式將剩下的每一位打散排列,最後形成具有較高壓縮比的MP3檔,並使壓縮後的檔在回放時能夠達(dá)到比較接近原音源的聲音效果。2.WMAWMA就是WindowsMediaAudio編碼後的檔格式,由微軟開發(fā)。WMA針對的不是單機市場,而是網(wǎng)路。它的競爭對手就是網(wǎng)路媒體市場中著名的RealNetworks。微軟聲稱,在只有在64kbps的碼率情況下,WMA可以達(dá)到接近CD的音質(zhì)。與以往的編碼不同,WMA支持防複製功能,它支持通過WindowsMediaRightsManager加入保護,可以限制播放時間和播放次數(shù)甚至於播放的機器等。由於WMA支持流技術(shù),即一邊讀一邊播放,因此WMA可以很輕鬆的實現(xiàn)線上廣播。WMA有著優(yōu)秀的技術(shù)特徵,在微軟的大力推廣下,這種格式被越來越多的人所接受。3.WAV這是一種古老的音頻檔格式,由微軟開發(fā)。WAV檔格式符合RIFF(ResourceInterchangeFileFormat,資源互換檔格式)規(guī)範(fàn)。所有的WAV都有一個檔頭,這個檔頭保存了音頻流的編碼參數(shù)。WAV對音頻流的編碼沒有硬性規(guī)定,除了PCM之外,還有幾乎所有支持ACM規(guī)範(fàn)的編碼都可以為WAV的音頻流進行編碼。在Windows平臺下,基於PCM編碼的WAV是被支持得最好的音頻格式,所有音頻軟體都能完美支持。由於本身可以達(dá)到較高的音質(zhì)的要求,WAV也是音樂編輯創(chuàng)作的首選格式,適合保存音樂素材。因此,基於PCM編碼的WAV被作為一種仲介的格式,常常使用在其他編碼的相互轉(zhuǎn)換之中,例如,MP3轉(zhuǎn)換成WMA。4.Ogg
VorbisOGG是一個龐大的多媒體開發(fā)計畫的專案名稱,涉及視頻音頻等方面的編碼開發(fā)。整個OGG專案計畫的目的就是向任何人提供完全免費的多媒體編碼方案,OGG的信念就是開源和免費。Vorbis是OGG專案中音頻編碼的正式命名,目前Vorbis已經(jīng)開發(fā)成功,並且開發(fā)出了編碼器。Ogg
Vorbis是高質(zhì)量的音頻編碼方案,官方數(shù)據(jù)顯示:Ogg
Vorbis可以在相對較低的數(shù)據(jù)速率下實現(xiàn)比MP3更好的音質(zhì),而且它可以支持多聲道。多聲道音樂的興起,給音樂欣賞帶來了革命性的變化,尤其在欣賞交響時,會帶來更多臨場感。這場革命性的變化是MP3無法適應(yīng)的,因為MP3只能編碼2個聲道。與MP3一樣,Ogg
Vorbis是一種靈活開放的音頻編碼,能夠在編碼方案已經(jīng)固定下來後繼續(xù)對音質(zhì)進行明顯的調(diào)節(jié)和新演算法的改良。因此,它的聲音品質(zhì)將會越來越好。與MP3相似,Ogg
Vorbis更像一個音頻編碼框架,可以不斷導(dǎo)入新技術(shù),逐步完善。5.RARA就是RealAudio格式,這是因特網(wǎng)上接觸得非常多的一種格式。這種格式完全針對網(wǎng)路上的媒體市場,支持非常豐富的功能。這種格式最大的特點是可以根據(jù)聽眾的帶寬來控制碼率,在保證流暢的前提下盡可能提高音質(zhì)。RA可以支持多種音頻編碼,其中包括ATRAC3。和WMA一樣,RA不但支持邊讀邊放,也同樣支持使用特殊協(xié)議來隱匿檔的真實網(wǎng)路地址,從而實現(xiàn)只線上播放而不提供下載的欣賞方式。6.APEAPE是Monkey’sAudio提供的一種無損壓縮格式。由於Monkey’sAudio提供了Winamp的插件支持,因此這就意味著壓縮後的檔不再是單純的壓縮格式,而是與MP3一樣可以播放的音頻檔格式。這種格式的壓縮比遠(yuǎn)低於其他格式,但由於能夠做到真正無損,因此獲得了不少發(fā)燒用戶的青睞。現(xiàn)在有不少無損壓縮方案,APE是其中有著突出性能的格式,它具有令人滿意的壓縮比,以及飛快的壓縮速度,成為不少朋友私下交流發(fā)燒音樂的惟一選擇。7.AACAAC(高級音頻編碼技術(shù),AdvancedAudioCoding)是杜比實驗室為音樂社區(qū)提供的技術(shù),聲稱最大能容納48通道的音軌,採樣率達(dá)96kHz。AAC在320kbps的數(shù)據(jù)速率下能為5.1聲道音樂節(jié)目提供相當(dāng)於ITU-R廣播的品質(zhì)。AAC是遵循MPEG-2的規(guī)格所開發(fā)的技術(shù),與MP3比起來,它的音質(zhì)比較好,也能夠節(jié)省大約30%的存儲空間與帶寬。8.ATRAC3ATRAC3(AdaptiveTransformAcousticCoding3)由日本索尼公司開發(fā),是MD所採用的ATRAC的升級版,其壓縮率(約為ATRAC的2倍)和音質(zhì)均與MP3相當(dāng)。壓縮原理包括同時掩蔽、時效掩蔽和等響度曲線等,與MP3大致相同。ATRAC3的版權(quán)保護功能採用的是OpenMG。目前,對應(yīng)ATRAC3的可攜式播放機主要是索尼公司自己的產(chǎn)品。不過,該公司已於2000年2月與富士通、日立、NEC、Rohm、三洋和TI等半導(dǎo)體製造商簽署了製造並銷售ATRAC3用LSI的專利許可協(xié)議。WAVE檔格式剖析WAVE檔作為多媒體中使用的聲波檔格式之一,是以RIFF格式為標(biāo)準(zhǔn)的。RIFF可以看成是一種樹形結(jié)構(gòu),其基本構(gòu)成單位為chunk,猶如樹形結(jié)構(gòu)中的節(jié)點,每個chunk由辨別碼、數(shù)據(jù)大小,以及數(shù)據(jù)所組成。WAVE檔的“RIFF”格式辨別碼為“WAVE”,整個檔由兩個chunk所組成,辨別碼分別是“fmt”和“data”。在“fmt”chunk下包含了一個PCM波形格式的數(shù)據(jù)結(jié)構(gòu),在此之後是包含原始聲音資訊的採樣數(shù)據(jù),這些數(shù)據(jù)是可以直接送到IIS匯流排的數(shù)字音頻信號。WAVE檔各部分內(nèi)容及格式如表8.1所示。常見的聲音檔主要有兩種,分別對應(yīng)於單聲道和雙聲道。對於單聲道聲音檔,採樣速率是11.025kHz,採樣數(shù)據(jù)為8位的短整數(shù)(shortint);而對於雙聲道身歷聲聲音檔,採樣速率為44.1kHz,每次採樣數(shù)據(jù)為一個16位的整數(shù)(int),高8位和低8位分別代表左右兩個聲道。WAVE檔數(shù)據(jù)塊包含以脈衝編碼調(diào)製(PCM)格式表示的樣本。WAVE檔是由樣本組織而成的。在WAVE檔中,聲道0代表左聲道,聲道1代表右聲道。在多聲道WAVE檔中,樣本是交替出現(xiàn)的。例如,對於8位雙聲道的身歷聲,存儲數(shù)據(jù)格式依次為:0聲道(左)、1聲道(右)、0聲道(左)、1聲道(右)。對於16位身歷聲,存儲數(shù)據(jù)依次為:0聲道(左)低位元組、0聲道(左)高位元組、1聲道(右)低位元組、1聲道(右)高位元組。8.2基於IIS介面的音頻系統(tǒng)IIS介面控制原理S3C2410X內(nèi)置了一個IIS匯流排控制器,該控制器實現(xiàn)到一個外部8/16位身歷聲音頻編解碼器介面,支持IIS匯流排數(shù)據(jù)格式和MSB-justified數(shù)據(jù)格式。S3C2410X中有兩條串行數(shù)據(jù)線,一條是輸入信號數(shù)據(jù)線,一條是輸出信號數(shù)據(jù)線,以同時發(fā)送和接收數(shù)據(jù)。IIS介面有3種工作方式:
正常傳輸模式,正常模式下使用IISCON寄存器對FIFO進行控制。如果傳輸FIFO緩存為空,IISCON的第7位被設(shè)置為“0”,表示不能繼續(xù)傳輸數(shù)據(jù),需要CPU對緩存進行處理。如果傳輸FIFO緩存非空,IISCON的第7位被設(shè)置成“1”,表示可以繼續(xù)傳輸數(shù)據(jù)。同樣,數(shù)據(jù)接收時,如果FIFO滿,標(biāo)識位是“0”,此時,需要CPU對FIFO進行處理,如果FIFO沒有滿,那麼標(biāo)誌位是“1”,這個時候可以繼續(xù)接收數(shù)據(jù)。
DMA模式,通過設(shè)置IISFCON寄存器可以使IIS介面工作於這種模式下。在這種模式中,F(xiàn)IFO寄存器組的控制權(quán)掌握在DMA控制器上,當(dāng)FIFO滿了,由DMA控制器對FIFO中的數(shù)據(jù)進行處理。DMA模式的選擇由IISCON寄存器的第4位和第5位控制。
傳輸/接收模式,這種模式下,IIS數(shù)據(jù)可以同時接收和發(fā)送音頻數(shù)據(jù)。IIS匯流排控制器結(jié)構(gòu)如圖8.2所示,各功能說明如下:
兩個5比特預(yù)除器IPSR,IPSA_A用於產(chǎn)生IIS匯流排介面的主時鐘,IPSA_B用做外部CODEC時鐘產(chǎn)生器。
16位元組FIFO,在發(fā)送數(shù)據(jù)時數(shù)據(jù)被寫進TxFIFO,在接收數(shù)據(jù)時數(shù)據(jù)從RxFIFO中讀取。
主IISCLK產(chǎn)生器SCLKG,在主模式下,有主時鐘產(chǎn)生串行位時鐘。
通道產(chǎn)生器和狀態(tài)機CHNC,IISCLK和IISLRCK有通道狀態(tài)機產(chǎn)生並控制。
16比特移位寄存器(SFTR),在發(fā)送數(shù)據(jù)時,並行數(shù)據(jù)經(jīng)由SFTR變成串行數(shù)據(jù)輸出;在數(shù)據(jù)接收時,串行數(shù)據(jù)由SFTR轉(zhuǎn)變成並行數(shù)據(jù)。音頻介面電路設(shè)計音頻介面程式設(shè)計1.放音放音程序代碼如下:#include"2410addr.h"#include"2410lib.h"#include"def.h“#include"2410iis.h"voidChangeDMA2(void);voidIIS_PortSetting(void);void_WrL3Addr(U8data);void_WrL3Data(U8data,inthalt);void__irqDMA2_Done(void);void__irqDMA2_Rec_Done(void);void__irq
RxInt(void);void__irq
Muting(void);#defineL3C(1<<4)//GPB4=L3CLOCK#defineL3D(1<<3)//GPB3=L3DATA#defineL3M(1<<2)//GPB2=L3MODE#definePLAY0#defineRECORD1//#defineREC_LEN0x50000//327,680Bytes#defineREC_LEN0x100000//1,048,576Bytes#defineDataCount0x10000//IISMaster/SlaveDataRx/TxCount#defineDataDisplay0x100//IISMasterDataDisplayCount#definePollMode0//1:PollingMode#defineDMA2Mode1//1:DMA2Mode#defineMICGain_Amp_Sel 0//0:Inputchannel2Amp.1:MICAmp.unsignedchar*Buf,*_temp;unsignedshort*rec_buf;volatileunsignedintsize=0;volatileunsignedint
fs=0;volatilecharwhich_Buf=1;volatilecharRec_Done=0;volatilecharmute=1;voidPlayTest_Iis(void){unsignedint
save_B,save_E,save_PB,save_PE;Uart_TxEmpty(0);由於IIS時鐘從系統(tǒng)分頻得到,下麵的代碼將系統(tǒng)PCLK降到33MHz,而且降頻後必須對串口重新進行初始化。ChangeClockDivider(1,1);//1:2:4ChangeMPllValue(0x96,0x5,0x1);//FCLK=135.428571MHz(PCLK=33.857142MHz)Uart_Init(33857142,115200);Uart_Printf("[IIStest(Play)usingUDA1341CODEC]\n");然後將用到的端口保存起來,並進行端口初始化。save_B=rGPBCON;save_E=rGPECON;save_PB=rGPBUP;save_PE=rGPEUP;IIS_PortSetting();IIS採用DMA方式進行錄音和播放,因此需要進行DMA中斷的註冊。pISR_DMA2=(unsigned)DMA2_Done;然後獲取語音數(shù)據(jù)及其大小、採樣頻率。rINTSUBMSK=~(BIT_SUB_RXD0);rINTMSK=~(BIT_EINT0|BIT_UART0|BIT_DMA2);//Non-cacheablearea=0x31000000~0x33feffffBuf=(unsignedchar*)0x31000000;_temp=Buf;Uart_Printf("DownloadthePCM(noADPCM)filebyDNW(Withheader)!!\n");size=*(Buf)|*(Buf+1)<<8|*(Buf+2)<<16|*(Buf+3)<<24;Uart_Printf("\nNow,Downloading...",size);rINTSUBMSK|=BIT_SUB_RXD0;size=*(Buf+0x2c)|*(Buf+0x2d)<<8|*(Buf+0x2e)<<16|*(Buf+0x2f)<<24;size=(size>>1)<<1;fs=*(Buf+0x1c)|*(Buf+0x1d)<<8|*(Buf+0x1e)<<16|*(Buf+0x1f)<<24;接著初始化UDA1341,設(shè)置為放音模式:Init1341(PLAY);接著進行DMA初始化:rDISRC2=(int)(Buf+0x30);//0x31000030~(Removeheader)rDISRCC2=(0<<1)+(0<<0);//源地址位於系統(tǒng)匯流排AHB,地址遞增rDIDST2=((U32)IISFIFO);//IISFIFOrDIDSTC2=(1<<1)+(1<<0);//目的地址位於外設(shè)匯流排APB,地址固定rDCON2=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(0<<24)+(1<<23)+(0<<22)+(1<<20)+(size/4);//101000001001xxxx
xxxx
xxxx
xxxx
xxxx//Handshake[31],SyncPCLK[30],CURR_TCInterruptRequest[29],//SingleTx[28],Singleservice[27],//I2SSDO[26:24],DMAsourceselected[23],Auto-reload[22],//Half-word[21:20],size/2[19:0]rDMASKTRIG2=(0<<2)+(1<<1)+(0<<0);//No-stop[2],DMA2channelOn[1],No-swtrigger[0]IIS初始化:if(fs==44100)//11.2896MHz(256fs)rIISPSR=(2<<5)+2;//PrescalerA,B=2<-FCLK135.4752MHz(1:2:4)else//fs=22050,5.6448MHz(256fs)rIISPSR=(5<<5)+5;//PrescalerA,B=5<-FCLK135.4752MHz(1:2:4)rIISCON=(1<<5)+(1<<2)+(1<<1);//TxDMAenable[5],Rxidle[2],Prescalerenable[1]//Mastermode[8],Txmode[7:6],LowforLeftChannel[5],IISformat[4],16bitch.[3],CDCLK256fs[2],IISCLK32fs[1:0]rIISMOD=(0<<8)+(2<<6)+(0<<5)+(0<<4)+(1<<3)+(0<<2)+(1<<0);rIISFCON=(1<<15)+(1<<13);//Tx
DMA,TxFIFO-->startpiling....啟動IIS。IIS啟動後,將採用DMA方式播放語音數(shù)據(jù),播放完畢後將引發(fā)中斷,並重新播放語音數(shù)據(jù)??赏ㄟ^按任意鍵,決定播放是否結(jié)束。//IISTxStartUart_Printf("\nPressanykeytoexit!!!\n");rIISCON|=0x1;//IISInterfacestartwhile(!Uart_GetKey()){if((rDSTAT2&0xfffff)<(size/6))ChangeDMA2();}其中,ChangeDMA2()函數(shù)根據(jù)標(biāo)誌位which_Buf決定是否重新播放,標(biāo)誌位which_Buf在中斷服務(wù)函數(shù)DMA2_Done()中設(shè)置。語音播放結(jié)束後,通知IIS,並恢復(fù)寄存器。Delay(10);//ForendofH/WTxrIISCON=0x0;//IISInterfacestoprDMASKTRIG2=(1<<2);//DMA2stoprIISFCON=0x0;//ForFIFOflushsize=0;rGPBCON=save_B;rGPECON=save_E;rGPBUP=save_PB;rGPEUP=save_PE;最後關(guān)閉中斷,並恢復(fù)系統(tǒng)時鐘:rINTMSK=(BIT_DMA2|BIT_EINT0);ChangeMPllValue(0xa1,0x3,0x1);//FCLK=202.8MHzUart_Init(0,115200);mute=1;}2.錄音錄音程式在初始化等動作上與放音類似,代碼如下:voidRecord_Iis(void){unsignedint
save_B,save_E,save_PB,save_PE;Uart_TxEmpty(0);ChangeClockDivider(1,1);//1:2:4ChangeMPllValue(0x96,0x5,0x1);//FCLK=135428571Hz,PCLK=3.385714MHzUart_Init(33857142,115200);Uart_Printf("[RecordtestusingUDA1341]\n");save_B=rGPBCON;save_E=rGPECON;save_PB=rGPBUP;save_PE=rGPEUP;IIS_PortSetting();錄音數(shù)據(jù)保存在rec_buf中:rec_buf=(unsignedshort*)0x31000000;pISR_DMA2=(unsigned)DMA2_Rec_Done;pISR_EINT0=(unsigned)Muting;rINTMSK=~(BIT_DMA2);Init1341(RECORD);rDISRCC2=(1<<1)+(1<<0);//APB,FixrDISRC2=((U32)IISFIFO);//IISFIFOrDIDSTC2=(0<<1)+(0<<0);//AHB,IncrementrDIDST2=(int)rec_buf;//0x31000000~rDCON2=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(1<<24)+(1<<23)+(1<<22)+(1<<20)+REC_LEN;//Handshake,syncPCLK,TCint,singletx,singleservice,//I2SSDI,I2SRxrequest,//Off-reload,half-word,0x50000halfword.rDMASKTRIG2=(0<<2)+(1<<1)+0;//No-stop,DMA2channelon,No-swtrigger//Master,Rx,L-ch=low,IIS,16bitch,CDCLK=256fs,IISCLK=32fsrIISMOD=(0<<8)+(1<<6)+(0<<5)+(0<<4)+(1<<3)+(0<<2)+(1<<0);rIISPSR=(2<<5)+2;//Prescaler_A/B=2<-FCLK135.4752MHz(1:2:4),11.2896MHz(256fs),44.1KHzrIISCON=(0<<5)+(1<<4)+(1<<3)+(0<<2)+(1<<1);//TxDMAdisable,RxDMAenable,Tx
idle,Rxnotidle,prescaler
enable,stoprIISFCON=(1<<14)+(1<<12);//RxDMA,RxFIFO-->startpiling....開始錄音://RxstartrIISCON|=0x1;錄音完畢將引發(fā)DMA2中斷,如下代碼等待錄音結(jié)束:while(!Rec_Done);rINTMSK=BIT_DMA2;Rec_Done=0;//IISStopDelay(10);//ForendofH/WRxrIISCON=0x0;//IISstoprDMASKTRIG2=(1<<2);//DMA2stoprIISFCON=0x0;//ForFIFOflush錄音完畢,然後播放聲音:Uart_Printf("EndofRecord!!!\n");Uart_Printf("Pressanykeytoplayrecordeddata\n");Uart_Printf("Ifyouwanttomuteornomutepushthe'EIN0'keyrepeatedly\n");Uart_Getch();size=REC_LEN*2;Uart_Printf("Size=%d\n",size);Init1341(PLAY);pISR_DMA2=(unsigned)DMA2_Done;rINTMSK=~(BIT_DMA2|BIT_EINT0);//DMA2InitializerDISRCC2=(0<<1)+(0<<0);//AHB,IncrementrDISRC2=(int)rec_buf;//0x31000000rDIDSTC2=(1<<1)+(1<<0);//APB,FixedrDIDST2=((U32)IISFIFO);//IISFIFOrDCON2=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(0<<24)+(1<<23)+(0<<22)+(1<<20)+(size/2);//Handshake,syncPCLK,TCint,singletx,singleservice,I2SSDO,I2Srequest,//Auto-reload,half-word,size/2rDMASKTRIG2=(0<<2)+(1<<1)+0;//No-stop,DMA2channelon,No-swtrigger//IISInitialize//Master,Tx,L-ch=low,iis,16bitch.,CDCLK=256fs,IISCLK=32fsrIISMOD=(0<<8)+(2<<6)+(0<<5)+(0<<4)+(1<<3)+(0<<2)+(1<<0);//rIISPSR=(4<<5)+4;//Prescaler_A/B=4for11.2896MHzrIISCON=(1<<5)+(0<<4)+(0<<3)+(1<<2)+(1<<1);//TxDMAenable,TxDMAdisable,Txnotidle,Rx
idle,prescaler
enable,stoprIISFCON=(1<<15)+(1<<13);//Tx
DMA,TxFIFO-->startpiling....Uart_Printf("Pressanykeytoexit!!!\n");rIISCON|=0x1;//IISTxStartwhile(!Uart_GetKey());//IISTxStopDelay(10);//ForendofH/WTxrIISCON=0x0;//IISstoprDMASKTRIG2=(1<<2);//DMA2stoprIISFCON=0x0;//ForFIFOflushsize=0;rGPBCON=save_B;rGPECON=save_E;rGPBUP=save_PB;rGPEUP=save_PE;rINTMSK=(BIT_DMA2|BIT_EINT0);ChangeMPllValue(0xa1,0x3,0x1);//FCLK=202.8MHzUart_Init(0,115200);mute=1;}8.3音頻設(shè)備程式的實現(xiàn)在Linux下,音頻設(shè)備程式的實現(xiàn)與檔系統(tǒng)的操作密切相關(guān)。Linux將各種設(shè)備以檔的形式給出統(tǒng)一的介面,這樣的設(shè)計使得對設(shè)備的編程與對檔的操作基本相同,對Linux內(nèi)核的系統(tǒng)調(diào)用也基本一致,從而簡化了設(shè)備編程。如何對各種音頻設(shè)備進行操作是在Linux上進行音頻編程的關(guān)鍵,通過內(nèi)核提供的一組系統(tǒng)調(diào)用,應(yīng)用程式能夠訪問聲卡驅(qū)動程式提供的各種音頻設(shè)備介面,這是在Linux下進行音頻編程最簡單也是最直接的方法。聲卡不是Linux控制臺的一部分,它是一個特殊的設(shè)備。聲卡主要提供3個重要的特徵:
數(shù)字取樣輸入/輸出;
頻率調(diào)製輸出;
MIDI介面。這3個特徵都有它們自己的設(shè)備驅(qū)動程式介面,數(shù)字取樣的介面是/dev/dsp,頻率調(diào)製的介面/dev/sequencer,而MIDI介面是/dev/midi。混音設(shè)備(如音量、平衡或者貝斯)可以通過/dev/mixer介面來控制。為了滿足相容性的需要,還提供了一個/dev/audio設(shè)備,該設(shè)備可用於讀SUN_law的聲音數(shù)據(jù),但它是映射到數(shù)字取樣設(shè)備的。音頻編程介面程式員可以使用ioctl()來操作這些設(shè)備,ioctl()請求是在linux/soundcard.h中定義的,它們以SNDCTL_開頭。首先使用open系統(tǒng)調(diào)用建立起與硬體間的聯(lián)繫,此時返回的檔描述符將作為隨後操作的標(biāo)識;接著使用read系統(tǒng)調(diào)用從設(shè)備接收數(shù)據(jù),或者使用write系統(tǒng)調(diào)用向設(shè)備寫入數(shù)據(jù),而其他所有不符合讀/寫這一基本模式的操作都可以由ioctl系統(tǒng)調(diào)用來完成;最後,使用close系統(tǒng)調(diào)用告訴Linux內(nèi)核不會再對該設(shè)備做進一步的處理。1.open系統(tǒng)調(diào)用系統(tǒng)調(diào)用open可以獲得對聲卡的訪問權(quán),同時還能為隨後的系統(tǒng)調(diào)用做好準(zhǔn)備,其函數(shù)原型如下所示:int
open(constchar*pathname,intflags,intmode);參數(shù)pathname是將要被打開的設(shè)備檔的名稱,對於聲卡來講一般是/dev/dsp。參數(shù)flags用來指明應(yīng)該以什麼方式打開設(shè)備檔,它可以是O_RDONLY、O_WRONLY或者O_RDWR,分別表示以只讀、只寫或者讀寫的方式打開設(shè)備檔;參數(shù)mode通常是可選的,它只有在指定的設(shè)備檔不存在時才會用到,指明新創(chuàng)建的檔應(yīng)該具有怎樣的許可權(quán)。如果open系統(tǒng)調(diào)用能夠成功完成,它將返回一個正整數(shù)作為檔標(biāo)誌符,在隨後的系統(tǒng)調(diào)用中需要用到該標(biāo)誌符。如果open系統(tǒng)調(diào)用失敗,它將返回
1,同時還會設(shè)置全局變數(shù)errno,指明是什麼原因?qū)е铝隋e誤的發(fā)生。2.read系統(tǒng)調(diào)用read用來從聲卡讀取數(shù)據(jù):int
read(int
fd,char*buf,size_tcount);參數(shù)fd是設(shè)備檔的標(biāo)誌符,它是通過之前的open系統(tǒng)調(diào)用獲得的;參數(shù)buf是指向緩衝區(qū)的字元指針,它用來保存從聲卡獲得的數(shù)據(jù);參數(shù)count則用來限定從聲卡獲得的最大字節(jié)數(shù)。如果read系統(tǒng)調(diào)用成功完成,它將返回從聲卡實際讀取的位元組數(shù),通常情況會比count的值小一些;如果read系統(tǒng)調(diào)用失敗,它將返回
1,同時還會設(shè)置全局變數(shù)errno,來指明是什麼原因?qū)е铝隋e誤的發(fā)生。3.write系統(tǒng)調(diào)用write用來向聲卡寫入數(shù)據(jù),其函數(shù)原型如下所示:size_t
write(int
fd,constchar*buf,size_tcount);系統(tǒng)調(diào)用write和系統(tǒng)調(diào)用read在很大程度是類似的,差別只在於write是向聲卡寫入數(shù)據(jù),而read則是從聲卡讀入數(shù)據(jù)。參數(shù)fd同樣是設(shè)備檔的標(biāo)誌符,它也是通過之前的open系統(tǒng)調(diào)用獲得的;參數(shù)buf是指向緩衝區(qū)的字元指針,它保存著即將向聲卡寫入的數(shù)據(jù);參數(shù)count則用來限定向聲卡寫入的最大字節(jié)數(shù)。如果write系統(tǒng)調(diào)用成功完成,它將返回向聲卡實際寫入的位元組數(shù);如果write系統(tǒng)調(diào)用失敗,它將返回
1,同時還會設(shè)置全局變數(shù)errno,來指明是什麼原因?qū)е铝隋e誤的發(fā)生。無論是read還是write,一旦調(diào)用之後,Linux內(nèi)核就會阻塞當(dāng)前應(yīng)用程式,直到數(shù)據(jù)成功地從聲卡讀出或者寫入為止。4.ioctl系統(tǒng)調(diào)用系統(tǒng)調(diào)用ioctl可以對聲卡進行控制,凡是對設(shè)備檔的操作不符合讀/寫基本模式的,都是通過ioctl來完成的,它可以影響設(shè)備的行為,或者返回設(shè)備的狀態(tài),其函數(shù)原型如下所示:int
ioctl(int
fd,intrequest,...);參數(shù)fd是設(shè)備檔的標(biāo)誌符,它是在設(shè)備打開時獲得的;如果設(shè)備比較複雜,那麼對它的控制請求相應(yīng)地也會有很多種,參數(shù)request的目的就是用來區(qū)分不同的控制請求;通常說來,在對設(shè)備進行控制時還需要有其他參數(shù),這要根據(jù)不同的控制請求才能確定,並且可能是與硬體設(shè)備直接相關(guān)的。5.close系統(tǒng)調(diào)用當(dāng)應(yīng)用程式使用完聲卡之後,需要用close系統(tǒng)調(diào)用將其關(guān)閉,以便及時釋放佔用的硬體資源,其函數(shù)原型如下所示:int
close(int
fd);參數(shù)fd是設(shè)備檔的標(biāo)誌符,它是在設(shè)備打開時獲得的。一旦應(yīng)用程式調(diào)用了close系統(tǒng)調(diào)用,Linux內(nèi)核就會釋放與之相關(guān)的各種資源,因此建議在不需要的時候儘量及時關(guān)閉已經(jīng)打開的設(shè)備。音頻設(shè)備檔
/dev/sndstat設(shè)備檔/dev/sndstat是聲卡驅(qū)動程式提供的最簡單的介面,通常它是一個只讀檔,作用也僅僅只限於彙報聲卡的當(dāng)前狀態(tài)。一般說來,/dev/sndstat是提供給最終用戶來檢測聲卡的,不宜用於程式當(dāng)中,因為所有的資訊都可以通過ioctl系統(tǒng)調(diào)用來獲得。
/dev/dsp聲卡驅(qū)動程式提供的/dev/dsp是用於數(shù)字採樣和數(shù)字錄音的設(shè)備檔,它對於Linux下的音頻編程來講非常重要。向該設(shè)備寫數(shù)據(jù)即意味著啟動聲卡上的D/A轉(zhuǎn)換器進行放音,而從該設(shè)備讀數(shù)據(jù)則意味著啟動聲卡上的A/D轉(zhuǎn)換器進行錄音。目前,許多聲卡都提供有多個數(shù)字採樣設(shè)備,它們在Linux下可以通過/dev/dsp等設(shè)備檔進行訪問。
/dev/audio/dev/audio類似於/dev/dsp,它相容於Sun工作站上的音頻設(shè)備,使用的是mu-law編碼方式。由於設(shè)備檔/dev/audio主要出於對相容性的考慮,所以在新開發(fā)的應(yīng)用程式中最好不要嘗試用它,而應(yīng)該以/dev/dsp進行替代。對於應(yīng)用程式來說,同一時刻只能使用/dev/audio或者/dev/dsp其中之一,因為它們是相同硬體的不同軟體介面。
/dev/mixer在聲卡的硬體電路中,混音器(mixer)是一個很重要的組成部分,它的作用是將多個信號組合或者疊加在一起,對於不同的聲卡來說,其混音器的作用可能各不相同。運行在Linux內(nèi)核中的聲卡驅(qū)動程式一般都會提供/dev/mixer這一設(shè)備檔,它是應(yīng)用程式對混音器進行操作的軟體介面。
/dev/sequencer目前大多數(shù)聲卡驅(qū)動程式還會提供/dev/sequencer設(shè)備檔,用來對聲卡內(nèi)建的波表合成器進行操作,或者對MIDI匯流排上的樂器進行控制,通常只用於電腦音樂軟體中。音頻設(shè)備編程設(shè)計1.DSP編程DSP是數(shù)字信號處理器(DigitalSignalProcessor)的簡稱,它用來進行數(shù)字信號處理的特殊晶片,聲卡使用它來實現(xiàn)模擬信號和數(shù)字信號的轉(zhuǎn)換。聲卡中的DSP設(shè)備實際上包含兩個組成部分:在以只讀方式打開時,能夠使用A/D轉(zhuǎn)換器進行聲音的輸入;而在以只寫方式打開時,則能夠使用D/A轉(zhuǎn)換器進行聲音的輸出。嚴(yán)格說來,Linux下的應(yīng)用程式要麼以只讀方式打開/dev/dsp輸入聲音,要麼以只寫方式打開/dev/dsp輸出聲音,但事實上,某些聲卡驅(qū)動程式仍允許以讀寫的方式打開/dev/dsp,以便同時進行聲音的輸入和輸出。在從DSP設(shè)備讀取數(shù)據(jù)時,從聲卡輸入的模擬信號經(jīng)過A/D轉(zhuǎn)換器變成數(shù)字採樣後的樣本,保存在聲卡驅(qū)動程式的內(nèi)核緩衝區(qū)中,當(dāng)應(yīng)用程式通過read系統(tǒng)調(diào)用從聲卡讀取數(shù)據(jù)時,保存在內(nèi)核緩衝區(qū)中的數(shù)字採樣結(jié)果將被複製到應(yīng)用程式所指定的用戶緩衝區(qū)中。需要指出的是,聲卡採樣頻率是由內(nèi)核中的驅(qū)動程式所決定的,而不取決於應(yīng)用程式從聲卡讀取數(shù)據(jù)的速度。如果應(yīng)用程式讀取數(shù)據(jù)的速度過慢,以致低於聲卡的採樣頻率,那麼多餘的數(shù)據(jù)將會被丟棄;如果讀取數(shù)據(jù)的速度過快,以致高於聲卡的採樣頻率,那麼聲卡驅(qū)動程式將會阻塞那些請求數(shù)據(jù)的應(yīng)用程式,直到新的數(shù)據(jù)到來為止。在向DSP設(shè)備寫入數(shù)據(jù)時,數(shù)字信號會經(jīng)過D/A轉(zhuǎn)換器變成模擬信號,然後產(chǎn)生出聲音。應(yīng)用程式寫入數(shù)據(jù)的速度同樣應(yīng)該與聲卡的採樣頻率相匹配,過慢的話會產(chǎn)生聲音暫停或者停頓的現(xiàn)象,而過快的話又會被內(nèi)核中的聲卡驅(qū)動程式阻塞,直到硬體有能力處理新的數(shù)據(jù)為止。無論是從聲卡讀取數(shù)據(jù),或是向聲卡寫入數(shù)據(jù),事實上都具有特定的格式,默認(rèn)為8位無符號數(shù)據(jù)、單聲道、8kHz採樣率,如果默認(rèn)值無法達(dá)到要求,可以通過ioctl系統(tǒng)調(diào)用來改變它們。通常情況下,在應(yīng)用程式中打開設(shè)備檔/dev/dsp之後,接著就應(yīng)該為其設(shè)置恰當(dāng)?shù)母袷?,然後才能從聲卡讀取或者寫入數(shù)據(jù)。對聲卡進行編程時,首先要做的是打開與之對應(yīng)的硬體設(shè)備,這是借助於open系統(tǒng)調(diào)用來完成的,並且一般情況下使用的是/dev/dsp檔。採用何種模式對聲卡進行操作也必須在打開設(shè)備時指定,對於不支持全雙工的聲卡來說,應(yīng)該使用只讀或者只寫的方式打開,只有那些支持全雙工的聲卡,才能以讀寫的方式打開,並且還要依賴於驅(qū)動程式的具體實現(xiàn)。Linux允許應(yīng)用程式多次打開或者關(guān)閉與聲卡對應(yīng)的設(shè)備檔,從而能夠很方便地在放音狀態(tài)和錄音狀態(tài)之間進行切換,建議在進行音頻編程時只要有可能就儘量使用只讀或者只寫的方式打開設(shè)備檔,因為這樣不僅能夠充分利用聲卡的硬體資源,而且還有利於驅(qū)動程式的優(yōu)化。下麵的代碼示範(fàn)了如何以只寫方式打開聲卡進行放音操作:inthandle=open("/dev/dsp",O_WRONLY);if(handle==-1){perror("open/dev/dsp");return-1;}運行在Linux內(nèi)核中的聲卡驅(qū)動程式專門維護了一個緩衝區(qū),其大小會影響到放音和錄音時的效果,使用ioctl系統(tǒng)調(diào)用可以對它的尺寸進行恰當(dāng)?shù)脑O(shè)置。調(diào)節(jié)驅(qū)動程式中緩衝區(qū)大小的操作不是必需的,如果沒有特殊的要求,一般採用默認(rèn)的緩衝區(qū)大小就可以了。但需要注意的是,緩衝區(qū)大小的設(shè)置通常應(yīng)緊跟在設(shè)備檔打開之後,這是因為對聲卡的其他操作有可能會導(dǎo)致驅(qū)動程式無法再修改其緩衝區(qū)的大小。下麵的代碼示範(fàn)了怎樣設(shè)置聲卡驅(qū)動程式中的內(nèi)核緩衝區(qū)的大小:intsetting=0xnnnnssss;intresult=ioctl(handle,SNDCTL_DSP_SETFRAGMENT,&setting);if(result==-1){
perror("ioctlbuffersize"); return-1;}在設(shè)置緩衝區(qū)大小時,參數(shù)setting實際上由兩部分組成,其低16位標(biāo)明緩衝區(qū)的尺寸,相應(yīng)的計算公式為buffer_size=2^ssss,即若參數(shù)setting低16位的值為16,那麼相應(yīng)的緩衝區(qū)的大小會被設(shè)置為65536位元組。參數(shù)setting的高16位則用來標(biāo)明分片(fragment)的最大序號,它的取值範(fàn)圍從2到0x7FFF,其中0x7FFF表示沒有任何限制。接下來要做的是設(shè)置聲卡工作時的聲道數(shù)目,根據(jù)硬體設(shè)備和驅(qū)動程式的具體情況,可以將其設(shè)置為0(單聲道,mono)或者1(身歷聲,stereo)。下麵的代碼示範(fàn)了應(yīng)該怎樣設(shè)置聲道數(shù)目。intchannels=0;//0=mono1=stereointresult=ioctl(handle,SNDCTL_DSP_STEREO,&channels);if(result==-1){
perror("ioctlchannelnumber"); return-1;}if(channels!=0){ //只支持身歷聲}採樣格式和採樣頻率是在進行音頻編程時需要考慮的另一個問題,聲卡支持的所有採樣格式可以在頭檔soundcard.h中找到,而通過ioctl系統(tǒng)調(diào)用則可以很方便地更改當(dāng)前所使用的採樣格式。下麵的代碼示範(fàn)了如何設(shè)置聲卡的採樣格式。intformat=AFMT_U8;intresult=ioctl(handle,SNDCTL_DSP_SETFMT,&format);if(result==-1){
perror("ioctlsampleformat"); return-1;}聲卡採樣頻率的設(shè)置也非常容易,只需在調(diào)用ioctl時將第二個參數(shù)的值設(shè)置為SNDCTL_DSP_SPEED,同時在第三個參數(shù)中指定採樣頻率的數(shù)值就行了。對於大多數(shù)聲卡來說,其支持的採樣頻率範(fàn)圍一般為5kHz到44.1kHz或者48kHz,但並不意味著該範(fàn)圍內(nèi)的所有頻率都會被硬體支持,在Linux下進行音頻編程時最常用到的幾種採樣頻率是11025Hz、16000Hz、22050Hz、32000Hz和44100Hz。下麵的代碼示範(fàn)了如何設(shè)置聲卡的採樣頻率。intrate=22050;intresult=ioctl(handle,SNDCTL_DSP_SPEED,&rate);if(result==-1){
perror("ioctlsampleformat"); return-1;}利用聲卡上的DSP設(shè)備進行聲音錄製和回放的完整程式,它的功能是先錄製幾秒鐘音頻數(shù)據(jù),將其存放在記憶體緩衝區(qū)中,然後再進行回放,其所有的功能都是通過讀寫/dev/dsp設(shè)備檔來完成的。/**sound.c*/#include<unistd.h>#include<fcntl.h>#include<sys/types.h>#include<sys/ioctl.h>#include<stdlib.h>#include<stdio.h>#include<linux/soundcard.h>#defineLENGTH3/*存儲秒數(shù)*/#defineRATE8000/*採樣頻率*/#defineSIZE8/*量化位數(shù)*/#defineCHANNELS1/*聲道數(shù)目*//*用於保存數(shù)字音頻數(shù)據(jù)的記憶體緩衝區(qū)*/unsignedcharbuf[LENGTH*RATE*SIZE*CHANNELS/8];intmain(){
int
fd; /*聲音設(shè)備的檔描述符*/
int
arg; /*用於ioctl調(diào)用的參數(shù)*/
intstatus;/*系統(tǒng)調(diào)用的返回值*//*打開聲音設(shè)備*/
fd=open("/dev/dsp",O_RDWR);if(fd<0){
perror("openof/dev/dspfailed");exit(1);}/*設(shè)置採樣時的量化位數(shù)*/
arg=SIZE;status=ioctl(fd,SOUND_PCM_WRITE_BITS,&arg);if(status==-1)
perror("SOUND_PCM_WRITE_BITS
ioctlfailed");if(arg!=SIZE)
perror("unabletosetsamplesize");
/*設(shè)置採樣時的聲道數(shù)目*/
arg=CHANNELS;status=ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&arg);if(status==-1)
perror("SOUND_PCM_WRITE_CHANNELS
ioctlfailed");if(arg!=CHANNELS)
perror("unabletosetnumberofchannels");/*設(shè)置採樣時的採樣頻率*/
arg=RATE;status=ioctl(fd,SOUND_PCM_WRITE_RATE,&arg);if(status==-1)
perror("SOUND_PCM_WRITE_WRITE
ioctlfailed");/*迴圈,直到按下Control-C*/while(1){
printf("Saysomething:\n");status=read(fd,buf,sizeof(buf));/*錄音*/if(status!=sizeof(buf))
perror("readwrongnumberofbytes");
printf("Yousaid:\n");status=write(fd,buf,sizeof(buf));/*回放*/if(status!=sizeof(buf))
perror("wrotewrongnumberofbytes");/*在繼續(xù)錄音前等待回放結(jié)束*/status=ioctl(fd,SOUND_PCM_SYNC,0);if(status==-1)
perror("SOUND_PCM_SYNC
ioctlfailed");}}2.Mixer編程混音器電路通常由兩個部分組成:輸入混音器和輸出混音器。輸入混音器負(fù)責(zé)從多個不同的信號源接收模擬信號,這些信號源有時也被稱為混音通道或者混音設(shè)備。模擬信號通過增益控制器和由軟體控制的音量調(diào)節(jié)器後,在不同的混音通道中分別進行調(diào)製,然後被送到輸入混音器中進行聲音的合成?;煲羝魃系碾娮娱_關(guān)可以控制不同通道中的信號與混音器相連,有些聲卡只允許連接一個混音通道作為錄音的音源,而有些聲卡則允許對混音通道做任意的連接。經(jīng)過輸入混音器處理後的信號仍然為模擬信號,它們將被送到A/D轉(zhuǎn)換器進行數(shù)位化處理。輸出混音器的工作原理與輸入混音器類似,同樣也有多個信號源與混音器相連,並且事先都經(jīng)過了增益調(diào)節(jié)。當(dāng)輸出混音器對所有的模擬信號進行混合之後,通常還會有一個總控增益調(diào)節(jié)器來控制輸出聲音的大小,此外,還有一些音調(diào)控制器來調(diào)節(jié)輸出聲音的音調(diào)。經(jīng)過輸出混音器處理後的信號也是模擬信號,它們最終會被送給喇叭或者其他的模擬輸出設(shè)備。對混音器的編程包括如何設(shè)置增益控制器的增益,以及怎樣在不同的音源間進行切換,這些操作通常是不連續(xù)的,而且不會像錄音或者放音那樣需要佔用大量的電腦資源。由於混音器的操作不符合典型的讀/寫操作模式,因此除了open和close兩個系統(tǒng)調(diào)用之外,大部分的操作都是通過ioctl系統(tǒng)調(diào)用來完成的。與/dev/dsp不同,/dev/mixer允許多個應(yīng)用程式同時訪問,並且混音器的設(shè)置值會一直保持到對應(yīng)的設(shè)備檔被關(guān)閉為止。為了簡化應(yīng)用程式的設(shè)計,Linux上的聲卡驅(qū)動程式大多都支持將混音器的ioctl操作直接應(yīng)用到聲音設(shè)備上,也就是說,如果已經(jīng)打開了/dev/dsp,那麼就不用再打開/dev/mixer來對混音器進行操作,而是可以直接用打開/dev/dsp時得到的檔標(biāo)誌符來設(shè)置混音器。聲卡上的混音器由多個混音通道組成,它們可以通過驅(qū)動程式提供的設(shè)備檔/dev/mixer進行編程。對混音器的操作是通過ioctl系統(tǒng)調(diào)用來完成的,並且所有控制命令都由SOUND_MIXER或者MIXER開頭,表8.3列出了常用的幾個混音器控制命令。對聲卡的輸入增益和輸出增益進行調(diào)節(jié)是混音器的一個主要作用,目前大部分聲卡採用的是8位或者16位的增益控制器,但作為程式員來講並不需要關(guān)心這些,因為聲卡驅(qū)動程式會負(fù)責(zé)將它們變換成百分比的形式,也就是說,無論是輸入增益還是輸出增益,其取值範(fàn)圍都是從0到100。在進行混音器編程時,可以使用SOUND_MIXER_READ宏來讀取混音通道的增益大小,例如,在獲取麥克風(fēng)的輸入增益時,可以使用如下的代碼:int
vol;ioctl(fd,SOUND_MIXER_READ(SOUND_MIXER_MIC),&vol);printf("Micgainisat%d%%\n",vol);對於只有一個混音通道的單聲道設(shè)備來說,返回的增益大小保存在低位位元組中。而對於支持多個混音通道的雙聲道設(shè)備來說,返回的增益大小實際上包括兩個部分,分別代表左、右兩個聲道的值,其中低位位元組保存左聲道的音量,而高位位元組則保存右聲道的音量。下麵的代碼可以從返回值中依次提取左右聲道的增益大小。intleft,right;left=vol&0xff;right=(vol&0xff00)>>8;printf("Leftgainis%d%%,Rightgainis%d%%\n",left,right);類似地,如果想設(shè)置混音通道的增益大小,則可以通過SOUND_MIXER_WRITE宏來實現(xiàn),此時遵循的原則與獲取增益值時的原則基本相同,例如,下麵的語句可以用來設(shè)置麥克風(fēng)的輸入增益。vol=(right<<8)+left;ioctl(fd,SOUND_MIXER_WRITE(SOUND_MIXER_MIC),&vol);在編寫實用的音頻程式時,混音器是在涉及相容性時需要重點考慮的一個對象,這是因為不同的聲卡所提供的混音器資源是有所區(qū)別的。聲卡驅(qū)動程式提供了多個ioctl系統(tǒng)調(diào)用來獲得混音器的資訊,它們通常返回一個整型的位掩碼(bitmask),其中每一位分別代表一個特定的混音通道,如果相應(yīng)的位為1,則說明與之對應(yīng)的混音通道是可用的。例如,通過SOUND_MIXER_READ_DEVMASK返回的位掩碼,可以查詢出能夠被聲卡支持的每一個混音通道,而通過SOUND_MIXER_READ_RECMAS返回的位掩碼,則可以查詢出能夠被當(dāng)做錄音源的每一個通道。下麵的代碼可以用來檢查CD輸入是否是一個有效的混音通道。ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);if(devmask&SOUND_MIXER_CD)printf("TheCDinputissupported");如果進一步還想知道其是不是一個有效的錄音源,則可以使用如下語句:ioctl(fd,SOUND_MIXER_READ_RECMASK,&recmask);if(recmask&SOUND_MIXER_CD)printf("TheCDinputcanbearecordingsource");目前,大多數(shù)聲卡提供多個錄音源,通過SOUND_MIXER_READ_RECSRC可以查詢出當(dāng)前正在使用的錄音源,同一時刻能夠使用幾個錄音源是由聲卡硬體決定的。類似地,使用SOUND_MIXER_WRITE_RECSRC可以設(shè)置聲卡當(dāng)前使用的錄音源,例如,下麵的代碼可以將CD輸入作為聲卡的錄音源使用。devmask=SOUND_MIXER_CD;ioctl(fd,SOUND_MIXER_WRITE_RECSRC,&devmask);此外,所有的混音通道都有單聲道和雙聲道的區(qū)別,如果需要知道哪些混音通道提供了對立體聲的支持,可以通過SOUND_MIXER_READ_STEREODEVS來獲得。一個簡單的混音器控制程式,利用它可以對各種混音通道的增益進行調(diào)節(jié),其所有的功能都是通過讀寫/dev/mixer設(shè)備檔來完成的。#include<unistd.h>#include<stdlib.h>#include<stdio.h>#include<sys/ioctl.h>#include<fcntl.h>#include<linux/soundcard.h>/*用來存儲所有可用混音設(shè)備的名稱*/constchar*sound_device_names[]=SOUND_DEVICE_NAMES;int
fd;/*混音設(shè)備所對應(yīng)的檔描述符*/int
devmask,stereodevs;/*混音器資訊對應(yīng)的位圖掩碼*/char*name;/*顯示命令的使用方法及所有可用的混音設(shè)備*/voidusage(){
inti;
fprintf(stderr,"usage:%s<device><left-gain%%><right-gain%%>\n" "%s<device><gain%%>\n\n" "Where<device>isoneof:\n",name,name);for(i=0;i<SOUND_MIXER_NRDEVICES;i++)if((1<<i)&devmask)/*只顯示有效的混音設(shè)備*/
fprintf(stderr,"%s",sound_device_names[i]);
fprintf(stderr,"\n");exit(1);}int
main(int
argc,char*argv[]){
intleft,right,level;/*增益設(shè)置*/
intstatus;/*系統(tǒng)調(diào)用的返回值*/
intdevice;/*選用的混音設(shè)備*/char*dev;/*混音設(shè)備的名稱*/
inti;name=argv[0];/*以只讀方式打開混音設(shè)備*/
fd=open("/dev/mixer",O_RDONLY);if(fd==-1){
perror("unabletoopen/dev/mixer");exit(1);}/*獲得所需要的資訊*/status=ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);if(status==-1)perror("SOUND_MIXER_READ_DEVMASK
ioctlfailed");status=ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs);if(status==-1)perror("SOUND_MIXER_READ_STEREODEVS
ioctlfailed");/*檢查用戶輸入*/if(argc!=3&&argc!=4)usage(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度廚師臨時用工合同范本(勞動權(quán)益保障)4篇
- 二零二四年度新能源汽車租賃合同范本3篇
- 二零二五版農(nóng)夫山泉礦泉水與健身教練合作銷售合同4篇
- 二零二四年度液化天然氣進口與分銷合同3篇
- 南匯農(nóng)業(yè)志2025版修訂與版權(quán)合同4篇
- 二零二四年國際貿(mào)易仲裁服務(wù)合同3篇
- 2025年度電商虛擬現(xiàn)實購物體驗合作協(xié)議26篇
- 二零二五年度面包磚生產(chǎn)質(zhì)量控制與認(rèn)證服務(wù)合同3篇
- 二零二五年度新能源汽車展示中心場地租賃合同4篇
- 二零二五年苗木種植基地合作銷售合同樣本3篇
- 干部職級晉升積分制管理辦法
- TSG ZF003-2011《爆破片裝置安全技術(shù)監(jiān)察規(guī)程》
- 護理服務(wù)在產(chǎn)科中的應(yīng)用課件
- 2024年代理記賬工作總結(jié)6篇
- 電氣工程預(yù)算實例:清單與計價樣本
- VOC廢氣治理工程中電化學(xué)氧化技術(shù)的研究與應(yīng)用
- 煤礦機電設(shè)備培訓(xùn)課件
- 科技論文圖表等規(guī)范表達(dá)
- 高考寫作指導(dǎo)議論文標(biāo)準(zhǔn)語段寫作課件32張
- 2021年普通高等學(xué)校招生全國英語統(tǒng)一考試模擬演練八省聯(lián)考解析
- 紅色研學(xué)旅行課程的設(shè)計與實踐
評論
0/150
提交評論