Python语音基础操作--7.1帧合并

《语音信号处理试验教程》(梁瑞宇等)的代码主要是Matlab实现的,现在Python比较热门,所以把这个项目大部分内容写成了Python实现,大部分是手动写的。使用CSDN博客查看帮助文件:

Python语音基础操作–2.1语音录制,播放,读取
Python语音基础操作–2.2语音编辑
Python语音基础操作–2.3声强与响度
Python语音基础操作–2.4语音信号生成
Python语音基础操作–3.1语音分帧与加窗
Python语音基础操作–3.2短时时域分析
Python语音基础操作–3.3短时频域分析
Python语音基础操作–3.4倒谱分析与MFCC系数
Python语音基础操作–4.1语音端点检测
Python语音基础操作–4.2基音周期检测
Python语音基础操作–4.3共振峰估计
Python语音基础操作–5.1自适应滤波
Python语音基础操作–5.2谱减法
Python语音基础操作–5.4小波分解
Python语音基础操作–6.1PCM编码
Python语音基础操作–6.2LPC编码
Python语音基础操作–6.3ADPCM编码
Python语音基础操作–7.1帧合并
Python语音基础操作–7.2LPC的语音合成
Python语音基础操作–10.1基于动态时间规整(DTW)的孤立字语音识别试验
Python语音基础操作–10.2隐马尔科夫模型的孤立字识别
Python语音基础操作–11.1矢量量化(VQ)的说话人情感识别
Python语音基础操作–11.2基于GMM的说话人识别模型
Python语音基础操作–12.1基于KNN的情感识别
Python语音基础操作–12.2基于神经网络的情感识别
Python语音基础操作–12.3基于支持向量机SVM的语音情感识别
Python语音基础操作–12.4基于LDA,PCA的语音情感识别

代码可在Github上下载busyyang/python_sound_open

语音合成主要可分为波形合成法,参数合成法,规则合成法。

  • 波形合成法
    • 波形编码合成,直接把需要合成的语音通过编码的形式进行存储,称为PCM合成。
    • 波形编辑合成,通过在音库中采取语音的合成单元波形,对这些波形进行编辑拼接后输出。
  • 参数合成法
    • 分析法:提取语音参数,压缩存储量,然后人工控制这些参数的生成。
  • 规则法
    • 通过语音学规则产生语音。系统中最小语音单位的声学参数,以及由音素组成音节,由音节组成词,由词组成句子。

帧合并

分帧处理后,需要将多个帧合并起来,涉及的操作有去创函数和去交叠操作。方法为:

  • 通过IFFT把一帧频域数据转化为时域数据。
  • 将一组激励脉冲通过一个滤波器。

常用的三种数据叠加方法为重叠相加法,重叠存储法,线性比例重叠相加法。

重叠相加法

假设信号长度为 N 1 N_1 N1,窗函数 h ( n ) h(n) h(n)的长度为 N N N,每帧的信号 x i ( n ) x_i(n) xi(n)长度为 M M M,将每帧信号与窗函数后面补零,使得长度都为 N + M − 1 N+M-1 N+M1,得到 x ^ i ( n ) \hat x_i(n) x^i(n) h ^ ( n ) \hat h(n) h^(n)。计算 x ^ i ( n ) \hat x_i(n) x^i(n) h ^ ( n ) \hat h(n) h^(n)的卷积结果,可以使用FFT和IFFT来计算结果。卷积结果 y ( n ) y(n) y(n)的长度为N+M-1,把重叠部分相加,与不重叠部分共同构成输出。把重叠相加推广到时域,信号 x ( n ) x(n) x(n)是分帧的,每帧为:
x i ( m ) = { x ( n ) , ( i − 1 ) Δ L + 1 ⩽ n ⩽ i Δ L + L 0 , 其 他 , m ∈ [ 1 , L ] x_i(m)=\left \{\begin{array}{ll} x(n)&,(i-1)\Delta L+1 \leqslant n \leqslant i\Delta L +L\\ 0&,其他 \end{array} \right.,m\in [1,L] xi(m)={x(n)0,(i1)ΔL+1niΔL+L,,m[1,L]

y i − 1 ( m ) y_{i-1}(m) yi1(m) y i ( m ) y_{i}(m) yi(m)有M个样点重叠,重叠部分为 ( i − 1 ) Δ L + 1 到 ( i − 1 ) Δ L + M (i-1)\Delta L+1 到 (i-1)\Delta L +M (i1)ΔL+1(i1)ΔL+M,输出为:
y ( n ) = { y ( n ) , n ⩽ ( i − 1 ) Δ L y ( n ) + y i ( m ) , ( i − 1 ) Δ L + 1 ⩽ n ⩽ ( i − 1 ) Δ L + M , M ∈ [ 1 , M ] y i ( m ) , ( i − 1 ) Δ L + 1 + M ⩽ n ⩽ ( i − 1 ) Δ L + L , M ∈ [ M + 1 , L ] y(n)=\left \{\begin{array}{ll} y(n)&,n\leqslant (i-1)\Delta L\\ y(n)+y_i(m)&,(i-1)\Delta L+1 \leqslant n \leqslant (i-1)\Delta L +M,M\in[1,M]\\ y_i(m)&,(i-1)\Delta L+1+M \leqslant n \leqslant (i-1)\Delta L+L,M\in[M+1,L] \end{array} \right. y(n)=y(n)y(n)+yi(m)yi(m),n(i1)ΔL,(i1)ΔL+1n(i1)ΔL+M,M[1,M],(i1)ΔL+1+Mn(i1)ΔL+L,M[M+1,L]

重叠存储法

重叠存储法是分帧数据在前面补零达到N+M-1的长度。FFT后只取后面M个样本点,输出到输出序列上。
y ( n ) = { y ( n ) , n ⩽ ( i − 1 ) Δ L y i ( m ) , ( i − 1 ) Δ L + 1 ⩽ n ⩽ ( i − 1 ) Δ L + M , M ∈ [ 1 , Δ L ] y(n)=\left \{\begin{array}{ll} y(n)&,n\leqslant (i-1)\Delta L\\ y_i(m)&,(i-1)\Delta L+1 \leqslant n \leqslant (i-1)\Delta L +M,M\in[1,\Delta L]\\ \end{array} \right. y(n)={y(n)yi(m),n(i1)ΔL,(i1)ΔL+1n(i1)ΔL+M,M[1,ΔL]

线性比例重叠相加

如果前一帧和下一帧的变化较大,那么用重叠相加法就不合适了。可以将重叠部分进行比例计权后相加。假设重叠部分长度为M,两个斜三角的窗函数 w 1 ( n ) = ( n − 1 ) / M w_1(n)=(n-1)/M w1(n)=(n1)/M w 2 ( n ) = ( M − n ) / M w_2(n)=(M-n)/M w2(n)=(Mn)/M n ∈ [ 1 , M ] n\in [1,M] n[1,M]

如果前一帧的重叠部分为 y 1 y_1 y1,后一帧的重叠部分为 y 2 y_2 y2。那么 y ( n ) = y 1 ( n ) w 1 ( n ) + y 2 ( n ) w 2 ( n ) y(n)=y_1(n)w_1(n)+y_2(n)w_2(n) y(n)=y1(n)w1(n)+y2(n)w2(n)

y ( n ) = { y ( n ) , n ⩽ ( i − 1 ) Δ L y ( n ) w 2 ( n ) + y i ( m ) w 1 ( n ) , ( i − 1 ) Δ L + 1 ⩽ n ⩽ ( i − 1 ) Δ L + M , M ∈ [ 1 , M ] y i ( m ) , ( i − 1 ) Δ L + 1 + M ⩽ n ⩽ ( i − 1 ) Δ L + L , M ∈ [ M + 1 , L ] y(n)=\left \{\begin{array}{ll} y(n)&,n\leqslant (i-1)\Delta L\\ y(n)w_2(n)+y_i(m)w_1(n)&,(i-1)\Delta L+1 \leqslant n \leqslant (i-1)\Delta L +M,M\in[1,M]\\ y_i(m)&,(i-1)\Delta L+1+M \leqslant n \leqslant (i-1)\Delta L+L,M\in[M+1,L] \end{array} \right. y(n)=y(n)y(n)w2(n)+yi(m)w1(n)yi(m),n(i1)ΔL,(i1)ΔL+1n(i1)ΔL+M,M[1,M],(i1)ΔL+1+Mn(i1)ΔL+L,M[M+1,L]

import numpy as np


def Filpframe_OverlapA(x, win, inc):
    """
    基于重叠相加法的信号还原函数
    :param x: 分帧数据
    :param win: 窗
    :param inc: 帧移
    :return:
    """
    nf, slen = x.shape
    nx = (nf - 1) * inc + slen
    frameout = np.zeros(nx)
    x = x / win
    for i in range(nf):
        start = i * inc
        frameout[start:start + slen] += x[i, :]
    return frameout


def Filpframe_OverlapS(x, win, inc):
    """
    基于重叠存储法的信号还原函数
    :param x: 分帧数据
    :param win: 窗
    :param inc: 帧移
    :return:
    """
    nf, slen = x.shape
    nx = (nf - 1) * inc + slen
    frameout = np.zeros(nx)
    x = x / win
    for i in range(nf):
        frameout[slen + (i - 1) * inc:slen + i * inc] += x[i, slen - inc:]
    return frameout


def Filpframe_LinearA(x, win, inc):
    """
    基于比例重叠相加法的信号还原函数
    :param x: 分帧数据
    :param win: 窗
    :param inc: 帧移
    :return:
    """
    nf, slen = x.shape
    nx = (nf - 1) * inc + slen
    frameout = np.zeros(nx)
    overlap = len(win) - inc
    x = x / win
    w1 = [i / overlap for i in range(overlap)]
    w2 = [i / overlap for i in range(overlap - 1, -1, -1)]
    for i in range(nf):
        if i == 0:
            frameout[:slen] = x[i, :]
        else:
            M = slen + (i - 1) * inc
            y = frameout[M - overlap:M] * w2 + x[i, :overlap] * w1
            xn = x[i, overlap:]
            yy = np.hstack((y, xn))
            frameout[M - overlap:M - overlap + slen] += yy
    return frameout

from chapter2_基础.soundBase import *
from chapter7_语音合成.flipframe import *
from chapter3_分析实验.C3_1_y_1 import enframe

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

data, fs = soundBase('C7_1_y.wav').audioread()

wlen = 256
wnd = np.hamming(wlen)
overlap = 100
f = enframe(data, wnd, overlap)
plt.figure(figsize=(14, 12))
# 7.1.1
fn_overlap = Filpframe_OverlapA(f, wnd, overlap)
plt.subplot(3, 2, 1)
plt.plot(data / np.max(np.abs(data)), 'k')
plt.title('原始信号')
plt.subplot(3, 2, 2)
plt.title('还原信号-重叠相加法')
plt.plot(fn_overlap / np.max(np.abs(fn_overlap)), 'c')

# 7.1.2
fn_s = Filpframe_OverlapS(f, wnd, overlap)
plt.subplot(3, 2, 3)
plt.plot(data / np.max(np.abs(data)), 'k')
plt.title('原始信号')
plt.subplot(3, 2, 4)
plt.title('还原信号-重叠存储法')
plt.plot(fn_s / np.max(np.abs(fn_s)), 'c')

# 7.1.3
fn_l = Filpframe_LinearA(f, wnd, overlap)
plt.subplot(3, 2, 5)
plt.plot(data / np.max(np.abs(data)), 'k')
plt.title('原始信号')
plt.subplot(3, 2, 6)
plt.title('还原信号-线性叠加法')
plt.plot(fn_l / np.max(np.abs(fn_l)), 'c')

plt.savefig('images/flipframe.png')
plt.close()

在这里插入图片描述

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值