Rasberry PiでPython使って音声を再生するプログラムを組んだのですが、
なかなかに苦戦したのでその道筋を示します。
仕様としては、イベントが発生したらイベントに応じた音声を再生して、
音声再生中に別のイベントが発生したら、再生中の音声を停止して新しいイベントの音声を再生するといった感じです。
これが後で効いてきます。
まずは王道のPyAudio
とりあえず「Python 音声 再生」みたいにググッたらどうやらPyAudioとやらがよく使われてるらしいので、こういつから試してみます。
インストールは公式にしたがって
apt-get install python-pyaudio python3-pyaudio
Pythonのバージョンは2.7.9なのでpython3-pyaudioはいらない気がします。
そして参考サイトを見ながら音声再生用のクラスを実装してみます
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pyaudio
import wave
from time import sleep
class AudioPlayer:
""" A Class For Playing Audio """
def __init__(self):
self.audio_file = ""
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()
stream = p.open(format=p.get_format_from_width(self.wf.getsampwidth()),
channels=self.wf.getnchannels(),
rate=self.wf.getframerate(),
output=True,
stream_callback=self.callback)
stream.start_stream()
while stream.is_active():
sleep(0.1)
stream.stop_stream()
stream.close()
self.wf.close()
p.terminate()
def callback(self, in_data, frame_count, time_info, status):
data = self.wf.readframes(frame_count)
return (data, pyaudio.paContinue)
やめられない、止まらない
こうして無事に音声の再生には成功しましたが、お察しの通り問題が。
止められねぇ...
純粋に私のスキル不足かもしれませんが、割り込みで再生を止める方法が分かりませんでした。
プロセスとか覗いたらいけるのだろうか。
Linuxにやらせてみよう
ここでちょっと視点を変えて、Pythonから音声を再生するのでなく、音声再生用のコマンドをPythonから実行して適宜中断させるとかどうだろうとか思ったわけです。
aplay お前もか…
というわけで次はaplayを試します。aplay hoge.wav
で再生できるからお手軽ですね。
aplayコマンドを実行するよう、さっきのクラスを書き換えます。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
class AudioPlayer:
""" A Class For Playing Audio """
def __init__(self):
self.audio_file = ""
self.is_playing = False
def setAudioFile(self, audio_file):
self.audio_file = audio_file
def playAudio(self):
if(self.audio_file == ""):
return
subprocess.call(["aplay", self.audio_file])
commandモジュールは非推奨なのでsubprocessモジュールを使います。
よし、これで再生はできる、中断するにはどうするのかなとaplay --help
を見てみると......無いですね。
aplayの再生を止めるにはCtl+CかPID調べてkillするかしか無いみたいですね。これはいかんでしょ。
そしてmpcへ...
いや、方向性は間違っていないはずだと信じてさらに調べるとmpcにたどり着きました。
このページの下のほうに書いてある内容を見る限り、音声を中断させるコマンドもある。いけるやん!
というわけでまたクラスを書き換えます。
といってもsubprocess.callを使うのは変わりません。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
class AudioPlayer:
""" A Class For Playing Audio """
def __init__(self):
self.audio_file = ""
self.is_playing = False
def setAudioFile(self, audio_file):
self.audio_file = audio_file
def playAudio(self):
if(self.audio_file == ""):
return
print 'play ' + self.audio_file
subprocess.call(["mpc", "stop"]) #音声停止
subprocess.call(["mpc", "clear"]) #プレイリストのクリア
subprocess.call(["mpc", "update"]) #音声ファイルの読み込み
subprocess.call(["mpc", "add", self.audio_file]) #プレイリストに追加
subprocess.call(["mpc", "play"]) #再生
これでテストしてみると...やった、音声が中断されて新しい音声が再生されたぞ!
これで勝つる!