您好,歡迎進(jìn)入深圳市穎特新科技有限公司官方網(wǎng)站!
錄音例程涉及了錄音和播放兩大塊內(nèi)容,上篇筆記說(shuō)了播放,這篇就來(lái)說(shuō)說(shuō)錄音這塊,也就是音頻編碼這部分功能。
上篇筆記中的這段話太裝逼了,我決定再?gòu)?fù)制下,嘿嘿。
“我的錘子便簽中有上個(gè)月記下的一句話,“斯蒂芬·平克說(shuō),寫作之難,在于把網(wǎng)狀思考,用樹(shù)狀結(jié)構(gòu),體現(xiàn)在線性展開(kāi)的語(yǔ)句里。”這篇代碼解析也有類似的困難,代碼的網(wǎng)狀結(jié)構(gòu),如何用文章這種線性載體來(lái)體現(xiàn)。”
跟上篇筆記的做法一樣,還是挑出了主干,來(lái)講下自己的理解。另外在文章最后添加了一個(gè)模塊拓?fù)鋱D來(lái)幫助消化。
本文作者twowinter,轉(zhuǎn)載請(qǐng)注明:http://blog.csdn.net/iotisan/
查看代碼主邏輯,主要是App_StartRec和App_ProcessRec這兩個(gè)函數(shù)。下面就分別進(jìn)行分析。
App_StartRec是由按鍵觸發(fā)的,也就是按鍵按下去就開(kāi)始錄音。
BOOL App_StartRec(void) { S_AUDIOCHUNK_HEADER sAudioChunkHeader; // 這回就不是Decode了,改用Encode。 // Initiate NuLiteEx audio encode lib with temp buffer provided for lib. NuLiteExApp_EncodeInitiate(&g_sApp.sNuLiteExAppEncode, (UINT8 *)&g_sApp.uTempBuf); // Start to encode NuLiteEx data with sample rate, bit per frame and saved data information into audio chunk header. if (NuLiteExApp_EncodeStart(&g_sApp.sNuLiteExAppEncode, &sAudioChunkHeader, ADC_SAMPLE_RATE, E_NULITEEX_ENCODE_BPS_10) == FALSE) return FALSE; // SPIFlash utility function provide encode data write into SPIFlash. // detail info please refer "SPIFlashUtil.h" SPIFlahUtil_StartWriteEncodeData(&sAudioChunkHeader, AUDIOROM_STORAGE_START_ADDR, NULL); // Light record led for display status. OUT5(0); // Start to record PCM data into buffer for produc NuLiteEx encode data. Record_StartRec(); return TRUE; }
可以看到App_StartRec主要牽扯了NuLiteExApp_EncodeStart和Record兩部分子函數(shù)。
NuLiteExApp_EncodeStart(&g_sApp.sNuLiteExAppEncode, &sAudioChunkHeader, ADC_SAMPLE_RATE, E_NULITEEX_ENCODE_BPS_10);照例對(duì)代碼做了中文注解方便消化。
g_sApp.sNuLiteExAppEncode是全局變量,涉及編碼庫(kù)的操作。sAudioChunkHeader是一個(gè)臨時(shí)變量,用來(lái)做音頻塊頭部信息。
BOOL NuLiteExApp_EncodeStart( S_NULITEEX_APP_ENCODE *psNuLiteExAppEncode, S_AUDIOCHUNK_HEADER *psAudioChunkHeader, UINT16 u16SampleRate, enum eNuLiteExEncodeBPS eBitPerSample) { if ( (eBitPerSample > NULITEEXAPP_ENCODE_MAX_BITRATE) || (u16SampleRate == 0) ) return FALSE; else { psAudioChunkHeader->u16SmplRate = u16SampleRate; psAudioChunkHeader->u32BitPerFrame = eBitPerSample; } // 將全局變量申請(qǐng)的內(nèi)存?zhèn)魅虢o編碼庫(kù),方便其工作執(zhí)行。將音頻塊頭部傳入,編碼庫(kù)最后的輸出結(jié)果會(huì)體現(xiàn)在這里。另外的采樣率信息是輸入變量,輔助生成最后的音頻塊。 // NuLiteEx encoder initiates work buffer. // Set bit rate and sample rate information for audio chunk header. NuLiteEx_EncodeInitiate((UINT8 *)psNuLiteExAppEncode->au32WorkBuf, psNuLiteExAppEncode->pau8TempBuf, psAudioChunkHeader, (enum eNuLiteExEncodeBPS)psAudioChunkHeader->u32BitPerFrame, psAudioChunkHeader->u16SmplRate); // Reset encode buffer read index and write index psNuLiteExAppEncode->sEncodeBufCtrl.u16BufWriteIdx = 0; psNuLiteExAppEncode->sEncodeBufCtrl.u16BufReadIdx = 0; // Set Encoded frame size, Storage Utility will refer to this size to write data. psNuLiteExAppEncode->sEncodeBufCtrl.u16FrameSize = (psAudioChunkHeader->u32BitPerFrame)>>3; psNuLiteExAppEncode->sEncodeBufCtrl.u16BufCount = (psNuLiteExAppEncode->sEncodeBufCtrl.u16FrameSize)*NULITEEXAPP_ENCODE_BUF_COUNT; // 這一步很關(guān)鍵,設(shè)置錄音模塊部分的緩存。 // Set input buffer size, PCM buffer pointer, frame size and sample rate. Record_SetInBufRecord( &psNuLiteExAppEncode->sInBufCtrl, NULITEEXAPP_IN_BUF_SIZE, psNuLiteExAppEncode->i16InBuf, NULITEEX_ENCODE_SAMPLE_PER_FRAME, psAudioChunkHeader->u16SmplRate); // 都要做這一步操作,錄音模塊的操作順序就是這樣:SetInBufRecord ->Add -> StartRec。 // Set application input buffer to record(ADC) output buffer. Record_Add(&psNuLiteExAppEncode->sInBufCtrl, psAudioChunkHeader->u16SmplRate); return TRUE; }
上面說(shuō)錄音模塊的操作順序就是這樣:SetInBufRecord ->Add -> StartRec。這就來(lái)了。
硬件PDMA這里頭涉及一個(gè)關(guān)鍵函數(shù),PDMA會(huì)把ADC數(shù)據(jù)直接放到s_pi16AdcBuf里頭。
void Record_StartRec(void) { g_u8AppCtrl |= APPCTRL_RECORD; #if (ADC_FILTER_ENABLE == 1) NoiseFilter_ResetIIR2(); s_pi16AdcBuf = g_ai16ADCSamples; #else // 主要是緩沖區(qū)的處理 if ( BUF_CTRL_ISNOT_CALLBACK(g_psAdcBufCtrl)) s_pi16AdcBuf = &g_psAdcBufCtrl->pi16Buf[g_psAdcBufCtrl->u16BufWriteIdx]; else s_pi16AdcBuf = g_ai16ADCSamples; #endif // 采用了硬件PDMA的方式 #if (ADC_PDMA_ENABLE == 1) PdmaCtrl_Start(ADC_PDMA_CH, (uint32_t *)&ADC->DAT, (uint32_t *)s_pi16AdcBuf, 8); #endif MIC_Start(); }
這個(gè)部分調(diào)用了這個(gè)關(guān)鍵函數(shù)。SPIFlashUtil_WriteEncodeData。主線程會(huì)在大部分時(shí)間執(zhí)行SPIFlashUtil_4KPagePartialWriting,將緩沖逐步寫入到SPI FLASH中。
另一個(gè)關(guān)鍵函數(shù)是NuLiteExApp_EncodeProcess。這是NuLiteEx庫(kù)的一個(gè)編碼處理應(yīng)用。
// Keep encode PCM buffer data to NuLiteEx lib. NuLiteExApp_EncodeProcess(&g_sApp.sNuLiteExAppEncode);
其在內(nèi)部調(diào)用了NuLiteEx_EncodeProcess,這是NuLiteEx庫(kù)的API。
源碼拓?fù)浣Y(jié)構(gòu)
上一篇:SDRAM容量的計(jì)算方法
下一篇:位域與位運(yùn)算
掃碼關(guān)注我們
傳真:0755-82591176
郵箱:vicky@yingtexin.net
地址:深圳市龍華區(qū)民治街道民治大道973萬(wàn)眾潤(rùn)豐創(chuàng)業(yè)園A棟2樓A08