使用PyAudio播放.mp3文件 [英] Playing .mp3 files with PyAudio

查看:1095
本文介绍了使用PyAudio播放.mp3文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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转换为 not 的样本)效果很好.

我正在使用gTTS库为我的应用程序将文本转换为语音.它会创建简短的.mp3文件,然后我需要播放.现在我只用

os.system("start english.mp3")

我想找到一种更好的方法来做到这一点.首先,我不想受到平台的限制.其次,我不希望文件开始播放时弹出播放器,我希望它停留在背景上.

我尝试为此找到一种极简主义的解决方案,因为我只需要简单玩耍就可以了.

UPD:我设法用pyglet播放它.似乎还不错,只是需要很长时间...我听到声音之前大约有10秒钟的延迟.而且它不适用于线程处理(我想在程序仍在运行时播放.mp3). 有没有办法让播放器停留在背景上而不弹出其他所有窗口?

解决方案

以下是简短的答案:

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()中更新变量/列表/数组/w/e,而不会出现任何问题,唯一不能做的就是从图形类外部调用任何图形函数.

没有前端的有趣方法:

但是,最理想的方法是像地狱般过时并使用 pyaudio 并手动摆弄音频帧.这样,只要正确解码数据,您就可以读取字面上的任何音频文件. 我用的是这个(轻踩一下,导致它不太漂亮)用于自己传输音频:

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)

这应该会产生接近音频的声音:)
wave在示例等中被过度利用的原因是,它基本上是未经编码的声音流,而不是以任何方式进行编码. mp3是一种高度压缩的音频格式, format 是此处的关键字.您需要某种方式来读取mp3数据,并将其从紧凑状态反转为数据流,然后将其压缩到扬声器中.

我不是音频专家,但这是一个音频摆设的粗略解释,该摆设是由稍微摆弄一下并使其正常工作的人完成的.

最后一个提示:

如果您希望使用Pyglet播放压缩的音频文件,则可以使用 AVbin .用于压缩文件的库.

Can pyaudio play .mp3 files? If yes, may I ask to write an example please. If no, what is the simplest way to convert .mp3 to .wav?

I have tried to use PyDub, could get my .wav file, but when I try to play it with PyAudio I get following error:

  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

With other .wav samples (which where not converted from mp3) if works well.

I am using gTTS library to convert text to speech for my application. It creates short .mp3 files which I need to play then. Right now I am using just

os.system("start english.mp3")

I want to find a better way to do this. First of all I don't want to be restricted about the platform. Secondly, I don't like that the player pops-up when the file begins to play, I'd like it to stay on the background.

I try to find the minimalist solution for this, as I don't need anything more than simple playing.

UPD: I managed to play it with pyglet. Seems fine, except it takes sooo long... I have about 10 seconds delay before I hear the sound. And it doesn't work proper with threading (I want to play the .mp3 while the program is still running). Is there the way just to make the player stay on the background and not pop-up over all other windows?

解决方案

Here's the short answer:

ffmpeg -i song.mp3 -acodec pcm_u8 -ar 22050 song.wav

TL;DR: I'm assuming you want to play an audio file, without a front-end.

There's a library for that, called The Snack Sound Toolkit which does this beautifully:

player = Sound() 
player.read('song.wav') 
player.play()

I know I used this with both streams and I think mp3 files, can't remember how or in which project, I might have to look into this though. Think it was mumble related.. anyhow..

If you're completely fine with using a front-end code such as pyglet (which is my pick of the heard), you need some options and some code for this to work as best as possible.

import pyglet
from pyglet.gl import *
pyglet.options['audio'] = ('openal', 'directsound', 'silent')

music = pyglet.resource.media('music.mp3')
music.play()

pyglet.app.run()

Dependencies: * OpenAL (for cross-platform compatibility)

Your problem with threading, is that Pyglet is an OpenGL library. Which doesn't take too kindly to Threading at all. Unless you let Pyglet fetch the data you need. Also, you will most likely bump into the problem of "pyglet blocks my code" (all graphic libraries do. so here's a workaround)

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()

This is totally fine, since you're not trying to update THE graphics from another thread.
Instead, you're fetching data on the graphics terms. You can however from worker() update a variable/list/array/w/e inside AudioWindow() without any problems, the only thing you can't do is call any graphical function from outside the graphic-class.

Without front-end the fun approach:

The most ideal way however, would to be going old-school as hell and use pyaudio and fiddle with audio frames manually. This way you can read literally any audio-file as long as you decode the data properly. I use this one(Tread lightly, cause it ain't pretty) for transporting audio myself:

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)

This should produce something close to audio :)
The reason why wave is so overutilized in examples etc, is because it's basically a unencoded stream of sound, not encoding in any way. mp3 however is a heavily compressed audio format, format being the key-word here. You need some way of read the mp3 data and reverse it from a compact state into a stream of data which you can squeeze into the speakers.

I'm no audio expert, but this is a rough explanation of how audio works from someone fiddling about with it for a bit and got it working.

Last note:

If you're expecting to play compressed audio-files with Pyglet, you can use AVbin. A library used for compressed files.

这篇关于使用PyAudio播放.mp3文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆