[英]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 接口規范。
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)
如果您正在尋找更高級的功能,您可以嘗試 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
這適用於 Windows,但不適用於我的 Ubuntu,所以我無能為力。
import pyglet
import time
sound = pyglet.media.load("Wet Hands.wav", "Wet Hands.wav")
sound.play()
time.sleep(sound.duration)
看來您使用的是 Linux,所以playsound
可能是您的選擇。我的代碼可能無法通過使用pygame
和pyglet
解決您的問題,因為我一直使用 Windows。如果您的機器上沒有解決方案,我建議您運行該程序在 Windows...
對於看到我回答的其他用戶,我已經在許多庫中做了很多測試,所以如果你使用的是 Windows,你可以嘗試mp3play
,它可以播放 mp3 和 wave 文件,而 mp3play 是最pythonic、最簡單、最輕量級和功能的圖書館。
只需復制下面的代碼並在您的工作目錄中創建一個名為 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.