【问题标题】:slow down spoken audio (not from mp3/wav) using python使用 python 减慢语音音频(不是来自 mp3/wav)
【发布时间】:2020-02-12 18:49:13
【问题描述】:

我需要减慢通过麦克风捕获的短时间的语音突发,然后在 python 脚本中实时播放。我可以使用 PyAudio 的输入和输出流在不改变速度的情况下捕获和播放音频,但我不知道如何减慢它的速度。

我看到 this post 使用 pydub 对来自文件的音频做了类似的事情,但不知道如何为我的目的修改它。

只是为了强调问题标题中的关键点,“(不是来自 mp3/wav 或任何其他文件类型)”,因为我想在 实时 短脉冲,理想情况下 所以只想处理从 PyAudio 流中读取的数据。

有使用 pydub 经验的人知道它是否可以满足我的需要吗?

注意,我意识到输出会越来越落后,并且可能存在缓冲问题,但是我只是在长达 30 秒的短暂时间内这样做,并且只想将语音速度减慢约 10%。

【问题讨论】:

标签: python audio


【解决方案1】:

所以事实证明它非常非常简单。

查看pydubpyaudio 代码库后,我意识到,与输入音频流(麦克风)相比,只需为输出音频流(扬声器)上的“rate”参数指定一个较低的值即可) stream.write() 函数会为我处理它。

我一直期望需要对原始数据进行物理操作才能将数据转换为更大的缓冲区。

这是一个简单的例子:

import pyaudio

FORMAT = pyaudio.paInt16
CHANNELS = 1
FRAME_RATE = 44100
CHUNK = 1024*4

# simply modify the value for the 'rate' parameter to change the playback speed
# <1 === slow down;  >1 === speed up
FRAMERATE_OFFSET = 0.8

audio = pyaudio.PyAudio()

#output stream
stream_out = audio.open(format=FORMAT,
                        channels=CHANNELS,
                        rate= int(FRAME_RATE * FRAMERATE_OFFSET),
                        output=True)

# open input steam to start recording mic audio
stream_in = audio.open(format=FORMAT, 
                       channels=CHANNELS,
                       rate=FRAME_RATE, 
                       input=True)

for i in range(1):
    # modify the chunk multiplier below to captyre longer time durations
    data = stream_in.read(CHUNK*25)
    stream_out.write(data)

stream_out.stop_stream()
stream_out.close()
audio.terminate()

为了实现这个操作,我需要设置一个共享内存数据缓冲区并设置一个子进程来处理输出,这样我就不会错过输入信号中的任何重要内容。

【讨论】:

    【解决方案2】:

    这就是我所做的。

    import wave
    channels = 1
    swidth = 2
    multiplier = 0.2
    
    spf = wave.open('flute-a4.wav', 'rb')
    fr=spf.getframerate() # frame rate
    signal = spf.readframes(-1)
    
    wf = wave.open('ship.wav', 'wb')
    wf.setnchannels(channels)
    wf.setsampwidth(swidth)
    wf.setframerate(fr*multiplier)
    wf.writeframes(signal)
    wf.close()
    

    我用这个repo的长笛。

    【讨论】:

    • 与我给 Arthur 的评论相同,我明确表示我不想使用任何文件。
    【解决方案3】:

    如 cmets 中所述,通过简单地增加或减少采样频率/帧速率,您可以加速减速音频。虽然如果您打算通过麦克风实时进行录制,其中一个想法是在几秒钟内录制,播放放慢的音频,然后再次进行录制。

    这是一个使用 sounddevice 的示例,这基本上是我的回答 here 的轻微修改。 我们循环录制音频 4 秒 3 次,并立即播放帧速率偏移(> 1 表示加速,

    import sounddevice as sd
    import numpy as np
    import scipy.io.wavfile as wav
    import time
    
    fs=44100
    duration = 4  # seconds
    #fs_offset = 1.3 #speedup
    fs_offset = 0.8 #speedup slow down
    
    for count in range(1,4):
        myrecording = sd.rec(duration * fs, samplerate=fs, channels=2, dtype='float64')
        print "Recording Audio chunk {} for {} seconds".format(count, duration)
        sd.wait()
        print "Recording complete, Playing chunk {} with offset {} ".format(count, fs_offset)
        sd.play(myrecording, fs * fs_offset)
        sd.wait()
        print "Playing chunk {} Complete".format(count)
        time.sleep(1)
    

    输出:

    $python sdaudio.py
    Recording Audio chunk 1 for 4 seconds
    Recording complete, Playing chunk 1 with offset 0.8 
    Playing chunk 1 Complete
    Recording Audio chunk 2 for 4 seconds
    Recording complete, Playing chunk 2 with offset 0.8 
    Playing chunk 2 Complete
    Recording Audio chunk 3 for 4 seconds
    Recording complete, Playing chunk 3 with offset 0.8 
    Playing chunk 3 Complete
    

    这是一个使用 PyAudio 从麦克风录音和 pydub 进行回放的示例。尽管您也可以使用 pyaudio 阻塞线功能来修改传出音频。我使用了 pydub,因为您提到了基于 pydub 的解决方案。这是来自here的代码模组。

    import pyaudio
    import wave
    from pydub import AudioSegment
    from pydub.playback import play
    import time
    
    FORMAT = pyaudio.paInt16
    CHANNELS = 2
    RATE = 44100
    CHUNK = 1024
    RECORD_SECONDS = 4
    #FRAMERATE_OFFSET = 1.4  #speedup
    FRAMERATE_OFFSET = 0.7 #slowdown
    WAVE_OUTPUT_FILENAME = "file.wav"
    
    def get_audio():
    
        audio = pyaudio.PyAudio()
    
        # start Recording
        stream = audio.open(format=FORMAT, channels=CHANNELS,
                        rate=RATE, input=True,
                        frames_per_buffer=CHUNK)
        frames = []
    
        for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
            data = stream.read(CHUNK)
            frames.append(data)
    
        # stop Recording
        stream.stop_stream()
        stream.close()
        audio.terminate()
    
        #save to file
        waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
        waveFile.setnchannels(CHANNELS)
        waveFile.setsampwidth(audio.get_sample_size(FORMAT))
        waveFile.setframerate(RATE * FRAMERATE_OFFSET)
        waveFile.writeframes(b''.join(frames))
        waveFile.close()
    
    
    for count in range(1,4):
        print "recording segment {} ....".format(count)
        frame_array = get_audio()
        print "Playing segment {} .... at offset {}".format(count, FRAMERATE_OFFSET)
        audio_chunk = AudioSegment.from_wav(WAVE_OUTPUT_FILENAME)
        print "Finished playing segment {} .... at offset {}".format(count, FRAMERATE_OFFSET)
        play(audio_chunk)
        time.sleep(1)
    

    输出:

    $python slowAudio.py 
    recording segment 1 ....
    Playing segment 1 .... at offset 0.7
    Finished playing segment 1 .... at offset 0.7
    recording segment 2 ....
    Playing segment 2 .... at offset 0.7
    Finished playing segment 2 .... at offset 0.7
    recording segment 3 ....
    Playing segment 3 .... at offset 0.7
    

    【讨论】:

    • 感谢 Anil,我非常感谢详细的回复,但是正如我在问题标题中所说,我不想使用文件。这是因为我需要以接近实时的方式执行此操作,并且为 0.1 秒的音频突发之类的写入/读取文件的开销使其无法使用。我希望这将是类似于 AudioSegment.from_wav() 的东西,它将在内存数据缓冲区上运行。这就是我需要的。
    【解决方案4】:

    这个问题已经回答here

    from pydub import AudioSegment
    sound = AudioSegment.from_file(…)
    
    def speed_change(sound, speed=1.0):
        # Manually override the frame_rate. This tells the computer how many
        # samples to play per second
        sound_with_altered_frame_rate = sound._spawn(sound.raw_data, overrides={
            "frame_rate": int(sound.frame_rate * speed)
        })
    
        # convert the sound with altered frame rate to a standard frame rate
        # so that regular playback programs will work right. They often only
        # know how to play audio at standard frame rate (like 44.1k)
        return sound_with_altered_frame_rate.set_frame_rate(sound.frame_rate)
    
    slow_sound = speed_change(sound, 0.75)
    fast_sound = speed_change(sound, 2.0)
    

    【讨论】:

    • 谢谢,但是我在标题中明确指出我不想从 wav/mp3 文件中读取。我将更新问题正文以强调这一点。
    • ogg_version = AudioSegment.from_ogg("never_gonna_give_you_up.ogg") *** flv_version = AudioSegment.from_flv("never_gonna_give_you_up.flv") *** mp4_version = AudioSegment.from_file("never_gonna_give_you_up.mp4", "mp4") *** wma_version = AudioSegment.from_file("never_gonna_give_you_up.wma", "wma") *** aac_version = AudioSegment.from_file("never_gonna_give_you_up.aiff", "aac")
    • 抱歉没有更清楚,我再次编辑了 OP,我想处理实时流数据,根本不使用 任何 文件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 2012-02-10
    • 2014-05-31
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    相关资源
    最近更新 更多