wavenet_vocoder(预处理MFCC特征提取代码段分析)

从加载进来音频开始看起,前面制作路径列表就不在细述了

wav = audio.load_wav(wav_path)

if hparams.rescaling:
    wav = wav / np.abs(wav).max() * hparams.rescaling_max

首先遇到hparams.rescaling_max=0.99,即wav /  wav内元素绝对值中的最大值,将使得所有元素范围在(-1,1),相当于做个归一化。

    if is_mulaw_quantize(hparams.input_type):
        # [0, quantize_channels)
        out = P.mulaw_quantize(wav, hparams.quantize_channels)

        # Trim silences
        start, end = audio.start_and_end_indices(out, hparams.silence_threshold)
        wav = wav[start:end]
        out = out[start:end]
        constant_values = P.mulaw_quantize(0, hparams.quantize_channels)
        out_dtype = np.int16
    elif is_mulaw(hparams.input_type):
        # [-1, 1]
        out = P.mulaw(wav, hparams.quantize_channels)
        constant_values = P.mulaw(0.0, hparams.quantize_channels)
        out_dtype = np.float32
    else:
        # [-1, 1]
        out = wav
        constant_values = 0.0
        out_dtype = np.float32

这段代码用来判断是否压缩,静音处理。如果输入参数input_type为mulaw_quantize则需要量化、压缩、静音过滤处理。如果为mulaw则进行只压缩处理。如果是raw则输入原音频,不做处理。这里的参数为raw。

调试证明mulaw_quantize时,量化后的输出out取值在[717-65533],因为静音阈值设置为2,代码要求量化值减去127要大于阈值。参数为mulaw和raw时取值为[-1,1]

 mel_spectrogram = audio.melspectrogram(wav).astype(np.float32).T

接下来遇到这个代码,melspectrogram这个函数是个硬骨头,得慢慢啃。这里主要是一段实现MFCC的过程建议大家到网上浏览下MFCC的实现流程。这里大概说下流程:

先对语音进行预加重、分帧和加窗;对每一个短时分析窗,通过FFT得到对应的频谱;将上面的频谱通过Mel滤波器组得到Mel频谱;在Mel频谱上面进行倒谱分析(取对数,做逆变换,实际逆变换一般是通过DCT离散余弦变换来实现,取DCT后的第2个到第13个系数作为MFCC系数),获得Mel频率倒谱系数MFCC  。详细可以读读原文。 (原文链接:https://blog.csdn.net/zouxy09/article/details/9156785)
 

def melspectrogram(y):
    D = _lws_processor().stft(y).T
    S = _amp_to_db(_linear_to_mel(np.abs(D))) - hparams.ref_level_db
    if not hparams.allow_clipping_in_normalization:
        assert S.max() <= 0 and S.min() - hparams.min_level_db >= 0
    return _normalize(S)

def get_hop_size():
    hop_size = hparams.hop_size
    if hop_size is None:
        assert hparams.frame_shift_ms is not None
        hop_size = int(hparams.frame_shift_ms / 1000 * hparams.sample_rate)
    return hop_size

def _lws_processor():
    return lws.lws(hparams.fft_size, get_hop_size(), mode="speech")

def _build_mel_basis():
    assert hparams.fmax <= hparams.sample_rate // 2
    return librosa.filters.mel(hparams.sample_rate, hparams.fft_size,
                               fmin=hparams.fmin, fmax=hparams.fmax,
                               n_mels=hparams.num_mels)    #构造一个梅尔滤波器组

def _linear_to_mel(spectrogram):
    global _mel_basis
    if _mel_basis is None:
        _mel_basis = _build_mel_basis()
    return np.dot(_mel_basis, spectrogram)

def _amp_to_db(x):
    min_level = np.exp(hparams.min_level_db / 20 * np.log(10))
    return 20 * np.log10(np.maximum(min_level, x))

def _normalize(S):
    return np.clip((S - hparams.min_level_db) / -hparams.min_level_db, 0, 1)

首先说明,本次debug下的输入音频y的尺度为(212893, ),后续需要对比一些变化,第一个用到了lws下的get_hop_size()函数,该函数主要是构造分帧时的移动步长,参数hparams.hop_size=256,该函数返回的值也是256,即后续移动步长为256。

至于lws.lws()这个函数没有找到源代码,不过根据MFCC实现过程来看,这里是实现了加窗和分帧的操作。

接下来是个短时傅里叶函数,MFCC的第二步。经过短时傅里叶stft函数后咱们拿到了频谱D,D次数的尺度是(513,835),也就是835个帧,每帧513个样点,步长为256,每次向前移动256,帧与帧之间重合样点513-256,这样算出来的总长度是略大于输入y的,但是由于stft这个函数源代码看不到,可能是中间有补零或者其他什么操作吧。

现在的D便是我们想要的频谱。之后我们需要使用mel滤波器得到mel频谱。

_linear_to_mel(np.abs(D))

先求个绝对值,然后便转到了_build_mel_basis()函数这里,librosa.filters.mel()就是用来构造梅尔滤波器的函数,具体函数用法可以Baidu一下。这里咱们输入的梅尔滤波器函数个数的参数为80,也就是将产生80个梅尔滤波器,注意梅尔滤波器的个数是可以和频谱个数不同的,这里将产生的mel系数为(80,513),之后将梅尔系数和频谱点乘,得到我们的mel频谱(80,835)。第三步的MFCC完成。

之后是_amp_to_db函数,该函数应该就是实现了将mel频谱转换到倒谱上,然后求倒谱系数的过程。(好吧,我承认这里我是懵逼的,一堆数学公式真的看不懂。。。。)

最后的_normalize(S)函数是用来归一化的。。。

后续的代码便是保存原音频的npy数据,保存MFCC特征的npy数据,也不再细述。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值