引言

工作需要将一份 双声道的PCM数据转换成单声道数据,我采用的是将左右声道样点值对应相加求平均样点值的办法。
计算式如下:

typedef          int s32;
typedef unsigned int u32;typedef          short s16;
typedef unsigned short u16;/*
*   双声道转换成单声道:48khz-16bit-stereo  --->  8khz-16bit-mono
*   源数据缓冲:pSrcBuf
*   源数据长度:dwSrcLen
*   目标数据缓冲:pDstBuf
*   下面的样点必须使用 s16 表示,禁止使用 u16表示,因为u16会导致计算出错,从而产生大噪声问题!
*/u32 dwSampleNum = dwSrcLen >> 2; //计算单声道样点数
u16* pwSrc = (u16*)pSrcBuf; //双声道数据缓冲
u16* pwDst = (u16*)pDstBuf; //单声道数据缓冲for (u32 dwIdx = 0 ; dwIdx < dwSampleNum; dwIdx++)
{pwDst[dwIdx]     = (pwSrc[2*dwIdx] + pwSrc[2*dwIdx + 1]) / 2; //左右声道求均值
}

问题

实际测试发现,上述代码处理后的PCM数据含有大量的大噪声!
用 Adobe Audition 打开处理后的单声道数据:

由图可知,必是大噪声。
将上图局部放大

继续放大

由图分析:正常的声音波形是在样点值接近0的时候发生突变的,变成极大值或极小值。
查看这些突变样点值大小

综上分析,正常的声音波形是在样点值接近0的时候发生突变的,变成极大值或极小值(即:绝对值接近 32768 = 2^15)

分析

我们在上面计算左右声道样点值的均值时,是用 u16 来表示样点值的,这种表示方法在计算均值时出问题了!
一般左右声道的对应样点值是比较接近的,可能出现下面的两种情况:
例如:左声道样点值 = -1 ,右声道样点值 = 1 时

(-1 + 1)/2
= (0000 0000 0000 0000 1111 1111 1111 1111 + 0000 0000 0000 0000 0000 0000 0000 0001) /2  //u16 整型提升为 s32
= (0000 0000 0000 0001 0000 0000 0000 0000) /2                                            //加法进位
= (0000 0000 0000 0000 1000 0000 0000 0000)                                               //除2相当于右移1位
= (1000 0000 0000 0000)                                                                   //截断操作:将计算结果赋值给 目标样点值s16
= -32768                                                                                  //(1000 0000 0000 0000)就是-32768的补码

例如:左声道样点值 = -2 ,右声道样点值 = 1 时

(-2 + 1)/2
= (0000 0000 0000 0000 1111 1111 1111 1110 + 0000 0000 0000 0000 0000 0000 0000 0001) /2  //u16 整型提升为 s32
= (0000 0000 0000 0000 1111 1111 1111 1111) /2                                            //加法进位
= (0000 0000 0000 0000 0111 1111 1111 1111)                                               //除2相当于右移1位
= (0111 1111 1111 1111)                                                                   //截断操作:将计算结果赋值给 目标样点值s16
= 32767                                                                                   //(0111 1111 1111 1111)就是32767的补码

其实,类似的左右样点组合还有很多,都是在0值附近,表现在波形中就是:
正常的声音波形在样点值接近0的时候发生突变的,变成极大值或极小值。

上述分析与问题现象一致,所以可以确定问题原因就是:
因为用 u16 来表示样点值的,导致在计算均值时出错!

解决方案

在计算左右声道的对应样点均值时,样点必须使用 s16 表示,禁止使用 u16表示,因为u16会导致计算出错,从而产生大噪声问题!

/*
*   双声道转换成单声道:48khz-16bit-stereo  --->  8khz-16bit-mono
*   源数据缓冲:pSrcBuf
*   源数据长度:dwSrcLen
*   目标数据缓冲:pDstBuf
*   下面的样点必须使用 s16 表示,禁止使用 u16表示,因为u16会导致计算出错,从而产生大噪声问题!
*/u32 dwSampleNum = dwSrcLen >> 2; //计算单声道样点数
s16* pwSrc = (s16*)pSrcBuf; //双声道数据缓冲
s16* pwDst = (s16*)pDstBuf; //单声道数据缓冲for (u32 dwIdx = 0 ; dwIdx < dwSampleNum; dwIdx++)
{pwDst[dwIdx]     = (pwSrc[2*dwIdx] + pwSrc[2*dwIdx + 1]) / 2; //左右声道求均值
}

记录一个音频PCM数据由双声道转单声道出错问题相关推荐

  1. 单声道数据转双声道_单声道转双声道方法

    单声道转双声道方法 前段时间有个朋友问我如何可以将一个音频文件的单声道转换为双声道 [音频文件右键查看 属性 → 摘要 → 音频 → 频道( 1. 单声道 2. 立体声) ] ,于是我推荐他用 Gol ...

  2. 从双声道转单声道看语言/算法性能差异

    目录 一.使用场景 二.算法 1. Java-数组遍历 2. c/c++ -索引遍历 3. c/c++ -指针遍历 三.数据说话 四.总结 一.使用场景 我们都知道不同的语言有不同的特性,所以在比较某 ...

  3. 音频PCM数据的单声道、双声道之间的转换

    在使用tinyalsa处理PCM音频数据时发现该设备只能以双声道形式打开设备. tinypcminfo工具可以查看设备信息. out和in里面channels 最大和最小值都是2.但是实际使用中有时候 ...

  4. pcm 32bit float 双声道转换16bit单声道

    pcm 32bit float 双声道转换16bit单声道 多通道音频转单通道 音频多通道是按照采样点进行交叉排列,比如双声道的16bit音频,16bit为一个采样点,那就是按照 通道1(16bit) ...

  5. js实现音频PCM数据合并、拼接、裁剪、调节音量等功能

    关于音频的内容,我边学习,边实践也总结了一些,从最开始实现一个简单的web音乐播放器的自定义工具栏,到后来的实现简单的音频频谱图.直到今天的对音频数据进行的进一步操作,我也是一点点的在进步.虽然很多地 ...

  6. ffmpeg进行混音,将两路音频pcm数据合成一路输出

    ffmpeg进行混音,将两路音频pcm数据合成一路输出 audiomixer.h #ifndef AUDIOMIXER_H #define AUDIOMIXER_H#include <map&g ...

  7. [Android] [音视频系列]在 Android 平台使用 AudioRecord 和 AudioTrack API 完成音频 PCM 数据的采集和播放,并实现读写音频 wav 文件

    参考 官方文档地址:https://developer.android.google.cn/reference/android/media/AudioRecord GitHub 地址:https:// ...

  8. 使用FFMpeg将音频PCM数据生成WAV和MP3文件

    文章目录 1. 获取编码器和创建解码器上下文 2. 创建音频流和输出封装上下文 3. 编码原始数据写入到文件中 WAV音频封装格式可以存储无编码的PCM数据,而MP3封装格式中不能直接存储PCM数据, ...

  9. AudioRecord 采集音频PCM数据

    AudioRecord 可以用来采集音频原始数据(PCM)格式,使用起来非常简单. 主要就是构造函数的定义 AudioRecord(int audioSource, int sampleRateInH ...

最新文章

  1. node平台截取图片模块——jimp
  2. oracle10g库连接报错
  3. HTML5按钮的点击态问题
  4. Ralink5350开发环境搭建
  5. 详细介绍 Qt Creator 快捷捷应用
  6. New Currency Rate IOS APP 上线
  7. 12018.LTC2631电压调节芯片
  8. 区分三个概念:Epoch, Batch, Iteration
  9. 职位越高的人,越容易犯5个错
  10. struts读常量顺序
  11. linux 启动作业,[转载] 随身带着走的作业系统 ~安装Linux作业系统于随身碟~
  12. python网页爬虫简单代码_python简单爬虫(示例代码)
  13. Part.0模糊集表示方法
  14. Java实现二维码扫码授权登陆
  15. 什么是HikariCP?HikariCP介绍(包含配置示例)
  16. wifi已连接不可上网服务器无响应,为什么手机连上wifi却上不了网
  17. word表格分开快捷键_Word快捷键一览表
  18. 针对PVS方式的VDI部署趋势杀毒优化方法
  19. 使用Stellarium查看彗星
  20. 太厉害了,终于有人能把Ansible讲的明明白白了,建议收藏

热门文章

  1. 2.RabbitMQ 的可靠性消息的发送
  2. 股份期权激励协议书模板
  3. 2866802菲尼克斯电源模块QUINT-PS3AC24DC40
  4. Web消息推送之SSE
  5. 24V转5V,24V转3.3V稳压芯片的电路图,PCB和BOM
  6. 员工上网行为管理——一把怎样的双刃剑
  7. 钢铁侠马斯克,当上了美国院士
  8. 联通物联卡为什么没有网络_联通物联网卡怎么样?联通物联卡的查询官网是什么?...
  9. 基于C#平台下利用POP3和SMTP协议的邮件归档系统
  10. 基于Java的酒店管理系统毕业论文