音频变速python版

音频变速

如何能在不改变音频其他特点的情况下,只改变语速呢?

有几个python的库可以实现该功能,下面一一介绍。

pydub库

首先,确保安装了pydub和ffmpeg。

下面是一个简单的Python脚本,展示如何改变音频的播放速度:

python 复制代码
from pydub import AudioSegment
from pydub.playback import play


def change_speed(audio_file, speed=1.0):
    sound = AudioSegment.from_file(audio_file)
    # 增加速度
    sound_with_altered_speed = sound._spawn(sound.raw_data, overrides={
         "frame_rate": int(sound.frame_rate * speed)
    }).set_frame_rate(sound.frame_rate)
    return sound_with_altered_speed

# 加载音频文件
audio_path = "your_audio_file.mp3"
# 改变速度,例如1.5倍速
altered_sound = change_speed(audio_path, speed=1.5)
# 播放修改后的音频
play(altered_sound)
# 导出音频
altered_sound.export("modified_audio.mp3", format="mp3")

change_speed函数接受原始音频文件路径和速度因子。通过修改帧率来改变速度。如果你想要加快速度,可以将速度因子设置为大于1的值;如果想要减慢速度,将其设置为小于1的值。

但是该方法在改变语音的同时,使得音调也发生改变。

librosa库

librosa主要用于音乐和音频分析。它支持音频的时间伸缩(即改变音频速度而不改变音调),并且提供了许多其他音频处理功能。

实现代码:

python 复制代码
import librosa
import soundfile as sf

audio_path = 'your_audio_file.wav'
y, sr = librosa.load(audio_path, sr=None)  # sr=None 保持原始采样率

# 变速处理,比如加速1.5倍
y_change = librosa.effects.time_stretch(y, 1.5)
#保存
sf.write('output_audio_file.wav', y_change, sr)

在改变音频速度的同时保持原有音调,librosa使用了时间拉伸算法(Time Stretching)。

librosa.effects.time_stretch函数是用于调整音频的播放速度,同时不改变音频的音高(音调)。

我们看下这个函数源码:

python 复制代码
def time_stretch(y, rate, **kwargs):
    '''Time-stretch an audio series by a fixed rate.'''
  
    if rate <= 0:
        raise ParameterError('rate must be a positive number')

    # Construct the short-term Fourier transform (STFT)
    stft = core.stft(y, **kwargs)

    # Stretch by phase vocoding
    stft_stretch = core.phase_vocoder(stft, rate)

    # Predict the length of y_stretch
    len_stretch = int(round(len(y)/rate))

    # Invert the STFT
    y_stretch = core.istft(
        stft_stretch, dtype=y.dtype, length=len_stretch, **kwargs)

    return y_stretch

可以看到,该函数主要包含三个步骤:

1.音频的频谱表示

首先,librosa.effects.time_stretch利用短时傅里叶变换(STFT)将音频信号从时间域转换到频域。这种转换将音频分解成其组成的频率成分,每个成分都有相应的幅度和相位。

2.相位估计(phase_vocoder)

在进行时间伸缩处理时,保持相位连续性是一个重要的挑战。librosa采用了相位估计技术来调整每个频率成分的相位,以保证在变速过程中音频信号的相位连续性。这是通过相位重构实现的,确保在变速后的音频中,所有频率成分的相位都能正确对齐。

3.相位恢复和重构,重建音频

处理相位信息时,使用相位展开技术,从原始音频中提取和修改相位信息,然后在处理过程中适当调整这些信息以匹配新的时间伸缩率。

最后,将处理过的频谱数据通过逆短时傅里叶变换(ISTFT)重新转换回时间域,生成最终的音频输出。在这一步中,经过调整的幅度和重构的相位信息被合成,以产生时间伸缩后的音频信号。

补充:相位声码器Phase vocoder

相位声码器(phase vocoder)是一种特殊的声码器,用于分析和修改音频信号的频谱相位。它是在数字信号处理中广泛使用的一种工具,特别适用于时间伸缩(改变音频速度而不改变音调)和音高移动(改变音调而不改变速度)。

相位声码器技术可以实现音频的时间伸缩。这一技术是基于频域处理,它可以调整音频的时长而不改变音高,主要依靠精确的相位处理。

先看看源码:

python 复制代码
def phase_vocoder(D, rate, hop_length=None):
    """Phase vocoder.  Given an STFT matrix D, speed up by a factor of `rate`

    Based on the implementation provided by [1]_.

    .. note:: This is a simplified implementation, intended primarily for
             reference and pedagogical purposes.  It makes no attempt to
             handle transients, and is likely to produce many audible
             artifacts.  For a higher quality implementation, we recommend
             the RubberBand library [2]_ and its Python wrapper `pyrubberband`.

    .. [1] Ellis, D. P. W. "A phase vocoder in Matlab."
        Columbia University, 2002.
        http://www.ee.columbia.edu/~dpwe/resources/matlab/pvoc/

    .. [2] https://breakfastquay.com/rubberband/

    Parameters
    ----------
    D : np.ndarray [shape=(d, t), dtype=complex]
        STFT matrix

    rate :  float > 0 [scalar]
        Speed-up factor: `rate > 1` is faster, `rate < 1` is slower.

    hop_length : int > 0 [scalar] or None
        The number of samples between successive columns of `D`.

        If None, defaults to `n_fft/4 = (D.shape[0]-1)/2`

    Returns
    -------
    D_stretched : np.ndarray [shape=(d, t / rate), dtype=complex]
        time-stretched STFT

    See Also
    --------
    pyrubberband
    """

    n_fft = 2 * (D.shape[0] - 1)

    if hop_length is None:
        hop_length = int(n_fft // 4)

    time_steps = np.arange(0, D.shape[1], rate, dtype=np.float)

    # Create an empty output array
    d_stretch = np.zeros((D.shape[0], len(time_steps)), D.dtype, order='F')

    # Expected phase advance in each bin
    phi_advance = np.linspace(0, np.pi * hop_length, D.shape[0])

    # Phase accumulator; initialize to the first sample
    phase_acc = np.angle(D[:, 0])

    # Pad 0 columns to simplify boundary logic
    D = np.pad(D, [(0, 0), (0, 2)], mode='constant')

    for (t, step) in enumerate(time_steps):

        columns = D[:, int(step):int(step + 2)]

        # Weighting for linear magnitude interpolation
        alpha = np.mod(step, 1.0)
        mag = ((1.0 - alpha) * np.abs(columns[:, 0])
               + alpha * np.abs(columns[:, 1]))

        # Store to output array
        d_stretch[:, t] = mag * np.exp(1.j * phase_acc)

        # Compute phase advance
        dphase = (np.angle(columns[:, 1])
                  - np.angle(columns[:, 0])
                  - phi_advance)

        # Wrap to -pi:pi range
        dphase = dphase - 2.0 * np.pi * np.round(dphase / (2.0 * np.pi))

        # Accumulate phase
        phase_acc += phi_advance + dphase

    return d_stretch

直接调用调用phase_vocoder来实现时间伸缩。这里是一个简单的示例:

python 复制代码
import librosa

# 加载音频数据
y, sr = librosa.load('audio_file.wav', sr=None)

# 计算STFT
D = librosa.stft(y)

# 应用相位声码器进行时间伸缩
D_stretched = librosa.core.phase_vocoder(D, rate=1.5)

# 通过逆STFT重构音频
y_stretched = librosa.istft(D_stretched)

基本原理:

相关推荐
databook10 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar11 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户83562907805112 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_12 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机18 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机19 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机19 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机19 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i20 小时前
drf初步梳理
python·django
每日AI新事件20 小时前
python的异步函数
python