前言

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

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

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

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

本文作者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(); // 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 == ) )
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 = ;
psNuLiteExAppEncode->sEncodeBufCtrl.u16BufReadIdx = ; // Set Encoded frame size, Storage Utility will refer to this size to write data.
psNuLiteExAppEncode->sEncodeBufCtrl.u16FrameSize = (psAudioChunkHeader->u32BitPerFrame)>>;
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, );
#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。

总结

源码拓扑结构

ISD9160学习笔记04_ISD9160音频编码代码分析的更多相关文章

  1. ISD9160学习笔记03_ISD9160音频解码代码分析

    录音例程涉及了录音和播放两大块内容,这篇笔记就先来说说播放,暂且先击破解码这部分功能. 我的锤子便签中有上个月记下的一句话,“斯蒂芬·平克说,写作之难,在于把网状思考,用树状结构,体现在线性展开的语句 ...

  2. memcached学习笔记——存储命令源码分析上篇

    原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...

  3. input子系统学习笔记六 按键驱动实例分析下【转】

    转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html 本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! i ...

  4. tensorflow笔记:多层LSTM代码分析

    tensorflow笔记:多层LSTM代码分析 标签(空格分隔): tensorflow笔记 tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) ten ...

  5. memcached学习笔记——存储命令源码分析下篇

    上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...

  6. ArcGIS案例学习笔记2_1_学校选址适宜性分析

    ArcGIS案例学习笔记2_1_学校选址适宜性分析 计划时间:第二天上午 目的:学校选址,适宜性分析 内容:栅格数据分析 教程:pdf page=323 数据:chapter8/ex1/教育,生活,土 ...

  7. tensorflow笔记:多层CNN代码分析

    tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代码分析 ...

  8. ISD9160学习笔记05_ISD9160语音识别代码分析

    前言 语音识别是特别酷的功能,ISD9160的核心卖点就是这个语音识别,使用了Cybron VR 算法. 很好奇这颗10块钱以内的IC是如何实现人家百来块钱的方案.且听如下分析. 本文作者twowin ...

  9. WebGL three.js学习笔记 创建three.js代码的基本框架

    WebGL学习----Three.js学习笔记(1) webgl介绍 WebGL是一种3D绘图协议,它把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的 ...

随机推荐

  1. Linux之查看切换Shell

    1.查看存在的shell cat /etc/shells 2.查看使用的shell echo $SHELL 3.切换shell 切换bash chsh -s /bin/bash 切换zsh chsh ...

  2. Simsimi 小黄鸡机器人最新无限制接口api simsimi机器人接口api 微信公众号

    一.什么是Simsimi? simsimi公司是提供智能服务,其中一个服务是simsimi聊天机器人服务,每天有超过百万的用户聊天,国内最大的搜索引擎——百度的产品siri使用的就是simsimi提供 ...

  3. HTML5实现摇一摇的功能(实测后)--转

    eviceMotionEvent(设备运动事件)返回设备有关于加速度和旋转的相关信息.加速度的数据将包含三个轴:x,y和z(示意如下图所 示,x轴横向贯穿手机屏幕或者笔记本键盘,y轴纵向贯穿手机屏幕或 ...

  4. 使用Maven清理项目

    在基于Maven的项目中,很多缓存输出在“target”文件夹中.如果想建立项目部署,必须确保清理所有缓存的输出,从面能够随时获得最新的部署. 要清理项目缓存的输出,发出以下命令: mvn clean ...

  5. e823. 创建JSplitPane

    A split pane divides its space between two components. The split pane contains a divider that allows ...

  6. (转)最简单的基于FFmpeg的内存读写的例子:内存播放器

    ffmpeg内存播放解码 目录(?)[+] ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章 ...

  7. (转)Integrating Intel® Media SDK with FFmpeg for mux/demuxing and audio encode/decode usages 1

    Download Article and Source Code Download Integrating Intel® Media SDK with FFmpeg for mux/demuxing ...

  8. Python WSGI开发随笔

    本文记录学习WSGI时的一些知识点,值得后续学习中注意. wsgi应用接口只要是一个可调用的对象就行,这个可调用的对象需要: 1. 接受两个位置参数: a. 包含CGI形式变量的字典: b. 应用调用 ...

  9. Keepalived + Nginx + Tomcat 的高可用负载均衡架构搭建

    Keepalived + Nginx + Tomcat 的高可用负载均衡架构搭建 Nginx 是一个高性能的 HTTP反向代理服务器 Keepalived 是一个基于VRRP协议来实现的LVS服务高可 ...

  10. Linux目录和文件管理

    今天我们来介绍一下对于Linux系统“命令“的理解和分类以及常用的目录文件管理命令的使用. 一. 命令 用于实现某一类功能的指令或程序,命令的执行依赖于解释器程序(例如:/bin/bash) 分类 内 ...