阅读 82

变声-变身小萝莉(iOS&安卓)Fmod

描述声音的维度

  • 音调(频率,类似正玄波的周期)
  • 音色 (周期内的波纹抖动形状)
  • 响度 (类似正弦波的振幅)

声音如何采集?

  • 声音具有能量,薄膜震动发声

采样率,多长时间采集一次样本?

img

  • 根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右

公式 : f=1/T,T为周期(单位 HZ、s)

常见采样率使用场景:

  • 8khz:电话等使用,对于记录人声已经足够使用。
  • 22.05khz:广播使用频率。
  • 44.1khz:音频CD。
  • 48khz:DVD、数字电视中使用。
  • 96khz-192khz:DVD-Audio、蓝光高清等使用。

量化深度?

  • 描述声音细腻程度,一般用8位,2^8 = 256个等级
单位换算
1位0、1
1bit8位
1B8bit
1k1024B
1M1024k

一段未压缩的音频长度如何计算?

如何计算一段原始音频数据的文件大小,需要以下四个参数:

  • 时间:a 单位 s
  • 量化深度:b 单位 B
  • 采样频率:c 单位 kHz
  • 声道数:d 单位个

实例:

  • 1.量化深度: 16 位
  • 2.采样频率:44.1khz(每秒采集44100次)
  • 3.声道数:2
  • 4.时间 10s

比特率如何计算:

数据量如何计算:

size(单位:M) = 44.1*16*2*10/8/1024
复制代码
一个新的参数概念比特率

得出:

  • 1.采样频率:44100 hz
  • 2.采样周期:t = 1/441000 s = 0.0000022 s

1s的比特率计算公式为:

16*44100*2 = 1378.125kbps
复制代码

这时文件大小有了新的计算方式

比特率(kpbs) * 时长(s)/ 8 / 1024 =  size(MB)                  
复制代码

音频编码格式

这个就是脉冲编码调制数据,即PCM,表示无损数据。

在iOS平台录制的音频格式就是PCM的。

此外常见的音频格式有MP3、WAV、AAC、ogg;

其中WAV也是无损的,相对于PCM多了一些描述信息,比如声道数,采样率等,大小为44字节

MP3、WAV、ogg都是有损压缩格式

划重点:
  • 音质比较 wav=flac=ape>aac=opus>ogg>mp3~wma

  • 硬件支持,在采集端和播放端的设备支持,mp3>wma>aac~wav~opus>flac~ ogg>ape

mp3
  • mp3 常见的压缩库是lame,可以直接将pcm数据压缩成mp3数据;
  • iOS、安卓、windows各个平台都支持
  • 比特率大于128kbits,表现很好
  • 压缩比比较高 1/10-1/12
aac
  • 适用于码率较低的场景
  • 如视频中的音轨
  • 某些安卓机不支持
  • 收版权使用税
ogg
  • 都挺好,平台不支持,表现最优
  • 不支持流媒体
Opus

腾讯trtc,声网的实时音视频

  • 6 kb/秒到510 kb/秒的比特率;单一频道最高256 kb/秒
  • 采样率从8 kHz(窄带)到48 kHz(全频)
  • 帧大小从2.5毫秒到60毫秒
  • 支持恒定比特率(CBR)、受约束比特率(CVBR)和可变比特率(VBR)
  • 支持语音(SILK层)和音乐(CELT层)的单独或混合模式
  • 支持单声道和立体声;支持多达255个音轨(多数据流的帧)
  • 可动态调节比特率,音频带宽和帧大小
  • 良好的鲁棒性丢失率和数据包丢失隐藏(PLC)
  • 浮点和定点实现

VBR(Variable bitrate,动态数据速率)的技术。可以让MP3文件的每一段甚至每一帧都可以有单独的bitrate,这样做的好处就是在保证音质的前提下最大程度的限制了文件的大小。同样在视频也有动态码率。

opus 作为音频流,典型的m3u8(ts)格式,流相关的东西,有机会我会在直播的文章中说明。

用一张图总结:

目前网络实时通信中使用的opus,speex,amr,silk,iLBC等的一些对比。speex可以采用的比特率最低,2kbps;iLBC的比特率和音质之间达到了不错的平衡;opus在码率、采样率、编码性能和音质之间达到了很好的平衡,但放弃了超低码率;

WX20201023-161541@2x.png

变声原理

音色?
  • 葫芦丝的声音
  • 二胡的声音
  • 架子鼓的声音
  • 不同人的声音

因此通过技术来改变音色,比较困难,也是最重要的,市面上没有开源的东西可以用来改变音色,但根据傅里叶函数,我们知道音色是可以降解的。后续会提到。

音调?

有些声音低沉,有些声音高亢,正式音调起的作用。男声比女生通常声音低一个八度之内,我们可以利用这个特点进行变声。实现男变女、女变男。

响度?

用来改变声音的大小,是属于振幅变化。

变色实操原理

  • 萝莉音还是大叔

改变声音的音调

  • 御姐音(变慢)

img

y = Asin(wx+φ) + b
复制代码
φ:决定波形与X轴位置关系或横向移动距离(左加右减)
ω:决定周期(最小正周期)T= 2π/w
A:决定峰值(即纵向拉伸压缩的倍数)
b:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
复制代码

这里的声音变慢指的是一个周期内的声音被拉长

  • 小黄人

调节语速、提高音调

  • 机器人

机器人特点,声音(音调)低,还有回声

回声如何实现?两个波形错开相位,具体错开多少由参数确定

soundTouch

soundTouch 是C++的开源库,支持跨平台

  • github地址:https://github.com/rspeyer/soundtouch
  • 官网地址:http://soundtouch.surina.net/
  • iOSDemo:https://github.com/sunzhe/SoundTouch
  • android Demo:https://github.com/aserbao/AndroidCamera

soundTouch 是对音调和响度的操作

    int        soundTouchTempoChange;   //速度 <变速不变调> 范围 -50 ~ 100
    int        soundTouchPitch;         //音调  范围 -12 ~ 12
    int        soundTouchRate;          //声音速率 范围 -50 ~ 100
复制代码

变速不变调(TSM)的基本原理

  • 就是把一段音频信号等分成不同的帧,帧的长度大多选取是50ms到100ms之间度,
  • 然后对每个帧进行一系列处理比如拉伸或者压缩
  • 最后在将这些帧重新叠加成合成信号

这里有一篇:https://zhuanlan.zhihu.com/p/101198499 知乎大神的解释

soundTouch

  • 缺点: 能调节的只有这三个参数,效果比较少,难以满足需求
  • 优点:支持变化后的音频导出,在一定需求条件时是调节比较方便

Fmod

Fmod也是C++的库,但是不开源,主要用作游戏声音效果,变声。

  • 官方:https://www.fmod.com/
  • iOSDemo:https://github.com/zhaochengfeng/FMODIOS
  • 安卓Demo:https://github.com/czl0325/VoiceChange-Andorid

知乎大神:https://zhuanlan.zhihu.com/p/46708534

方式一、

iOS 下载后出现各个平台的静态库,可使用

lipo -create path1 path2 -output pathout
复制代码
方式二:

利用cmake根据根据需求合并不同版本。

  • 工具链:https://github.com/leetal/ios-cmake

  • 声音效果文档:https://www.fmod.com/resources/documentation-api?version=2.1&page=core-api-common-dsp-effects.html

常用参数:

  • FMOD_DSP_PITCHSHIFT 音调调节
  • FMOD_DSP_TYPE_FLANGE, //对声音产生法兰效应。
  • FMOD_DSP_TYPE_DELAY 延迟
  • FMOD_DSP_TYPE_ECHO 回音
  • FMOD_DSP_TYPE_TREMOLO 颤音
  • FMOD_DSP_TYPE_FADER 衰减器
  • FMOD_DSP_TYPE_ITLOWPASS 超低通滤波 允许超低音调通过,高音调被过滤或者减弱
  • FMOD_DSP_TYPE_LOWPASS 低通滤波 低通滤波 允许超低音调通过,高音调被过滤或者减弱
  • FMOD_DSP_TYPE_HIGHPASS 高通滤波 高通滤波 允许超低音调通过,低音调被过滤或者减弱
  • FMOD_DSP_TYPE_LIMITER 限幅器 响度控制

更多参数参考:https://www.twblogs.net/a/5d3eebc1bd9eee51fbf8f460/?lang=zh-cn

Fmod使用

  • FmodPlayer定义
typedef struct Fmod_Player{
    FMOD_SYSTEM *system;
    FMOD_SOUND *sound;
    FMOD_CHANNEL *channel;
    FMOD_CHANNELGROUP *channelGroup;
    FMOD_DSP *dsp;
    FMOD_DSP *dsp2;
    FMOD_DSP *dsp3;
    FMOD_DSP *dsp4;
    FMOD_DSP *dsp5;

    float volum;
    int flag;
    bool isMan;
}Fmod_Player;

复制代码
  • 初始化
int play_init(Fmod_Player **play)//初始化
{
    *play = (Fmod_Player *)malloc(sizeof(Fmod_Player));
}
复制代码

为什么用双重指针?

  • 播放文件
int play_start(Fmod_Player *play, const char *name, int flag,bool isGirl)
{
    int err = 0;
    err = FMOD_System_CreateStream(play->system,name, FMOD_3D, 0, &play->sound);
    if(err!=0) return -1;
    
    err = FMOD_Sound_SetMode(play->sound,FMOD_LOOP_OFF);
    if(err != 0) return -1;
    
    err = FMOD_System_PlaySound(play->system, play->sound, play->channelGroup, false, &play->channel);
    
    if(err!=0)return -1;
    play->flag = 1;
    play->isGirl = isGirl;
    
    //设置音效
    fmod_set_audio_effect(flag,isGirl,play->system, play->channel, play->dsp, play->dsp2,play->dsp3,play->dsp4,play->dsp5);
    
    return err;
}
复制代码
  • 播放、暂停
play_continue_pause(player,is_play);
复制代码

is_play : 0暂停,1播放

  • 设置音量
FMOD_Channel_SetVolume(play->channel,n);
复制代码

傅里叶级数与变换

我发现无论是高数考试、还是磨皮算法、隐藏水印、声音变声,都绕不开一个话题,那就是傅里叶,这是简直就是bug一般的存在。

所以没有数学天赋,请绕路。

请找李永乐的视频

傅里叶变换、拉普拉斯变换、Z 变换的联系是什么?为什么要进行这些变换?

img