EnsekiTT Blog

EnsekiTTが書くブログです。

PythonとPyAudioで大きい音がしたときに録音する話

つまりなにしたの?

PythonPyAudioで大きい音がしたときに録音を始めて10秒位録音することにした。

f:id:ensekitt:20190114040720j:plain
PythonPyAudioで大きい音がしたときに録音する話
*1

なんでやろうと思ったか

ensekitt.hatenablog.com
これはこれでいいとして、変な音がしたら後で聞きたくなる。
全録しても聞くのがめんどくさいので、大きい音がしたときだけにする。

録音のルール

  • 大きい音がしたら録音を始める
  • 録音中に大きい音がしたら録音時間を伸ばす(開始時刻を更新する)
  • 録音中で大きい音がしなかったら10秒で録音を停止する

録音するファイル名はyyyymmdd_hhmmss_audio.wavとする
ensekitt.hatenablog.com

ルールをもとに以下のコードを書いてみた

コード

import pyaudio
import numpy as np
import wave
import time
from datetime import datetime

class AudioLight():
    def __init__(self):
        # オーディオに関する設定
        self.p = pyaudio.PyAudio()
        self.channels = 1 # ステレオの場合は2
        self.rate = 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)
        self.threshold = 10000
        self.wf = None
        self.status = 0 # 0: norec, 1: rec
        self.start_at = time.time()

    # コールバック関数
    def callback(self, in_data, frame_count, time_info, status):
        if self.wf is not None:
            self.wf.writeframes(in_data)
        amp = np.fromstring(in_data, np.int16)
        self.rec_check(amp)
        out_data = in_data
        return (out_data, pyaudio.paContinue)

    def rec_check(self, amp):
        # 停止中で大きい音がしたら、新しいファイルを作成して開始時刻を設定
        if (self.status == 0) and (amp.max() > self.threshold):
            self.status = 1
            time_stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            self.open_file(time_stamp)
            self.start_at = time.time()
            print("Start Rec")
        # 録音中で大きい音がしたら、開始時刻を更新
        elif (self.status == 1) and (amp.max() > self.threshold):
            self.start_at = time.time()
            print("Update rec time")
        # 録音中で大きい音がしなくなってから10秒経ったら、ファイルを閉じる
        elif (self.status == 1) and (amp.max () <= self.threshold):
            if (time.time() - self.start_at) > 10:
                self.status = 0
                self.close_file()
                print("Rec is done.")


    def open_file(self, time_stamp):
        self.wf = wave.open(time_stamp + "_audio.wav", "wb")
        self.wf.setnchannels(self.channels)
        self.wf.setsampwidth(2)
        self.wf.setframerate(self.rate)

    def close_file(self):
        self.wf.close()
        self.wf = None

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

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

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

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

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

実行した結果

あっ!とか手を叩いたりすると録音が始まった。
あとは録音開始レベルを適切にすれば良さそう。

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