EnsekiTT Blog

EnsekiTTが書くブログです。

PyAudioでマイクから入ってきた音をそのまま聞く話

つまりなにしたの?

PyAudioというPythonの外部オーディオを扱うためのライブラリを使って、
マイクで入ってきた音を、そのままヘッドホンで聞いてみた。
f:id:ensekitt:20181217235530j:plain

なんでやったの?

入ってきた音をそのまま聞けるということは、入ってきた音を加工して聞くこともできるということ!
でも特に加工も思いつかないので、とりあえずそのまま吐き出すようにしてみた。

環境

 % python
Python 3.6.4 (default, Mar  2 2018, 00:45:54)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyaudio
>>> pyaudio.__version__
'0.2.11'

大まかな方針

PyAudioにはブロックモードとノンブロッキングモードがある。
ブロックモードは録音や再生をしている間、次の処理に行かない。
これ自体をThread化すればもちろん問題ないのだが、わざわざ自前でThreadingなどを用いて、
並列処理することもできるが、そんなときに必要になるのがノンブロッキングモードである。
ノンブロッキングモードではPyAudioがよしなにThreadを作ってくれて実行される。
オーディオが入力されたときに呼び出される関数(Callback関数)を定義すれば他の処理と
並列処理することができるので今回はこれを用いることにする。

コード

import pyaudio
import time

class AudioFilter():
    def __init__(self):
        # オーディオに関する設定
        self.p = pyaudio.PyAudio()
        self.channels = 2 # マイクがモノラルの場合は1にしないといけない
        self.rate = 48000 # DVDレベルなので重かったら16000にする
        self.format = pyaudio.paInt16
        self.stream = self.p.open(
                        format=self.format,
                        channels=self.channels,
                        rate=self.rate,
                        output=True,
                        input=True,
                        stream_callback=self.callback)

    # コールバック関数(再生が必要なときに呼び出される)
    def callback(self, in_data, frame_count, time_info, status):
        out_data = in_data
        return (out_data, pyaudio.paContinue)

    def close(self):
        self.p.terminate()

if __name__ == "__main__":
    # AudioFilterのインスタンスを作る場所
    af = AudioFilter()

    # ストリーミングを始める場所
    af.stream.start_stream()

    # ノンブロッキングなので好きなことをしていていい場所
    while af.stream.is_active():
        time.sleep(0.1)

    # ストリーミングを止める場所
    af.stream.stop_stream()
    af.stream.close()
    af.close()

実行方法

% python stream.py
クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。