Cable Messenger:语音波纹曲线生成策略

本文探讨了在iOS开发中避免过度依赖第三方库,以AMR-WB音频格式为例,讲解如何处理PCM数据生成波纹曲线。首先介绍了PCM数据的生成与分析,涉及RIFF WAV文件格式。接着,详细阐述了波纹曲线控件的核心逻辑,包括PCM数据的二次采样、曲线数量与高度计算以及绘制逻辑。强调理解技术本质,鼓励开发者深入探究并实践。
摘要由CSDN通过智能技术生成


Cable Messenger 聊天中进行短语音发送时,可以通过对语音文本数据进行实时分析,生成相关的语音波纹起伏曲线。

此篇文章主要为了倡导大家,在项目开发中,要多思考多实践,不要动手就离不开第三方库,没有第三方库就迈不开腿,甚至去找产品经理去改需求。很多东西其实可以自己写自己实现,而且要多了解和学习技术,多了解事物的本身,做项目不是简单的堆第三方库。

波纹数据的生成与分析

PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。

如果是单声道的音频文件,采样数据按时间的先后顺序依次存,如果是双声道的话就按照LRLRLR的方式存储,存储的时候与字节序有关。以位深度为16bit为例,对于双声道的音频文件而言,在每个采样时间间隔内,会同时生成 16 * 2 bit的数字音频数据,以顺序的形式进行存储。

PCM数据,作为设备生成的最原始数据,在进行各种压缩算法和封装格式进行封装后,生成了我们大家所熟知的MP3, AMR 等格式。而当我们接收到各种各样的音频格式,要进行播放前,要反向地对各种格式进行解封装,对相应该压缩后的数据进行还原,还原成原始的PCM数据后才能进行播放。因为本编不是对音频格式理论的详细描述,所以只一笔带过。

Cable Messenger 对于短语音文件格式上,采用了比较适合传输短语音文件的AMR-WB 格式进行传输。与AMR-NB相比,AMR-WB支持的频率区间更大,也是比较常用的AMR格式。

在安卓平台上,原生的播放控件已经完美支持AMR下两种格式文件的播放。而在IOS平台上,声称在过去的版本曾经支持过AMR文件格式的播放。但就现时,原生的播放器还是缺少了对于AMR文本进行直接拆封解压生成PCM数据进行播放的能力。于是IOS端在接收到AMR格式文件时,在播放前就对AMR数据进行了自动的转换,生成PCM格式数据,以WAV封装规范对PCM数据进行封装。在播放的时候交由原生音频播放器进行播放。

PCM作为最原始的音频数据,是生成波纹数据的基础。所以第一步我们要做的就是如何分离PCM数据。

在介绍前,先要了解什么是RIFF资源互换文件格式。RIFF文件由一个或多个“块”组成。每个“块”由“块标识”(4Byte)“长度”(4Byte)“数据”(由前面的长度决定)。

就WAV文件而言,它由一个“块标识”值RIFF的“块”进行封装。而在这个“块”内部的“数据”中,由一个标准的块组成,“块标识”值为WAVE

WAVE子块中,又可能存在以fmt(格式信息) data(PCM数据)fact(附加数据)为“块标识”值的三种子块。其中波纹数据就放在 data“块标识”值的的“数据”中。

好了,说到我自己都绕进去了。因为不是一篇理论型的文章,就不长篇大论的说理论了,有兴趣的话,这些资料到处都可以查来。

以下以Objective C 代码为例给出PCM数据的取值方法,因为只关注于PCM数据的取值,其它的块信息就不给出分析代码了。

以下给出的代码中,以位深度为16bit,单声道,采用均衡采样的方式进行采样生成的PCM数据为例。

#pragma mark - 分析wav的声纹曲线, 返回声纹数据
+ (nullable NSData*) decodePCM:(nonnull NSString*)path{
   
    NSData *wavData = [NSData dataWithContentsOfFile:path];
    if wavData == nil{
   
    	return null;
    }
    
    int index 	 	 = 0;
    int dataSize 	 = 0;
    BOOL enable  	 = NO;
    NSData *riifData = nil;
 
    //1. 先判断文件是否是标准RIFF格式
    NSData *dType   = [wavData subdataWithRange:NSMakeRange(0, 4)];
    NSString *sType = [[NSString alloc] initWithData:dType encoding:NSUTF8StringEncoding];
    if([@"RIFF" isEqualToString:fileType]){
   
        enable = YES;
        //2.取得RIFF数据长度
        int riifSize;
        [[wavData subdataWithRange:NSMakeRange(4, 4)] getBytes:&riifSize length:sizeof(riifSize)];
            
        //判断 是否是 WAVE 格, WAVE格式后面会有 format 和 data chunk
        NSData *dWave   = [wavData subdataWithRange:NSMakeRange(8, 4)];
        NSString *sWave = [[NSString alloc] initWithData:dWave encoding:NSUTF8StringEncoding];
        if ([@"WAVE" isEqualToString:sWave] == NO){
   
            enable = NO;
        }
        //3.截取 WAVE chunk 数据
        if (riifSize > 0){
   
            riifSize = riifSize - 4;
            riifData = [wavData subdataWithRange:NSMakeRan
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值