Pythonのタグを新着順で眺めているとこんな記事がありました。
Pythonから音声ファイルを割り込みで再生させる
PyAudio使ったことあるけどそんな使い方してなかったので、「PyAudioでもできそうだけどできないのかな?」と思いながら、読んでいました。
気がついたら作ってました。
# !/usr/bin/env python
# -*- coding: utf-8 -*-
import pyaudio
import wave
from time import sleep
import threading
CHUNK = 1024
class AudioPlayer:
""" A Class For Playing Audio """
def __init__(self):
self.audio_file = ""
# 止める用のフラグ
self.paused = threading.Event()
def setAudioFile(self, audio_file):
self.audio_file = audio_file
def playAudio(self):
if (self.audio_file == ""):
return
self.wf = wave.open(self.audio_file, "rb")
p = pyaudio.PyAudio()
self.stream = p.open(format=p.get_format_from_width(self.wf.getsampwidth()),
channels=self.wf.getnchannels(),
rate=self.wf.getframerate(),
output=True)
data = self.wf.readframes(CHUNK)
# play stream (3)
while len(data) > 0:
# もし、止めるフラグが立ってたら
if self.paused.is_set():
# 再生を止める
self.stream.stop_stream()
# フラグを初期状態に
self.paused.clear()
break
self.stream.write(data)
data = self.wf.readframes(CHUNK)
# stop stream (4)
self.stream.stop_stream()
self.stream.close()
# close PyAudio (5)
p.terminate()
def play(player):
# 再生は別のスレッドでする
audio_thread = threading.Thread(target=player.playAudio)
audio_thread.start()
if __name__ == "__main__":
player1 = AudioPlayer()
player1.setAudioFile("1.wav")
player2 = AudioPlayer()
player2.setAudioFile("2.wav")
play(player1)
# 例えば0,5秒後に別の音源に変える
sleep(0.5)
# 1を止めて
player1.paused.set()
# 2を再生
play(player2)
一応できたのですが、 バグ というかがあって。。。
メインの部分を、一度止めてもう一度再生するみたいにすると、
if __name__ == "__main__":
player1 = AudioPlayer()
player1.setAudioFile("1.wav")
play(player1)
# 例えば0,5秒後にもう一度同じのを再生する
sleep(0.5)
# 1を止めて
player1.paused.set()
# もう一度1を再生
play(player1)
Python(39927,0x105607000) malloc: *** error for object 0x100886800: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
zsh: abort python audio.py
ってエラーがでるので、適宜
if __name__ == "__main__":
player1 = AudioPlayer()
player1.setAudioFile("1.wav")
play(player1)
# 例えば0,5秒後にもう一度同じのを再生する
sleep(0.5)
# 1を止めて
player1.paused.set()
# もう一度1を再生
# エラー出るからスリープかける
sleep(0.6)
play(player1)
として、スリープをかけてあげてください。私の環境では0.6秒以上休まないとこのエラーがでます。