最近因为项目需要对声音进行变声,所以边学习边做,发现音频的处理思路并不难,但是做起来还是有些繁琐的(比预期的)

趁着脑子还发热,赶紧把思路总结一下,记录下来。

主要讲三个部分

1,如何变声2,安卓实现变声3,ios实现变声

1.如何变声?

要想自己写一个变声的函数或者库出来,谈何容易,所以采用了大家普遍采用的库SoundTouch。

该库可以实现改变声音的速度,节拍,音调(这个最重要,可以把声音的音调调高调低,使之变成男生女生,可以参照汤姆猫),该库中对外提供方法的类为SoundTouch类,该类提供了许多方法,其中最重要的就是setPitch,setRate这几个调节声音参数的方法,可以通过设置参数大小实现各种效果,该类在使用前需要初始化一下,设置预制参数如下:

                mSoundTouchInstance->setSetting(SETTING_USE_QUICKSEEK, 0);
mSoundTouchInstance->setSetting(SETTING_USE_AA_FILTER, !(0));
mSoundTouchInstance->setSetting(SETTING_AA_FILTER_LENGTH, 32);
mSoundTouchInstance->setSetting(SETTING_SEQUENCE_MS, 40);
mSoundTouchInstance->setSetting(SETTING_SEEKWINDOW_MS, 16);
mSoundTouchInstance->setSetting(SETTING_OVERLAP_MS, 8);

然后设置音频参数实现效果:

                mSoundTouchInstance->setChannels(2);
mSoundTouchInstance->setSampleRate(8000);
mSoundTouchInstance->setPitch(2);

这里解释一下音频处理的几个参数,很重要。

声道:channals,可以是单声道和双声道,分别对应1,2

采样率:SampleRate  8000-44100不等,一般是常用的几个值,安卓里面好像44100是所有设备都支持的,所以设置成44100比较保险吧

每个声道的位数:bitsPerChannel 一般设置为16

每个帧的声道数 ChannelsPerFrame    对于pcm数据来说,这个是1

还有几个参数,对于安卓和ios可能说法不太一样,以上几个是都要用到的,比较重要,必须得掌握

2.Android中实现变声

因为项目要求录音要实时播放,所以需要采用读取音频数据流(PCM格式)来播放,采用的api是AudioRecorder和AudioTrack。这两个类相关资料较多,官方文档也比较详细。难点是Android中调用c++库需要使用到jni技术,这里就需要花一些力气将SoundTouch编成so库来使用了。对于这方面可以参考我的上一篇关于JNI的博客,也可以参考网上的资料,将SoundTouch类的几个重要函数对应到java层的Native函数,然后在java层调用。

以下是我写的代码的一部分

首先初始化AudioTrack和AudioRecord:

        //初始化AudioTrack
     int trbusize=AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,RECORDER_SAMPLERATE,
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
trbusize,
AudioTrack.MODE_STREAM);
     //初始化AudioRecord
int rebusize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
     AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord= new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDER_SAMPLERATE,
AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, rebusize);

各项参数的含义可以参考api文档,需要注意的是,因为不同设备支持的参数可能不同,需要时可以写一个循环把所有可能的参数遍历一遍。

之后是录音和播放,可以分别放到两个线程里面。一般来说都是把录音数据保存到文件中,然后再进行播放,这样可以应付一般的录音需求。但不足之处在于,录音时间久了,文件会很大,如果在网络上实时播放的话这样肯定不行。解决方法就是将录音的数据传到一个缓冲区,然后播放时直接从缓冲区取走数据即可。这个缓冲区可以考虑用循环队列或者在java里面可以直接用一个LinkedList实现。

然后是变声部分:

                while(isInstancePlaying){
if(l<21){
byte[] mbyte=new byte[64];
mAudioRecord.read(mbyte,0,64);
SoundTouch.getSoundTouch().putSamples(mbyte,0,INPUT_LENGTH);
SoundTouch.getSoundTouch().setPitchSemiTones(pitchTone);
SoundTouch.getSoundTouch().receiveSamples(mbyte,INPUT_LENGTH);

byteArray.add(mbyte);
l=byteArray.size();
}
else{
mAudioTrack.write(byteArray.getFirst(),0,64);
byteArray.removeFirst();
l=byteArray.size();
}

代码中加粗的三个函数putSamples,setPitchSemiTones,receiveSamples.这三个都是native方法,在SoundTouch库中分别通过SoundTouch类提供的对应函数实现,

通过put和receive两个函数,mbyte这个数据块中的音频数据就实现了变声,变声的效果是通过中间的函数setPitchSemiTones()设置的。这里为了实现实时变声,我采用

了LinkedList作为一个缓冲区,l是其长度,当小于20时添加到byteArray的末尾,同时AudioTrack不断读取数组中的第一个元素来播放然后删除该元素,这样实现了实时的播放。

最后播放完要记得释放mAudioTrack和mAudioRecorder。通过stop和release方法实现。

3.IOS实现变声

因为本人之前没接触过ios所以做起来遇到了不少问题,还好最后解决了。

ios里面的音频处理比起安卓来说感觉要麻烦一些,用到的核心api就是AudioQueue,正在使用之前一定要好好理解一下它的原理,跟安卓不同的是ios播放和录音都是用的这个api。就相当于它一个东西实现了安卓中AudioRecorder和AudioTrack的功能,只不过在播放和录音过程中内部的流程有所变化。

核心思想:

Audio里面有自带的一个队列,首先用户创建若干个(3-6个左右都行)缓冲器用来装填音频数据,在自带队列中播放或录音完后使用用户自定义的回调函数进行处理,使得缓冲器能够被重新利用,并且可以在回调函数中实现用户自定义的一些功能,比如变声,写入文件等等操作。官方给了说明图比较详细,需要着重理解一下。

首先是录音的流程图:

然后是播放的流程图:

如何变声呢?

ios的变声不需要安卓的jni,因为oc语言可以和c++混编,所以这点相对来说要简单许多。流程如下:

首先在你的程序中实例化一个SoundTouch类,然后在初始化时将它的参数设置好(setSetting),之后在上面所述的回调函数里面就可以将录音得到的数据流进行处理然后选择保存到文件或者直接播放。思路就是这样,但是里面的函数的参数相对还是比较繁琐的,前面原理没理解的话这边就很难做下去了。

实时播放?

思路同Android,可以写一个循环队列用来缓存音频数据,然后边录音往里面传数据边播放,跟安卓不同的是这些操作需要放到相应的回调函数里面来实现,有个简单的办法是在录音的回调函数里面直接播放pcm数据。因为数据是一块一块的进来的,每使用完一次缓冲器才会调用一次回调函数,可以直接在回调函数里面进行播放。

以上就是两个平台上实现录音和实时播放的简单介绍,这里面的东西还是蛮多的,值得深入研究。

  

IOS和Android音频开发总结的更多相关文章

  1. Android音频开发之——如何播放一帧音频

    本文重点关注如何在Android平台上播放一帧音频数据.阅读本文之前,建议先读一下<Android音频开发(1):基础知识>,因为音频开发过程中,经常要涉及到这些基础知识,掌握了这些重要的 ...

  2. Android音频开发(1):基础知识

    Android音频开发(1):基础知识 导读 人的说话频率基本上为300Hz~3400Hz,但是人耳朵听觉频率基本上为20Hz~20000Hz. 对于人类的语音信号而言,实际处理一般经过以下步骤: 人 ...

  3. Vue项目用于Ios和Android端开发

    起因 前公司商城App项目使用的是H5开发,有微信公众号.Ios和Android三个版本,H5版本是自己写的一套框架,已经用了有些年头了,承载不下不断涌现出的新需求.而Ios和Android端通过we ...

  4. Android Multimedia框架总结(十七)音频开发基础知识

    请尊重分享成果,转载请注明出处,本文来自逆流的鱼yuiop,原文链接:http://blog.csdn.net/hejjunlin/article/details/53078828 近年来,唱吧,全民 ...

  5. 《React Native 精解与实战》书籍连载「配置 iOS 与 Android 开发环境」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  6. char的定义在iOS和Android下是不同的

    char is different in iOS and Android!跨平台开发时很容易忽略的非常坑爹的一个区别. 我的需求是实现一个算法,这个算法在iOS和Android下需要保持一致的结果,很 ...

  7. Android IOS WebRTC 音视频开发总结(十六)-- 音频设备操作之opensl与jni

    本节主要分享视频通话中android和ios上操作音频设备的方式,如调解音量大小,启用扬声器(本系列文章转载请说明出处,博客园RTC.Blacker). 先看看webrtc中处理音频设备代码的目录结构 ...

  8. Android IOS WebRTC 音视频开发总结(二九)-- 安卓噪声消除交流

    Android上的音质一直被大家所困扰和诟病,这里面有很多原因, 下面是最近一位前UC同行发邮件跟我交流的一些记录,供参考,支持原创,文章来自博客园RTC.Blacker,转载请说明出处. 以下文字来 ...

  9. Android IOS WebRTC 音视频开发总结(六)-- iOS开发之含泪经验

    前段时间在搞webrtc iOS开发,所以将标题改为了Android IOS WebRTC 音视频开发总结, 下面都是开发过程中的经验总结,转载请说明出处(博客园RTC.Blacker): 1. IO ...

随机推荐

  1. Redis学习四:解析配置文件 redis.conf

    一.它在哪 地址: 思考:为什么要将它拷贝出来单独执行? 二.Units单位 1 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit 2 对大小写不敏感 三.INCLUDES包 ...

  2. Centos7 设置静态IP后重启网络服务出错

    systemctl restart networkJob for network.service failed because the control process exited with erro ...

  3. Docker 初相见

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Li ...

  4. 基本控件文档-UIView属性

    CHENYILONG Blog 基本控件文档-UIView属性 Fullscreen   UIView属性技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http ...

  5. 编写shell脚本一键启动zookeeper集群!!

    踩了一个多小时坑终于解决了: 这里分享给大家,更主要的目的是记住这些坑,避免以后重复走!!! 首先,这里采用ssh秘钥方式进行集群主机之间免密登录执行启动命令 这里简单说下原理: 通过ssh去另外一台 ...

  6. numpy之ones,array,asarray

    from:http://blog.csdn.net/gobsd/article/details/56485177 numpy.ones() 废话少说直接上代码 >>> np.ones ...

  7. 加密文件之Java改进版

    对应Python版:加密文件之Python版Java版比Python版要快得多,两个版本不在一个量级上.在加密解密1G大文件时,Java版花费的时间是秒级,而Python版花费的时间是10分钟级. i ...

  8. flask基础之app初始化(四)

    前言 flask的核心对象是Flask,它定义了flask框架对于http请求的整个处理逻辑.随着服务器被启动,app被创建并初始化,那么具体的过程是这样的呢? 系列文章 flask基础之安装和使用入 ...

  9. 转载-struts中logic标签使用

    Struts中Logic逻辑标签的作用及用法 Struts中Logic逻辑标签的作用及用法 2006年10月18日 星期三 21:34 Terry原创,转载请说明作者及出处 Logic标签大部分的功能 ...

  10. C++面试常见问题

    转载:https://zhuanlan.zhihu.com/p/34016871?utm_source=qq&utm_medium=social 1.在C++ 程序中调用被C 编译器编译后的函 ...