簡體   English   中英

如何在python中播放wav文件?

[英]how to play wav file in python?

我嘗試使用 pygame 播放 wav 文件,如下所示:

import pygame
pygame.init()

pygame.mixer.music.load("mysound.wav")
pygame.mixer.music.play()
pygame.event.wait()

但它改變了聲音,我不知道為什么! 我閱讀了此鏈接解決方案,但無法解決播放波形文件的問題!

對於這個解決方案,我不知道我應該導入什么?

s = Sound() 
s.read('sound.wav') 
s.play()

對於這個解決方案 /dev/dsp 在新版本的 linux 中不存在:

from wave import open as waveOpen
from ossaudiodev import open as ossOpen
s = waveOpen('tada.wav','rb')
(nc,sw,fr,nf,comptype, compname) = s.getparams( )
dsp = ossOpen('/dev/dsp','w')
try:
  from ossaudiodev import AFMT_S16_NE
except ImportError:
  if byteorder == "little":
    AFMT_S16_NE = ossaudiodev.AFMT_S16_LE
  else:
    AFMT_S16_NE = ossaudiodev.AFMT_S16_BE
dsp.setparameters(AFMT_S16_NE, nc, fr)
data = s.readframes(nf)
s.close()
dsp.write(data)
dsp.close()

當我嘗試 pyglet 它給了我這個錯誤:

import pyglet

music = pyglet.resource.media('mysound.wav')
music.play()

pyglet.app.run()
--------------------------

nima@ca005 Desktop]$ python play.py
Traceback (most recent call last):
  File "play.py", line 4, in <module>
    music = pyglet.resource.media('mysound.wav')
  File "/usr/lib/python2.7/site-packages/pyglet/resource.py", line 587, in media
    return media.load(path, streaming=streaming)
  File "/usr/lib/python2.7/site-packages/pyglet/media/__init__.py", line 1386, in load
    source = _source_class(filename, file)
  File "/usr/lib/python2.7/site-packages/pyglet/media/riff.py", line 194, in __init__
    format = wave_form.get_format_chunk()
  File "/usr/lib/python2.7/site-packages/pyglet/media/riff.py", line 174, in get_format_chunk
    for chunk in self.get_chunks():
  File "/usr/lib/python2.7/site-packages/pyglet/media/riff.py", line 110, in get_chunks
    chunk = cls(self.file, name, length, offset)
  File "/usr/lib/python2.7/site-packages/pyglet/media/riff.py", line 155, in __init__
    raise RIFFFormatException('Size of format chunk is incorrect.')
pyglet.media.riff.RIFFFormatException: Size of format chunk is incorrect.
AL lib: ReleaseALC: 1 device not closed

您可以使用PyAudio 在我的 Linux 上的一個例子它可以工作:

#!usr/bin/env python  
#coding=utf-8  

import pyaudio  
import wave  

#define stream chunk   
chunk = 1024  

#open a wav format music  
f = wave.open(r"/usr/share/sounds/alsa/Rear_Center.wav","rb")  
#instantiate PyAudio  
p = pyaudio.PyAudio()  
#open stream  
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),  
                channels = f.getnchannels(),  
                rate = f.getframerate(),  
                output = True)  
#read data  
data = f.readframes(chunk)  

#play stream  
while data:  
    stream.write(data)  
    data = f.readframes(chunk)  

#stop stream  
stream.stop_stream()  
stream.close()  

#close PyAudio  
p.terminate()  

pygame 更改音頻的原因是混音器默認為 22k 采樣率:

initialize the mixer module
pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=4096): return None

你的wav可能是8k。 所以當 pygame 播放它時,它的播放速度大約是原來的兩倍。 所以在 init 中指定你的 wav 頻率。

Pyglet 在正確讀取 RIFF 標頭時存在一些問題。 如果你有一個非常基本的 wav 文件(正好有一個 16 字節的 fmt 塊),而 fmt 塊中沒有其他信息(如“事實”數據),它就可以工作。 但是它沒有在塊中提供額外的數據,所以它真的不遵守 RIFF 接口規范。

在 Windows 上為我工作: https ://pypi.org/project/playsound/

>>> from playsound import playsound
>>> playsound('/path/to/a/sound/file/you/want/to/play.wav')

注意:這在 Windows 中有一個錯誤,它不會關閉流。 我在這里添加了一個 PR 進行修復: https ://github.com/TaylorSMarks/playsound/pull/53/commits/53240d970aef483b38fc6d364a0ae0ad6f8bf9a0

PyGame有 2 個用於播放聲音和音樂的不同模塊, pygame.mixer模塊和pygame.mixer.music模塊。 該模塊包含用於加載 Sound 對象和控制播放的類。 文檔中解釋了差異:

音樂播放和常規聲音播放之間的區別在於音樂是流式傳輸的,並且從未真正一次加載。 混音器系統一次只支持一個音樂流。

如果要播放單個wav文件,則必須初始化模塊並從文件中創建pygame.mixer.Sound()對象。 調用play()開始播放文件。 最后,您必須等待文件播放。

使用get_length()以秒為單位獲取聲音的長度並等待聲音完成:( pygame.time.wait()的參數以毫秒為單位)

import pygame

pygame.mixer.init()
my_sound = pygame.mixer.Sound('mysound.wav')
my_sound.play()
pygame.time.wait(int(my_sound.get_length() * 1000))

或者,您可以使用pygame.mixer.get_busy測試是否正在混合聲音。 循環不斷地查詢混音器的狀態:

import pygame
pygame.init()

pygame.mixer.init()
my_sound = pygame.mixer.Sound('mysound.wav')
my_sound.play()

while pygame.mixer.get_busy():
    pygame.time.delay(10)
    pygame.event.poll()

視窗

勝聲

如果你是 Windows 用戶,最簡單的方法是使用 winsound。你甚至不需要安裝它。

不推薦,功能太少

import winsound
winsound.PlaySound("Wet Hands.wav", winsound.SND_FILENAME)  
# add winsound.SND_ASYNC flag if you want to wait for it. 
# like winsound.PlaySound("Wet Hands.wav", winsound.SND_FILENAME | winsound.SND_ASYNC)

mp3播放

如果您正在尋找更高級的功能,您可以嘗試 mp3play。

不幸的是,mp3play 僅在 Python2 和 Windows 中可用。

如果您想在其他平台上使用它,請使用 playsound,盡管它的功能很差。如果您想在 Python3 中使用它,我會給您提供 Python 3 上可用的修改版本。(在答案的底部)

另外,mp3play 非常擅長播放波形文件,它給你更多的選擇。

import time
import mp3play
music = mp3play.load("Wet Hands.wav")
music.play()
time.sleep(music.seconds())

跨平台

播放聲音

Playsound 非常好用,但不推薦使用,因為無法暫停或獲取音樂的某些信息,而且經常出現錯誤。除非其他方法根本不起作用,否則您可以試試這個。

import playsound
playsound.playsound("Wet Hands.wav", block=True)

游戲

我正在使用這段代碼,它在我的測試后可以在 Ubuntu 22.04 上運行。 如果它在您的機器上不起作用,請考慮更新您的 pygame 庫。

import pygame
pygame.mixer.init()
pygame.mixer.music.load("Wet Hands.wav")
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
    pass

pyglet

這適用於 Windows,但不適用於我的 Ubuntu,所以我無能為力。

import pyglet
import time
sound = pyglet.media.load("Wet Hands.wav", "Wet Hands.wav")
sound.play()
time.sleep(sound.duration)

結論

看來您使用的是 Linux,所以playsound可能是您的選擇。我的代碼可能無法通過使用pygamepyglet解決您的問題,因為我一直使用 Windows。如果您的機器上沒有解決方案,我建議您運行該程序在 Windows...

對於看到我回答的其他用戶,我已經在許多庫中做了很多測試,所以如果你使用的是 Windows,你可以嘗試mp3play ,它可以播放 mp3 和 wave 文件,而 mp3play 是最pythonic、最簡單、最輕量級和功能的圖書館。

Python3中的mp3play

只需復制下面的代碼並在您的工作目錄中創建一個名為 mp3play.py 的文件並粘貼內容。

import random
from ctypes import windll, c_buffer


class _mci:
    def __init__(self):
        self.w32mci = windll.winmm.mciSendStringA
        self.w32mcierror = windll.winmm.mciGetErrorStringA

    def send(self, command):
        buffer = c_buffer(255)
        command = command.encode(encoding="utf-8")

        errorcode = self.w32mci(command, buffer, 254, 0)
        if errorcode:

            return errorcode, self.get_error(errorcode)
        else:
            return errorcode, buffer.value

    def get_error(self, error):
        error = int(error)
        buffer = c_buffer(255)
        self.w32mcierror(error, buffer, 254)
        return buffer.value

    def directsend(self, txt):
        (err, buf) = self.send(txt)
        # if err != 0:
        #     print('Error %s for "%s": %s' % (str(err), txt, buf))
        return err, buf


class _AudioClip(object):
    def __init__(self, filename):
        filename = filename.replace('/', '\\')
        self.filename = filename
        self._alias = 'mp3_%s' % str(random.random())

        self._mci = _mci()

        self._mci.directsend(r'open "%s" alias %s' % (filename, self._alias))
        self._mci.directsend('set %s time format milliseconds' % self._alias)

        err, buf = self._mci.directsend('status %s length' % self._alias)
        self._length_ms = int(buf)

    def volume(self, level):
        """Sets the volume between 0 and 100."""
        self._mci.directsend('setaudio %s volume to %d' %
                             (self._alias, level * 10))

    def play(self, start_ms=None, end_ms=None):
        start_ms = 0 if not start_ms else start_ms
        end_ms = self.milliseconds() if not end_ms else end_ms
        err, buf = self._mci.directsend('play %s from %d to %d'
                                        % (self._alias, start_ms, end_ms))

    def isplaying(self):
        return self._mode() == 'playing'

    def _mode(self):
        err, buf = self._mci.directsend('status %s mode' % self._alias)
        return buf

    def pause(self):
        self._mci.directsend('pause %s' % self._alias)

    def unpause(self):
        self._mci.directsend('resume %s' % self._alias)

    def ispaused(self):
        return self._mode() == 'paused'

    def stop(self):
        self._mci.directsend('stop %s' % self._alias)
        self._mci.directsend('seek %s to start' % self._alias)

    def milliseconds(self):
        return self._length_ms

    def __del__(self):
        self._mci.directsend('close %s' % self._alias)


_PlatformSpecificAudioClip = _AudioClip


class AudioClip(object):
    __slots__ = ['_clip']

    def __init__(self, filename):
        self._clip = _PlatformSpecificAudioClip(filename)

    def play(self, start_ms=None, end_ms=None):
        if end_ms is not None and end_ms < start_ms:
            return
        else:
            return self._clip.play(start_ms, end_ms)

    def volume(self, level):
        assert 0 <= level <= 100
        return self._clip.volume(level)

    def isplaying(self):
        return self._clip.isplaying()

    def pause(self):
        return self._clip.pause()

    def unpause(self):
        return self._clip.unpause()

    def ispaused(self):
        return self._clip.ispaused()

    def stop(self):
        return self._clip.stop()

    def seconds(self):
        return int(round(float(self.milliseconds()) / 1000))

    def milliseconds(self):
        return self._clip.milliseconds()


def load(filename):
    """Return an AudioClip for the given filename."""
    return AudioClip(filename)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM