見出し画像

pyaudioの録音時間に少し自由を利かす

どうしてもpyaudioで録音時間を気にせずにwavファイルに保存したかった。

wavファイルに保存する方法で、あとsubprocess使った方法があるらしい。一応紹介。

とはいえ、SoXとやらを導入したり、コード見た限り私がやりたいことができなさそうだったので仕方なく色々かじって作ってみた。

やってる事はSiriがやるような録音方法に近い、多分。


やりたいこと

①録音時間は無制限
②音が聞こえなくなったら録音を停止し、1秒間待機
③待機中何も音が聞こえなかったらwavファイルに保存
④待機中に音が鳴ったら録音を再開


コード

使っているコードをほぼ転用しているので、そこそこ分かりやすいとはいえ無駄が多いんじゃないかと個人的に思ってる。

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

# 音データフォーマット
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
audio = pyaudio.PyAudio()
RATE = 44100

threshold = 0.1# 閾値 

print("recording......")
start = time.time()  # 計測開始

while True:
   # 音の取込開始
   stream = audio.open(format = FORMAT,
      channels = CHANNELS,
      rate = RATE,
      input = True,
      frames_per_buffer = chunk
      )
   # 音データの取得
   data = stream.read(chunk)
   # ndarrayに変換
   x = np.frombuffer(data, dtype="int16") / 32768.0

   if x.max() > threshold:
      end = time.time()  # 計測終了
      print("recording now......")
      finish = False
      frames = []
      # 録音処理
      while True:        
          print("recording now...")
          for i in range(0, int(RATE / chunk * 1)):
              data = stream.read(chunk)
              frames.append(data)
              ndarray = np.frombuffer(data, dtype="int16") / 32768.0
              print("閾値=" + str(ndarray.max()))
          if ndarray.max() < 0.3:
              zr = 0
              while True:                
                  data = stream.read(chunk)
                  ndarray = np.frombuffer(data, dtype="int16") / 32768.0
                  if zr >=1:
                      finish = True
                      break
                  if ndarray.max() > threshold:
                      zr = 0
                      print(zr)
                      break
                  time.sleep(0.01)
                  zr += 0.01
                  print(zr)
          if finish:
              break
      break

# 録音終了処理
stream.stop_stream()
stream.close()
audio.terminate()

# 録音データをファイルに保存
wav = wave.open("output.wav", 'wb')
wav.setnchannels(CHANNELS)
wav.setsampwidth(audio.get_sample_size(FORMAT))
wav.setframerate(RATE)
wav.writeframes(b''.join(frames))
wav.close()

録音開始後は1秒間録音の繰り返し。ただし、録音処理後に音量が閾値(今回は0.3)を下回れば、そこから約1秒間連続で閾値(こっちは0.1)を下回っているかどうか判断する繰り返し処理に入る。1秒以内にまた基準値を超えれば再び録音作業に戻るが、基準値を超えなければそのまま保存処理に入る。

これで4秒などに固定せずに録音することが可能になった。


おまけ

収集された音データは全て1つのlist型となるので、音声翻訳にかける際も楽。下の写真は実際に上のコードに音声翻訳を付け加えたものの実行結果。

画像1

おはようございます 今日はいい天気(ですね)

もごもごと話してしまい、語尾の「ですね」は読み取ってくれなかった。まぁしょうがない。

この記事が気に入ったらサポートをしてみませんか?