如何高效地将gtts音频转换为pydub音频片段?

4

我想在pydub中操作gtts音频,但不确定如何将gtts文件转换为pydub音频。

我知道可以将Google Text to Speech音频转换为mp3格式,也知道可以使用pydub导入mp3文件,但这种方法效率低下。有没有一种方法可以跳过创建mp3文件并直接处理音频呢?

我尝试将gtts文件作为参数传递给AudioSegment.from_mp3(),但我相当确定它需要的是一个字符串。

from gtts import gTTS
from io import BytesIO
from pydub import AudioSegment

mp3_fp = BytesIO()
tts = gTTS('hello', 'en')
tts.write_to_fp(mp3_fp)
song = AudioSegment.from_mp3(mp3_fp)

我遇到了一个"CouldntDecodeError"错误:
  File "C:\ProgramData\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "C:/Users/py/ex/gtts_test.py", line 18, in <module>
    song = AudioSegment.from_mp3(mp3_fp)

  File "C:\ProgramData\Anaconda3\lib\site-packages\pydub\audio_segment.py", line 716, in from_mp3
    return cls.from_file(file, 'mp3', parameters=parameters)

  File "C:\ProgramData\Anaconda3\lib\site-packages\pydub\audio_segment.py", line 704, in from_file
    p.returncode, p_err))

CouldntDecodeError: Decoding failed. ffmpeg returned error code: 1

Output from ffmpeg/avlib:

b'ffmpeg version 4.1.1 Copyright (c) 2000-2019 the FFmpeg developers\r\n  built with gcc 8.2.1 (GCC) 20190212\r\n  configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth\r\n  libavutil      56. 22.100 / 56. 22.100\r\n  libavcodec     58. 35.100 / 58. 35.100\r\n  libavformat    58. 20.100 / 58. 20.100\r\n  libavdevice    58.  5.100 / 58.  5.100\r\n  libavfilter     7. 40.101 /  7. 40.101\r\n  libswscale      5.  3.100 /  5.  3.100\r\n  libswresample   3.  3.100 /  3.  3.100\r\n  libpostproc    55.  3.100 / 55.  3.100\r\n[mp3 @ 000001da0c1292c0] Failed to read frame size: Could not seek to 1026.\r\npipe:: Invalid argument\r\n'
3个回答

5

你必须将BytesIO对象的位置设置为0!

from gtts import gTTS
from io import BytesIO
from pydub import AudioSegment

mp3_fp = BytesIO()
tts = gTTS('hello', 'en')
tts.write_to_fp(mp3_fp)
mp3_fp.seek(0)
song = AudioSegment.from_mp3(mp3_fp)

2
救命稻草!我找到的例子,甚至是官方的,都没有提到这个! - Jorge Barroso

0

如果你有像维基百科摘要这样非常长的文本,将其转换为声音可能需要太长时间。下面的脚本可以将长文本拆分为句子并将其转换为声音,并添加一个 MP3 文件,我还添加了有趣的部分来更改声音速度并使其像儿童的声音。玩得开心...

from pydub import AudioSegment
from gtts import gTTS
from io import BytesIO
import pygame
from nltk.tokenize import sent_tokenize
from queue import Queue  # Python 3 import
import threading

sentence_queue = Queue()
audio_queue = Queue()


def split_sentence(text):
    # text = text.replace('.', '. ')
    text = text.replace('!', '. ')
    text = text.replace('?', '. ')
    sentences = sent_tokenize(text)
    for sentence in sentences:
        sentence_queue.put(sentence)
    sentence_queue.put(None)


def speed_swifter(sound, speed=1.0):
    sound_with_altered_frame_rate = sound._spawn(
        sound.raw_data, overrides={"frame_rate": int(sound.frame_rate * speed)})
    return sound_with_altered_frame_rate


def recognize_worker():
    # this runs in a background thread
    i = 1
    while True:
        mp3_fp = BytesIO()
        # retrieve the next sentense job from the main thread
        sentence = sentence_queue.get()
        if sentence is None:
            break
        # received sentence data, now we'll convert it using Google
        try:
            speech = gTTS(text=sentence, lang="tr", slow=False)
            speech.write_to_fp(mp3_fp)  # save to IO bytes
        except:
            print("gtts çalışmadı")
        sentence_queue.task_done()  # mark the audio processing job as completed in the queue
        mp3_fp.seek(0)  # BYTE IO rewind ?
        song = AudioSegment.from_mp3(mp3_fp)  # convert to audio
        slower_sound = speed_swifter(song, 1.3)
        slower_sound.export('assets/sound_out/'+str(i)+'.mp3', format="mp3")
        audio_queue.put('assets/sound_out/'+str(i)+'.mp3')
        i += 1
    audio_queue.put(None)


def player(filename):
    pygame.mixer.init()
    pygame.mixer.music.load(filename)
    pygame.mixer.music.set_volume(1.0)
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy() == True:
        pass
    pygame.mixer.music.unload()
    os.remove(filename)


def say(context):
    split_sentence(context)
    threading.Thread(target=recognize_worker).start()
    while True:
        mp3 = audio_queue.get()
        if mp3 is None:
            break
        player(mp3)
        audio_queue.task_done()


if __name__ == "__main__":
    context = 'Murat Boz. Türk şarkıcı. söz yazarı. ve oyuncudur.ürün beklediğimizden. çok çok iyi. gerek görüntü. kalitesi gerek de ses kalitesi gayet güzel. düşünmeden alabilirsiniz '
    say(context)
``

0
你必须将流的指针位置移动到0(零)索引处。(现在是1026,因为你向其写入了数据) 你必须从头到尾读取它。所以在写入后添加mp3_fp.seek(0)

与chang-hwan-lee的回答相比,这个回答似乎没有任何新的信息。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接