ISD9160学习笔记04_ISD9160音频编码代码分析

前言

录音例程涉及了录音和播放两大块内容,上篇笔记说了播放,这篇就来说说录音这块,也就是音频编码这部分功能。

上篇笔记中的这段话太装逼了,我决定再复制下,嘿嘿。

“我的锤子便签中有上个月记下的一句话,“斯蒂芬·平克说,写作之难,在于把网状思考,用树状结构,体现在线性展开的语句里。”这篇代码解析也有类似的困难,代码的网状结构,如何用文章这种线性载体来体现。”

跟上篇笔记的做法一样,还是挑出了主干,来讲下自己的理解。另外在文章最后添加了一个模块拓扑图来帮助消化。

本文作者twowinter,转载请注明:http://blog.csdn.net/iotisan/

查看代码主逻辑,主要是App_StartRec和App_ProcessRec这两个函数。下面就分别进行分析。

第一部分 App_StartRec

App_StartRec是由按键触发的,也就是按键按下去就开始录音。

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两部分子函数。

重中之重NuLiteExApp_EncodeStart

NuLiteExApp_EncodeStart(&g_sApp.sNuLiteExAppEncode, &sAudioChunkHeader, ADC_SAMPLE_RATE, E_NULITEEX_ENCODE_BPS_10);照例对代码做了中文注解方便消化。

g_sApp.sNuLiteExAppEncode是全局变量,涉及编码库的操作。sAudioChunkHeader是一个临时变量,用来做音频块头部信息。

 

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;
    }

    // 将全局变量申请的内存传入给编码库,方便其工作执行。将音频块头部传入,编码库最后的输出结果会体现在这里。另外的采样率信息是输入变量,辅助生成最后的音频块。
    // 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;

    // 这一步很关键,设置录音模块部分的缓存。
    // 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;
}

也很重要的Record_StartRec

上面说录音模块的操作顺序就是这样:SetInBufRecord ->Add -> StartRec。这就来了。 
硬件PDMA这里头涉及一个关键函数,PDMA会把ADC数据直接放到s_pi16AdcBuf里头。

void Record_StartRec(void)
{

    g_u8AppCtrl |= APPCTRL_RECORD;

    #if (ADC_FILTER_ENABLE == 1)
    NoiseFilter_ResetIIR2();
    s_pi16AdcBuf = g_ai16ADCSamples;
    #else
    // 主要是缓冲区的处理
    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();
}

第二部分 App_ProcessRec

这个部分调用了这个关键函数。SPIFlashUtil_WriteEncodeData。主线程会在大部分时间执行SPIFlashUtil_4KPagePartialWriting,将缓冲逐步写入到SPI FLASH中。

另一个关键函数是NuLiteExApp_EncodeProcess。这是NuLiteEx库的一个编码处理应用。

// Keep encode PCM buffer data to NuLiteEx lib.
NuLiteExApp_EncodeProcess(&g_sApp.sNuLiteExAppEncode);

其在内部调用了NuLiteEx_EncodeProcess,这是NuLiteEx库的API。

总结

源码拓扑结构

 

转载于:https://www.cnblogs.com/zhugeanran/p/9230048.html

近年来,随着电子技术突飞猛进的发展,各种数字电子设备悄然兴起。这些电子设备虽然功能非常强大,但桌面按钮操作却十分复杂,同一个按键往往可以实现多种操作。目前,人们使用的电视遥控器基本上都是手动遥控器,虽然使用相对比较方便,但是对于儿童和老年人却存在以下四点不便: 1、键盘不易识别,使用起来有障碍; 2、容易按错键、选错台; 3、要看某个频道要记住它所对应的数字代码,由于频道比较多,大量的代码很容易混淆; 4、在夜晚不开灯的情况下,很难用普通手动遥控器轻易转换频道。 基于以上几点Nuvoton推出了基于ISD9160的智能语音遥控器方案。ISD9160是一款具有Cortex-M0内核的语音SOC,能够实现录音放音等应用。通过软件支持,ISD9160可以实现特定人和非特定人语音识别。其中非特定人语音识别支持九种语音,方便客户开发国际化的产品。客户在开发的时候,使用Nuvoton提供的ASR Tool工具,只需将所需命令写成文本模式,然后经由工具转换,就能生成用于项目文件的语音识别代码模块,简单并且容易使用。客户可以方便的进行自己遥控器命令的定制。 ► 核心技术优势 ISD91xxx系列是以内嵌的ARM:registered:Cortex:trade_mark:-M0 32位微控制器核心为低功率、录音及播放所优化的系统上芯片产品。在音讯功能部份,ISD9xxx系列包括一颗具备80dB SNR性能的Sigma-Delta ADC,搭配具有最高至56dB增益的可程序增益放大器(PGA),以直接连接麦克风。音讯输出是由能对8Ω喇叭输出1W功率的差动Class D放大器(DPWM)所提供的。ISD9160VI能提供对于少数字汇的简单指令,例如「开电视」、「关电视」、「音量+」、「音量-」等语音辨识,一旦辨识出指令(关键字),装置就能在预先储存在芯片上的闪存中的音讯提供音效。 ► 方案规格 •FCC/ETSI认证 •低功率消耗: o<5uA @ 待机模式 o17mA @ 按键矩阵操作模式 o30mA @ 麦克风操作模式 •FHSS跳频:164个频道 •操作:8公尺 •音频质量:16-bit PCM @16KHz •支持Skype/语音电话 •喇叭独立辨识(SIR) •适用于少数字汇之简单指令的优异精确性 •目前支持九种语言及多种方言 方案来源于大大通。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值