Pythonロゴともろみ先輩

今回はpyaudioを使った録音の中でも,収録時間を事前に設定しないコーディングをご紹介します。

先日pyaudioの簡単な使い方を以下の記事でご紹介したのですが,

検索してみると意外と収録時間を指定しない録音方法は紹介されていないことに気づきました。

用途によっては何かが終わるまでずっと録音していてほしいとかいう要望もあるかと思いますので,ここではそれを実現する方法を説明していきます。

今回はinput関数を使った方法を紹介しますので,まずinput関数について少し説明をしてから本題に入っていきます。

input関数とは?

input関数とはpythonの組み込み関数の一つで,プログラムの実行中にキー入力を求めるものです。

ですので,これを使ってキー入力によって処理を変えるというようなコードを書くことが可能になります。

以下のようにして入力を取得します。

val = input()

返り値はstr型になっていますので以降数値で扱いたいときにはfloat(val)やint(val)なんかで型変換してあげましょう。

val = input()
n = int(val)

pyaudioで時間を指定しない録音方法

それではいよいよ本題です。

上で説明したinput関数を使って「q」を入力するまで録音し続けるようなコードを書いてみましょう!

個人的な好みでクラスを使って書いていますが必須ではないのでそこは適宜書き換えてください。

ちなみに録音自体はノンブロッキング処理で行う必要がありますので注意してください。

まずはインポート部分+クラスの定義部分です。

import numpy as np
import wave
import pyaudio
import sys
import time

class Record:
    def __init__(self, chunksize=1024, nchannels=1, fs=44100):
        self.CHUNK = chunksize
        self.FORMAT = pyaudio.paInt16
        self.NCHANNELS = nchannels
        self.RATE = fs
        self.rec_sig = []
        self.command = None
        self.p = pyaudio.PyAudio()

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

    def callback(self, in_data, frame_count, time_info, status_flags):
        self.rec_sig.append(in_data)
        if self.command=="q":
            return None, pyaudio.paComplete
        return None, pyaudio.paContinue

    def recording(self, filename):
        stream = self.p.open(
            format=self.FORMAT,
            channels=self.NCHANNELS,
            rate=self.RATE,
            input=True,
            frames_per_buffer=self.CHUNK,
            stream_callback=self.callback
            )

        stream.start_stream()
        while stream.is_active():
            self.command = input(">>")
            time.sleep(0.01)

        stream.stop_stream()
        stream.close()
        wf = wave.open(filename, 'wb')
        wf.setnchannels(self.NCHANNELS)
        wf.setsampwidth(2)
        wf.setframerate(self.RATE)
        wf.writeframes(b''.join(self.rec_sig))
        wf.close()

ポイントとしてはcommandという変数を用意してinput関数を利用してキー入力が来たらそこに格納します。

while stream.is_active():
    self.command = input(">>")
    time.sleep(0.01)

録音はその間ノンブロッキング処理によって並列で進行していて,commandが”q”になったら終了処理に移行する仕組みです。

def callback(self, in_data, frame_count, time_info, status_flags):
    self.rec_sig.append(in_data)
    if self.command=="q":
        return None, pyaudio.paComplete
    return None, pyaudio.paContinue

次にメイン部分です。

if __name__ ==  "__main__":
    chunksize=1024
    nchannels=1
    fs=44100
    filename = "./output.wav"
    rec = Record(chunksize, nchannels, fs)
    rec.recording(filename)

最後に全てを含めた全文を載せておきます。

import numpy as np
import wave
import pyaudio
import sys
import time

class Record:
    def __init__(self, chunksize=1024, nchannels=1, fs=44100):
        self.CHUNK = chunksize
        self.FORMAT = pyaudio.paInt16
        self.NCHANNELS = nchannels
        self.RATE = fs
        self.rec_sig = []
        self.command = None
        self.p = pyaudio.PyAudio()

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

    def callback(self, in_data, frame_count, time_info, status_flags):
        self.rec_sig.append(in_data)
        if self.command=="q":
            return None, pyaudio.paComplete
        return None, pyaudio.paContinue

    def recording(self, filename):
        stream = self.p.open(
            format=self.FORMAT,
            channels=self.NCHANNELS,
            rate=self.RATE,
            input=True,
            frames_per_buffer=self.CHUNK,
            stream_callback=self.callback
            )

        stream.start_stream()
        while stream.is_active():
            self.command = input(">>")
            time.sleep(0.01)

        stream.stop_stream()
        stream.close()
        wf = wave.open(filename, 'wb')
        wf.setnchannels(self.NCHANNELS)
        wf.setsampwidth(2)
        wf.setframerate(self.RATE)
        wf.writeframes(b''.join(self.rec_sig))
        wf.close()

if __name__ ==  "__main__":
    chunksize=1024
    nchannels=1
    fs=44100
    filename = "./output.wav"
    rec = Record(chunksize, nchannels, fs)
    rec.recording(filename)

まとめ

お疲れ様でした。

今回はちょっとしたTipsですので少し短めですが,意外と実用性のある内容なのではないかなと思っています。

何かご質問等ある方はコメントをお願いします。

それではまた!