日本高清不卡中文字幕-一起草草视频在线观看-亚洲精品一区二区三区色-国产亚洲精品免费视频

您好,歡迎進入深圳市穎特新科技有限公司官方網(wǎng)站!

您現(xiàn)在的位置:首頁 新聞資訊 >> 新聞頭條 >> ISD9160學習筆記03_ISD9160音頻解碼代碼分析
新聞資訊
NEWS INFORMATION

ISD9160學習筆記03_ISD9160音頻解碼代碼分析

發(fā)布時間:2019-05-22

錄音例程涉及了錄音和播放兩大塊內(nèi)容,這篇筆記就先來說說播放,暫且先擊破解碼這部分功能。

我的錘子便簽中有上個月記下的一句話,“斯蒂芬·平克說,寫作之難,在于把網(wǎng)狀思考,用樹狀結(jié)構(gòu),體現(xiàn)在線性展開的語句里。”這篇代碼解析也有類似的困難,代碼的網(wǎng)狀結(jié)構(gòu),如何用文章這種線性載體來體現(xiàn)。我盡量挑出了主干,來講解自己的理解。另外在文章最后添加了一個模塊拓撲圖來幫助消化。

我還是建議大家還是多琢磨下源碼,代碼的事還是讓代碼來說話,筆記是一個輔助的概括梳理。

本文作者twowinter,轉(zhuǎn)載請注明:http://blog.csdn.net/iotisan/

查看代碼主邏輯,主要是App_StartPlay和App_ProcessPlay這兩個函數(shù)。下面就分別進行分析。

第一部分 App_StartPlay

BOOL App_StartPlay(void)
{
    // Initiate NuLiteEx audio decode lib with callback functions stored in g_asAppCallBack[0]
    NuLiteExApp_DecodeInitiate(&g_sApp.sNuLiteExAppDecode, (UINT8 *)&g_sApp.uTempBuf, 0);

    // Start NuLiteEx decode lib to decode NuLiteEx file stored from address and played from audio channel 0.
    // And decode the first frame of PCMs.
    if ( NuLiteExApp_DecodeStartPlayByAddr(&g_sApp.sNuLiteExAppDecode, AUDIOROM_STORAGE_START_ADDR, 0) == FALSE )
        return FALSE;

    // Light playback led(PB9) for display status.
    OUT4(0);

    // Start Ultraio Timer & HW pwm for UltraIO curve output
    ULTRAIO_START();

    // Start to playback audio. 
    Playback_StartPlay();
}

可以看到App_StartPlay主要牽扯了NuLiteExApp和Playback兩部分子函數(shù)。

重中之重 NuLiteExApp_DecodeStartPlayByAddr

由于對音頻編解碼這塊比較陌生,我還是給對應(yīng)代碼做了中文注解方便消化。

BOOL NuLiteExApp_DecodeStartPlayByAddr(S_NULITEEX_APP_DECODE *psNuLiteExAppDecode, UINT32 u32NuLiteExStorageStartAddr, UINT8 u8PlaybackChannel)
{
    UINT16 u16SampleRate;
    // NuLiteEx解碼庫初始化對應(yīng)的工作緩沖區(qū),應(yīng)用層傳入temp緩存來方便解碼庫內(nèi)部工作。另外根據(jù)傳入的SPI地址從SPI取文件,獲取采樣率。
    // NuLiteEx decoder initiates work buffer and returns sample rate.
    if ( (u16SampleRate = NuLiteEx_DecodeInitiate(  (UINT8*)psNuLiteExAppDecode->au32DecodeWorkBuf, 
                                                    psNuLiteExAppDecode->pau8TempBuf, 
                                                    u32NuLiteExStorageStartAddr, 
                                                    g_asAppCallBack[psNuLiteExAppDecode->u8CallbackIndex].pfnReadDataCallback )) == 0 )
        return FALSE;   

    // 給Playback模塊對接對應(yīng)的工作緩沖區(qū),方便其下一步播放。
    // Initiate and set output buffer variable(include frame size, buffer size etc.) 
    Playback_SetOutputBuf(  &psNuLiteExAppDecode->sOutBufCtrl,
                            NULITEEXAPP_OUT_BUF_SIZE,
                            psNuLiteExAppDecode->i16OutBuf,
                            NULITEEXAPP_OUT_SAMPLES_PER_FRAME,
                            u16SampleRate );

    // 工作緩沖區(qū),置有效位。
    // Trigger active flag of output buffer for NuLiteEx decoding
    BUF_CTRL_SET_ACTIVE(&psNuLiteExAppDecode->sOutBufCtrl);

    // 工作緩沖區(qū)中的讀寫指針賦值。
    // Pre-decode one frame
    psNuLiteExAppDecode->sOutBufCtrl.u16BufWriteIdx = NULITEEXAPP_OUT_SAMPLES_PER_FRAME;
    if ( NuLiteExApp_DecodeProcess(psNuLiteExAppDecode) == FALSE )
    {
        BUF_CTRL_SET_INACTIVE(&psNuLiteExAppDecode->sOutBufCtrl);
        return FALSE;
    }
    psNuLiteExAppDecode->sOutBufCtrl.u16BufReadIdx = NULITEEXAPP_OUT_SAMPLES_PER_FRAME;

    // 記錄當前播放的channel,用來停止播放。
    // Record play channel index for stopping to play.
    psNuLiteExAppDecode->u8PlaybackChannel = u8PlaybackChannel;
    // 準備播放,把這里的循環(huán)緩沖區(qū)同playback共用。
    // Add audio codec into channel and preper to play codec.
    Playback_Add(psNuLiteExAppDecode->u8PlaybackChannel, &psNuLiteExAppDecode->sOutBufCtrl);

    return TRUE;
}

也很重要的Playback_StartPlay

void Playback_StartPlay(void)
{
    INT16 *pi16PcmBuf;

    if( s_u8PlayCtrl == PLAYBACK_NOACTION ) // 這個s_u8PlayCtrl是playback模塊內(nèi)部處理的。
    {
        #if ( PLAYBACK_CHANNEL_COUNT > 1)
        pi16PcmBuf = g_ai16DACSamples;
        #else
        pi16PcmBuf = &g_psDacBufCtrl->pi16Buf[g_psDacBufCtrl->u16BufReadIdx];// PCM數(shù)據(jù)緩沖區(qū)復制。
        #endif

        #if ((APU_FILTER_ENABLE == 1)&&(APU_UPSAMPLE == 2))
        NuDACFilterEx_Up2Initial(g_au8Up2WorkBuf);
        #elif ((APU_FILTER_ENABLE == 1)&&(APU_UPSAMPLE == 4))
        NuDACFilterEx_Up4Initial(g_au8Up4WorkBuf);
        #endif
        g_u8AppCtrl|=APPCTRL_PLAY;
        s_u8PlayCtrl |= PLAYBACK_START;
        #if (APU_ENABLE)
        {
            UINT8 u8Count;

            for( u8Count = 0; u8Count < 8; u8Count ++)
                g_ai16DACSamples[u8Count] = 0;      //Clear virtual buffer
        }
        #endif

        Playback_ResetChannelVolume(0);

        SPK_Start(); // 這里頭開始調(diào)用DPWM來播放DPWM->DATA,DPWM_START_PLAY(DPWM);

        #if (APU_PDMA_ENABLE)
        PdmaCtrl_Start(APU_PDMA_CH, (uint32_t *)pi16PcmBuf, (uint32_t *)&DPWM->DATA, 8);// 將PCM緩沖數(shù)據(jù)傳到DPWM->DATA中。
        #endif

    }
}

第二部分 App_ProcessPlay

App_ProcessPlay只調(diào)用了如下這個函數(shù)

BOOL NuLiteExApp_DecodeProcess(S_NULITEEX_APP_DECODE *psNuLiteExAppDecode)
{
    INT16 *pi16OutBuf;

    // 環(huán)形緩沖區(qū)非激活狀態(tài),這個只有在應(yīng)用層置位(按鍵停止、或者啟動失敗等情況)
    if (BUF_CTRL_IS_INACTIVE(&psNuLiteExAppDecode->sOutBufCtrl))
        return FALSE;

    // 環(huán)形緩沖區(qū)還有未讀數(shù)據(jù)
    if ( Playback_NeedUpdateOutputBuf(&psNuLiteExAppDecode->sOutBufCtrl) )
    {
        // 由核心庫來判斷這個文件是否解析完了
        // Check end of file
        if(NuLiteEx_DecodeIsEnd((UINT8*)psNuLiteExAppDecode->au32DecodeWorkBuf))
        {
            // Trigger inactive flag of output buffer to stop NuLiteEx decoding
            BUF_CTRL_SET_INACTIVE(&psNuLiteExAppDecode->sOutBufCtrl);
            // Use to represnt no active(or end) of decoding
            psNuLiteExAppDecode->sOutBufCtrl.u16SampleRate = 0;
            return FALSE;
        }

        // Record output data buffer pointer(for duplicate & process)
        pi16OutBuf = (PINT16)&psNuLiteExAppDecode->sOutBufCtrl.pi16Buf[psNuLiteExAppDecode->sOutBufCtrl.u16BufWriteIdx];

        // 核心庫繼續(xù)發(fā)揮其巨大作用,開足馬力讀取文件中PCM數(shù)據(jù)轉(zhuǎn)到緩沖區(qū)。
        NuLiteEx_DecodeProcess( (UINT8*)psNuLiteExAppDecode->au32DecodeWorkBuf, 
                                psNuLiteExAppDecode->pau8TempBuf, 
                                pi16OutBuf, 
                                g_asAppCallBack[psNuLiteExAppDecode->u8CallbackIndex].pfnReadDataCallback, 
                                g_asAppCallBack[psNuLiteExAppDecode->u8CallbackIndex].pfnUserEventCallback);

        // PlayBack依舊共享這個緩沖區(qū),準備對數(shù)據(jù)進行進一步處理
        // Update write index of output buffer and avoid buffer overflow
        Playback_UpdateOutputBuf(&psNuLiteExAppDecode->sOutBufCtrl);

        // Duplicate data into buffer for using duplication callback function.
        if ( psNuLiteExAppDecode->u8CtrlFlag&(NULITEEXAPP_CTRL_DUPLICATE_TO_BUF|NULITEEXAPP_CTRL_DUPLICATE_TO_FUNC) )
        {
            if ( psNuLiteExAppDecode->u8CtrlFlag & NULITEEXAPP_CTRL_DUPLICATE_TO_BUF )
                BufCtrl_WriteWithCount(psNuLiteExAppDecode->psDuplicateOutBufCtrl, NULITEEXAPP_OUT_SAMPLES_PER_FRAME, pi16OutBuf );
            else 
                psNuLiteExAppDecode->pfnDuplicateFunc(NULITEEXAPP_OUT_SAMPLES_PER_FRAME, pi16OutBuf);
        }       
    }   
    return TRUE;
}

總結(jié)

源碼拓撲結(jié)構(gòu)

 

聯(lián)系方式0755-82591179

傳真:0755-82591176

郵箱:vicky@yingtexin.net

地址:深圳市龍華區(qū)民治街道民治大道973萬眾潤豐創(chuàng)業(yè)園A棟2樓A08

庆元县| 芷江| 宜兰县| 彰化市| 长海县| 芒康县| 竹北市| 天津市| 吴桥县| 贵德县| 定结县| 大新县| 随州市| 颍上县| 彰化市| 巴东县| 卓尼县| 梁山县| 乌鲁木齐县| 阿拉善左旗| 七台河市| 大城县| 华蓥市| 五大连池市| 延川县| 阿巴嘎旗| 师宗县| 柳林县| 寻乌县| 南昌县| 博罗县| 长岛县| 黄山市| 卢龙县| 抚顺县| 黑山县| 保德县| 巴楚县| 陆川县| 抚远县| 册亨县|