pyaudio可以播放.mp3文件吗?如果是的话,请问一个例子。如果不是,将.mp3转换为.wav的最简单方法是什么?
我曾尝试使用PyDub,可以获取我的.wav文件,但是当我尝试使用PyAudio播放时出现以下错误:
File "C:\Python33\lib\wave.py", line 130, in initfp
raise Error('file does not start with RIFF id')
wave.Error: file does not start with RIFF id
使用其他.wav示例(其中不从mp3转换)如果运行良好。
我正在使用gTTS库为我的应用程序将文本转换为语音。它会创建我需要播放的短.mp3文件。现在我只使用
os.system("start english.mp3")
我想找到一个更好的方法来做到这一点。首先,我不想限制平台。其次,我不喜欢当文件开始播放时播放器弹出,我希望它留在后台。
我试图为此找到极简主义的解决方案,因为除了简单的游戏之外,我不需要任何其他东西。
UPD:我设法用pyglet播放它。看起来很好,除了它需要太长时间......我听到声音之前有大约10秒的延迟。并且它不适用于线程(我想在程序运行时播放.mp3)。 有没有办法让玩家留在后台而不是弹出所有其他窗户?
答案 0 :(得分:7)
这是简短的回答:
ffmpeg -i song.mp3 -acodec pcm_u8 -ar 22050 song.wav
TL; DR:我假设你想播放一个没有前端的音频文件。
有一个名为The Snack Sound Toolkit的库,可以很好地完成这个任务:
player = Sound()
player.read('song.wav')
player.play()
我知道我在两个流中使用了这个,我认为mp3文件,不记得如何或在哪个项目中,可能需要查看这个。认为这是咕噜咕噜......无论如何..
如果你完全没有使用像pyglet这样的前端代码(这是我所听到的),你需要一些选项和一些代码来尽可能地工作。
import pyglet
from pyglet.gl import *
pyglet.options['audio'] = ('openal', 'directsound', 'silent')
music = pyglet.resource.media('music.mp3')
music.play()
pyglet.app.run()
依赖关系: * OpenAL(用于跨平台兼容性)
你的线程问题是Pyglet是一个OpenGL库。根本不需要对线程感兴趣。除非你让Pyglet获取你需要的数据。 你也很可能遇到“pyglet阻塞我的代码”的问题(所有的图形库都有。所以这里有一个解决方法)
import pyglet, os
from time import sleep
from threading import *
from pyglet.gl import *
pyglet.options['audio'] = ('openal', 'directsound', 'silent')
class worker(Thread):
def __init__(self):
Thread.__init__(self)
self.audio_frames = []
self.run()
def add_frame(self, filename):
self.audio_frames.append(filename)
def get_frame(self):
if len(self.audio_frames) > 0:
return self.audio_frames.pop(0)
return None
def run(self):
while 1:
for root, folders, files in os.walk('./audio_files/'):
for f in file:
self.add_frame(f)
sleep(1)
class AudioWindow(pyglet.window.Window):
def __init__(self):
self.audio_worker = worker()
def render(self):
frame = self.audio_frames.get_frame()
if frame:
music = pyglet.resource.media('music.mp3')
music.play()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
这完全没问题,因为你没有尝试从另一个线程更新图形 相反,您正在获取图形术语的数据。 但是,您可以从worker()更新AudioWindow()中的变量/ list / array / w / e而不会出现任何问题,您唯一不能做的就是从图形类外部调用任何图形函数。
然而,最理想的方式是将老派当作地狱并使用pyaudio并手动调整音频框架。这样,只要正确解码数据,您就可以读取任何音频文件。我自己传输音频时I use this one(轻轻一点,因为它并不吝啬):
import pyaudio
import wave
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 44100
p = pyaudio.PyAudio()
output = p.open(format=FORMAT,
channels=1,
rate=RATE,
output=True) # frames_per_buffer=CHUNK_SIZE
with open('audio.wav', 'rb') as fh:
while fh.tell() != FILE_SIZE: # get the file-size from the os module
AUDIO_FRAME = fh.read(CHUNK_SIZE)
output.write(AUDIO_FRAME)
这应该产生接近音频的东西:)
wav在例子等中如此过分的原因是因为它基本上是一个未编码的声音流,而不是以任何方式编码。然而,mp3是一种高度压缩的音频格式,格式是这里的关键词。您需要某种方式来读取mp3数据并将其从紧凑状态转换为可以挤入扬声器的数据流。
我不是音频专家,但这是一个粗略的解释,说明音频是如何起作用的,因为有些人正在使用音频并使其工作。
如果您希望使用Pyglet播放压缩音频文件,可以使用AVbin。用于压缩文件的库。
答案 1 :(得分:2)
我的要点是here,享受
#!/usr/bin/env python3
"""
Play a file continously, and exit gracefully on signal
Based on https://github.com/steveway/papagayo-ng/blob/working_vol/SoundPlayer.py
@author Guy Sheffer (GuySoft) <guysoft at gmail dot com>
"""
import signal
import time
import os
import threading
import pyaudio
from pydub import AudioSegment
from pydub.utils import make_chunks
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self,signum, frame):
self.kill_now = True
def play(self):
"""
Just another name for self.start()
"""
self.start()
def stop(self):
"""
Stop playback.
"""
self.loop = False
class PlayerLoop(threading.Thread):
"""
A simple class based on PyAudio and pydub to play in a loop in the backgound
"""
def __init__(self, filepath, loop=True):
"""
Initialize `PlayerLoop` class.
PARAM:
-- filepath (String) : File Path to wave file.
-- loop (boolean) : True if you want loop playback.
False otherwise.
"""
super(PlayerLoop, self).__init__()
self.filepath = os.path.abspath(filepath)
self.loop = loop
def run(self):
# Open an audio segment
sound = AudioSegment.from_file(self.filepath)
player = pyaudio.PyAudio()
stream = player.open(format = player.get_format_from_width(sound.sample_width),
channels = sound.channels,
rate = sound.frame_rate,
output = True)
# PLAYBACK LOOP
start = 0
length = sound.duration_seconds
volume = 100.0
playchunk = sound[start*1000.0:(start+length)*1000.0] - (60 - (60 * (volume/100.0)))
millisecondchunk = 50 / 1000.0
while self.loop:
self.time = start
for chunks in make_chunks(playchunk, millisecondchunk*1000):
self.time += millisecondchunk
stream.write(chunks._data)
if not self.loop:
break
if self.time >= start+length:
break
stream.close()
player.terminate()
def play(self):
"""
Just another name for self.start()
"""
self.start()
def stop(self):
"""
Stop playback.
"""
self.loop = False
def play_audio_background(audio_file):
"""
Play audio file in the background, accept a SIGINT or SIGTERM to stop
"""
killer = GracefulKiller()
player = PlayerLoop(audio_file)
player.play()
print(os.getpid())
while True:
time.sleep(0.5)
# print("doing something in a loop ...")
if killer.kill_now:
break
player.stop()
print("End of the program. I was killed gracefully :)")
return
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(add_help=True, description="Play a file continously, and exit gracefully on signal")
parser.add_argument('audio_file', type=str, help='The Path to the audio file (mp3, wav and more supported)')
args = parser.parse_args()
play_audio_background(args.audio_file)
答案 2 :(得分:0)
我们可以使用VLC绑定来支持更多文件格式。
https://gist.github.com/elibroftw/b803191c3b919a67b6a65668572680cc
答案 3 :(得分:-3)
如果您使用安装了Windows Media Player的Windows,这是一个简单的解决方案:
wmp = Dispatch('WMPlayer.OCX')
wmp.settings.autoStart = True
wmp.settings.volume = 50
wmp.URL = r"tts_cache\gtts.mp3" #auto-start
while wmp.PlayState != 1: #wait until stopped
pythoncom.PumpWaitingMessages()
time.sleep(0.1)
wmp.URL = ""
不幸的是,当我尝试用新文件替换mp3文件时,它有时无法写入。我认为WMP可以阻止它。所以我决定每次都创建一个新文件并称之为“缓存”。)