12
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pythonから音声ファイルを割り込みで再生させる

Posted at

Rasberry PiでPython使って音声を再生するプログラムを組んだのですが、
なかなかに苦戦したのでその道筋を示します。

仕様としては、イベントが発生したらイベントに応じた音声を再生して、
音声再生中に別のイベントが発生したら、再生中の音声を停止して新しいイベントの音声を再生するといった感じです。

これが後で効いてきます。

まずは王道のPyAudio

とりあえず「Python 音声 再生」みたいにググッたらどうやらPyAudioとやらがよく使われてるらしいので、こういつから試してみます。

インストールは公式にしたがって
apt-get install python-pyaudio python3-pyaudio
Pythonのバージョンは2.7.9なのでpython3-pyaudioはいらない気がします。

そして参考サイトを見ながら音声再生用のクラスを実装してみます

audio_player.py
#!/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コマンドを実行するよう、さっきのクラスを書き換えます。

audio_player.py
#!/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を使うのは変わりません。

audio_player.py
#!/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"]) #再生

これでテストしてみると...やった、音声が中断されて新しい音声が再生されたぞ!
これで勝つる!

参考ページ

12
18
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?