📚 一、DSP理论回顾
在上一次实验中,我们介绍了如何将音频进行变速播放的算法 Phase Vocoder。本次实验是在其基础上,介绍将音频变调的实现方法。此外我们会简要介绍关于共振峰的概念,让音频变调但不变音色。
1.1 傅里叶变换回顾
连续傅里叶变换:
$$ X(f) = \int_{-\infty}^{+\infty} x(t) \cdot e^{-j2\pi ft} dt $$离散傅里叶变换(DFT):
$$ X[k] = \sum_{n=0}^{N-1} x[n] \cdot e^{-j2\pi kn/N}, \quad k = 0, 1, ..., N-1 $$1.2 短时傅里叶变换(STFT)
语音信号是非平稳信号,其频率特性随时间变化。STFT通过分帧加窗处理,获得时频特性:
- $w[n]$:窗函数(汉宁窗、汉明窗等)
- $R$:帧移(Hop Size)
- $m$:帧索引
- $N$:FFT点数
1.3 Phase Vocoder 相位声码器
Phase Vocoder 是一种基于 STFT 的时频处理技术。在变速实验中,我们通过修改帧移实现时间拉伸:
图1.1 Phase Vocoder 基本流程
- 变速原理:以分析帧移 $R_a$ 分帧,以合成帧移 $R_s$ 重建
- 拉伸因子:$\alpha = R_s / R_a$($\alpha > 1$ 减速,$\alpha < 1$ 加速)
- 相位修正:保证频率连续性,避免相位不连续导致的伪影
🎯 二、实验简介
2.1 什么是变调?
变调(Pitch Shifting)是指改变音频信号的基本频率(基频),从而改变我们听到的音高。
🎹 音乐中的音调
中音C(do)的基频为 261 Hz
中音E(mi)的基频为 330 Hz
mi 比 do 高,因为基频更大
👥 男女声差异
男性基频:85 - 180 Hz
女性基频:165 - 255 Hz
通常 >160Hz 判断为女声
2.2 钢琴音阶频谱对比
图2.1 钢琴中音C(do)和中音E(mi)的频谱图对比
图中可以看到,do 的基频在 261.339 Hz,mi 的基频在 329.607 Hz。除了基频,还能观察到几个波峰,这些被称为谐波,是基频的整数倍。
2.3 男女声频谱对比
图2.2 男女声频谱对比(男性基频约113Hz,女性基频约197Hz)
可以通过调用 f0 = pitch(x, fs) 函数直接得到语音信号基频。(要求MATLAB版本在2018以后)
🗣️ 三、人体发声原理
当我们说话时,空气通过肺部传递到声带,声门的闭合引发空气震动,再传过调音区就形成了语音信号。简单来说,有两个部分:声带(声源区)和过滤器(调音区)。
图3.1 人体发声器官示意图
🫁 动力区
肺部和横膈膜提供气流动力
🔊 声源区
声带振动产生基频,决定音高
🎭 调音区
口腔、咽腔、鼻腔修饰音色
假设大家唱同一首歌的第一个音,音调一样(基频相同),但通过过滤器后,每个人口腔的形状、舌头的位置等都会对音色进行修改,所以区别了每个人不同的说话声音。
即使我们改变了语音信号的基频,将女性声音的音调变得低沉后,其结果也并不太像是男性声音,其原因就是我们没有对过滤器部分进行修改。
📊 四、共振峰 (Formant)
4.1 共振峰的概念
过滤器(调音区)部分区分了每个人不同的音色。描述这一部分的参数被称作共振峰(Formant)。
- 基频(F0):声源部分,决定音高
- 共振峰(F1, F2, F3...):过滤部分,决定音色
二者并无直接关系,但由于口腔内空气的传播造成的共振会和声源部分相互影响,所以共振峰往往出现在谐波附近,这也造成了区分共振峰和谐波的困难。
4.2 不同元音的共振峰
以下显示了分别发出元音【ah】、【ee】、【oo】的频谱图,可以明显看出三个不同元音的共振峰的不同。
图4.1 元音 [AH]、[EE]、[OO] 的口型与频谱对比
4.3 共振峰的限制
人类的发声器官限定了我们的共振峰是有固定范围的:
| 性别 | 元音 i/u 的共振峰范围 |
|---|---|
| 女性 | 600 ~ 2900 Hz |
| 男性 | 500 ~ 2600 Hz |
当我们升高了音调,我们也会升高共振峰。如果超过了正常人类的共振峰范围,那么音频听起来就会像是"小黄人"或者"花栗鼠"这样的音色。
4.4 共振峰修正的思想
怎样才能在升高音调(升高基频)的同时保留共振峰?我们需要共振峰修正。以保留频谱幅度为思想实现保留共振峰的目的。
图4.2 频谱幅度修正原理:(a)原始 → (b)升调拉伸包络 → (c)修正保持原包络
⚙️ 五、PV变调 - 方法一
5.1 基于时间伸缩 + 重采样
在上一次实验中,我们基于 PV 原理对音频实现了变速处理。回忆其流程:相位编码器通过修正每帧相位后,以新的帧移进行重建实现对于音频长度的改变。
如果以 $R_a$ 作为帧移分帧后有 W 帧信号,每帧信号大小为 [U, V],计算频谱并修正相位再还原回时间信号后,每帧的大小仍然是 [U, V],以 $R_s$ 作为新的帧移对 W 帧信号进行合并。
5.2 方法一流程
Phase Vocoder 时间伸缩
使用变速实验的PV算法,改变帧移实现时间拉伸/压缩
重采样恢复原长
通过插值将信号恢复到原始长度,实现频率变化
🔼 升高音调
- PV 拉伸信号($\alpha > 1$)
- 下采样到原长度
- 频率升高,音调上升
🔽 降低音调
- PV 压缩信号($\alpha < 1$)
- 上采样到原长度
- 频率降低,音调下降
🔧 六、PV变调 - 方法二
6.1 基于频谱帧操作
方法二从时间角度对变调进行实现。仍然以 $R_a$ 作为帧移进行分帧,对 W 帧信号计算频谱后,通过对频谱的抽取(减少帧)或复制(增加帧),再反变换回时间信号后,仍然以 $R_a$ 作为帧移进行重建。由于帧数的变化,重建后的信号长度和原始信号的长度不同,此时通过插值还原到原始音频长度,实现变调。
图6.1 方法二:以 α=0.5 为例的频谱帧抽取变调流程
6.2 方法二详细步骤
读入音频信号 x(n)
读取原始音频文件
分帧加窗
以帧长 M、帧移 R = M - L 对信号分帧,乘以窗函数 g(n)
FFT计算每帧频谱
得到频谱矩阵 $|X_1(f)|^2, |X_2(f)|^2, ..., |X_W(f)|^2$
频谱帧操作(以 α=0.5 为例)
每2帧保留1帧进行降调;升调则复制帧
IFFT + OLA重建时域信号
逆变换后使用原始帧移 R 进行重叠相加
插值拉伸回原始长度
信号长度变化后,通过插值恢复原长,频率随之变化
6.3 两种方法对比
| 特性 | 方法一(时间伸缩+重采样) | 方法二(频谱帧操作) |
|---|---|---|
| 核心思想 | 先变速后重采样 | 直接操作频谱帧数 |
| 实现难度 | 较简单,复用PV变速代码 | 需要理解帧操作 |
| 重建帧移 | 使用新帧移 $R_s$ | 使用原帧移 $R_a$ |
🔬 七、频谱幅度修正原理
7.1 为什么需要频谱修正?
如前文所说,修正频谱幅度可以简单实现修正共振峰的目的,达到维持原声音质的效果。
7.2 频谱对比
假设我们有原始音频 orig2.wav,可以看到它的共振峰谱图如下:
图7.1 原始音频频谱(Fundamental标记基频,F标记共振峰位置)
假若我们升高了音调,基频和共振峰的位置同时向右偏移,可以看到共振峰的波形相比原始要宽:
图7.2 升高音调后的频谱(基频右移,共振峰包络被拉伸)
修正共振峰使得波形和原始一致,最终目的是基频向右升高,共振峰包络不变:
图7.3 修正后频谱(基频升高,但共振峰包络保持原始位置)
7.3 频谱修正算法流程
- 分析阶段:对原始音频信号分帧加窗后得到每帧信号的频谱,如图A所示
- 求包络:求得每帧信号的包络,如图A中F折线所示
- 计算残差:用每帧信号的频谱除以包络得到消除共振峰后的语音频谱残留
- 重构包络:根据变调因子和第2步中的包络重构F折线,如图C中F折线所示
- 合成输出:将第3步中的语音频谱残留乘以第4步中的重构包络得到图C语音信号
7.4 包络提取方法(拓展知识)
LPC(线性预测编码)
假设当前采样点可以由前若干个采样点线性预测:
$\hat{x}[n] = \sum_{k=1}^{p} a_k \cdot x[n-k]$
[a, g] = lpc(frame, p);
[H, w] = freqz(g, a, nfft);
envelope = abs(H);
倒谱法(Cepstrum)
频谱取对数后再做傅里叶逆变换:
$c[n] = IFFT\{log|FFT\{x[n]\}|\}$
X = fft(frame);
ceps = ifft(log(abs(X)+eps));
% 低通滤波后变换回频域
📝 八、实验总结
8.1 本次实验内容
🎵 基频与音调
理解基频决定音高
男女声频率差异
🗣️ 发声原理
源-滤波器模型
声源区 vs 调音区
📊 共振峰
音色的决定因素
"小黄人"效应
8.2 两种变调方法
方法一
PV时间伸缩 → 重采样
使用新帧移 $R_s$ 重建
方法二
频谱帧抽取/复制 → 插值
使用原帧移 $R_a$ 重建
8.3 学习目标
- 理解音频基频与音调的关系
- 掌握 Phase Vocoder 变调算法原理
- 理解共振峰(Formant)的概念及其作用
- 实现频谱幅度修正以保持音色
- 推荐使用汉宁窗(Hanning Window),窗长1024,帧移256
- 变调因子 $\alpha$:$\alpha > 1$ 升调,$\alpha < 1$ 降调
- 注意处理频率超出奈奎斯特频率的情况