質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

984閲覧

リアルタイムでの音声のフィルタリング

sibazyun

総合スコア18

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/10/05 09:07

前提・実現したいこと

今リアルタイムで録音した音声にフィルタをかけ、出力するプログラミングを作っているのですが、
バンドパスフィルタ(マイクから入力した音声の値が小さい周波数にカットオフ周波数が変わるようになっています)を一つしかかけていないにもかかわらずたまに出力音声のぐらふにやまが2つできてしまい原因を探しています。
濃い青のグラフが入力音声の周波数スペクトラム、薄い青がフィルタ後の出力する音声の周波数スペクトラムです。

発生している問題・エラーメッセージ

一枚目が正しく動いているとき二枚目が山が2つできてしまったときです
正常時
異常発生時

該当のソースコード

python

1# グラフ更新し続ける 2 3import pyaudio 4import time 5import sys 6import numpy as np 7import matplotlib.pyplot as plt 8from collections import deque 9from scipy import signal 10 11input_device = 0 # 入力デバイス 12output_device = 1 # 出力デバイス 13sampling_rate = 44100 # サンプリングレート マイクの特性に合わせる 14CHUNK = 2 ** 10 # データ長になる 15record_seconds = 1.0 # サンプリングする必要最低限の時間 16freq_limit = 12000 # Hz 17 18 19class Plot(): # もうすこしマトモなclassにしたい 20 def __init__(self): 21 self.fig, self.ax = plt.subplots(1, 1) 22 self.lines, = self.ax.plot(0, 0, color='b') # 第一プロット 23 self.lines2, = self.ax.plot(0, 0, color='c') # 第二プロット 24 self.lines3, = self.ax.plot(0, 0) # 第三プロット 25 self.points, = self.ax.plot(0, 0, color='orange', marker='o', markersize=15, linestyle='None') # ポイント 26 self.target, = self.ax.plot(0, 0, color='red', marker='o', markersize=15, linestyle='None') 27 #カットオフ周波数表示 28 self.ann = self.ax.annotate("", (0, 0)) 29 self.ann2 = self.ax.annotate("", (0, 0)) 30 self.ann3 = self.ax.annotate("", (0, 0)) 31 plt.yscale('symlog') 32 33 def set(self, x_data, y_data): 34 self.lines.set_data(x_data, y_data) 35 # 現在の値を取得(これで合ってる?) 36 y = y_data[-1] 37 # 値を更新 38 self.ann.set_text(f'fe1={y:0.2f}') 39 # 動的に表示箇所を変更する場合は以下のような処理を記述 40 self.ann.set_position((0, y)) 41 self.ax.set_xlim(0, x_data.max()) 42 self.ax.set_ylim(0, y_data.max()) 43 44 def set2(self, x_data, y_data): 45 self.lines2.set_data(x_data, y_data) 46 # self.ax.set_xlim(0, x_data.max()) 47 # self.ax.set_ylim(0, y_data.max()) 48 49 def set3(self, x_data, y_data): 50 self.lines3.set_data(x_data, y_data) 51 # self.ax.set_xlim(0, x_data.max()) 52 # self.ax.set_ylim(0, y_data.max()) 53 54 55 def set_points(self, x_data, y_data): 56 self.points.set_data(x_data, y_data) 57 58 def set_targets(self, x_data, y_data): 59 self.targets(x_data, y_data) 60 61 def pause(self): 62 plt.pause(.01) 63 64 def close(self): 65 plt.close() 66 67 68class AudioFilter(): 69 def __init__(self): 70 # オーディオに関する設定 71 self.p = pyaudio.PyAudio() 72 self.channels = 1 # モノラル 73 self.format = pyaudio.paFloat32 74 self.voice_data = deque([], maxlen=int(sampling_rate * record_seconds)) 75 self.filtered_data = deque([], maxlen=int(sampling_rate * record_seconds)) 76 self.noise_data = deque([], maxlen=int(sampling_rate * record_seconds)) 77 self.rate = sampling_rate 78 self.chunk = CHUNK 79 self.idt = '' 80 self.fe1 = 100/(sampling_rate/2) 81 self.fe2 = 10000/(sampling_rate/2) 82 self.min_id = [] 83 self.minimum = [] 84 #self.filter1 = signal.firwin(numtaps=255, cutoff=[self.fe1,self.fe2], pass_zero=False) 85 self.audio_data = '' 86 # self.time = {} 87 self.stock_sec = record_seconds 88 self.buf = np.array([]) 89 90 self.stream = self.p.open( 91 format=self.format, 92 channels=self.channels, 93 rate=self.rate, 94 output=True, 95 input=True, 96 frames_per_buffer=self.chunk, # バッファごとのフレーム長を指定 97 input_device_index=input_device, 98 output_device_index=output_device, 99 stream_callback=self.callback # コールバック関数の指定 100 ) 101 102 # コールバック関数(chunk貯まるたびに呼び出される。長い処理を書くと再帰が深くなる) 103 def callback(self, in_data, frame_count, time_info, status): 104 filter1 = signal.firwin(numtaps=255, cutoff=[self.fe1, self.fe2], pass_zero=False)#フィルタの定義 105 106 #min_idに値が入ったとき、それに合わせカットオフ周波数を変更 107 if len(self.minimum) >= 1: 108 j = 0 109 #サンプリングレートの1/2以上の値を除外 110 for i in self.minimum: 111 if i > 20000 or i < 100: 112 j += 1 113 else: 114 break 115 #カットオフ周波数の変更 116 self.fe1 = (self.minimum[j]-100)/ (sampling_rate / 2) 117 self.fe2 = (self.minimum[j]+100)/ (sampling_rate / 2) 118 print('fe1 and fe2 is',self.minimum[j]-100,self.minimum[j]+100) 119 120 121 self.buf = np.frombuffer(in_data, dtype="float32") 122 filt = signal.lfilter(filter1, 1, self.buf) 123 self.noise_data.extend(self.buf) # 環境音データ 124 # self.voice_data.extend(self.buf) # 加工前の音声データ 125 self.filtered_data.extend(filt) # 加工後の音声データ 126 out_data = filt.astype("float32").tostring() # 加工した音声データを出力 127 return (out_data, pyaudio.paContinue) 128 129 def filtering(self): 130 return 0 131 132 def close(self): 133 self.p.terminate() 134 135 136if __name__ == '__main__': 137 138 freqList = np.fft.fftfreq(int(sampling_rate * record_seconds), d=1.0 / sampling_rate) 139 pt = Plot() # プロット用 140 141 af = AudioFilter() # AudioFilterのインスタンス 142 af.stream.start_stream() # ストリーミングを始める 143 144 # ノンブロッキングなので好きなことをしていていい場所 145 while af.stream.is_active(): 146 if (len(af.noise_data) >= int(sampling_rate * record_seconds)): 147 148 data = np.array(af.noise_data) 149 af.noise_data.clear() 150 x = np.fft.fft(data) 151 152 filtered_data = np.array(af.filtered_data) 153 af.filtered_data.clear() 154 fft_filtered_data = np.fft.fft(filtered_data) 155 156 amplitude = np.array([np.sqrt(c.real ** 2 + c.imag ** 2) for c in x]) # 振幅スペクト 157 amplitude_filtered_data = np.array([np.sqrt(c.real ** 2 + c.imag ** 2) for c in fft_filtered_data]) 158 pt.set(freqList[:int(len(freqList) / 2)], amplitude[:int(len(freqList) / 2)]) # 環境音プロット 159 pt.set2(freqList[:int(len(freqList) / 2)], amplitude_filtered_data[:int(len(freqList) / 2)]) # 加工後音声プロット 160 161 # 下限ピーク検出 162 af.min_id = signal.argrelmin(amplitude, order=1000) # small peaks 163 ary = amplitude[af.min_id] 164 pt.set_points(af.min_id, ary) 165 targets = np.sort(ary) 166 pt.pause() 167 #print(ary) 168 169 # 下限ピークを昇順に並び替え 170 af.minimum = af.min_id[0][ary.argsort()] 171 print(af.minimum) 172 173 pt.close() 174 175 # ストリーミングを止める場所 176 af.stream.stop_stream() 177 af.stream.close() 178 af.close()

試したこと

カットオフ周波数の値を表示させ以上が起きていないかを見たのですが問題はありませんでした

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2019/10/05 09:42

「バンドパスフィルタ(マイクから入力した音声の値が小さい周波数にカットオフ周波数が変わるようになっています)」の意味が判りません。 音声信号によって、周波数特性が変わるという特殊なバンドパスフィルターを使っているという事ですか? 周波数特性がダイナミックに変化するとすると、フィルターの特性もリアルタイムに観測できるのでしょうか?
sibazyun

2019/10/06 06:00

``` signal.firwin(numtaps=255, cutoff=[self.fe1, self.fe2], pass_zero=False) ``` scipyのfirwin関数を用いてバンドパスフィルタを作成しているのですが、このcutoffの値に取得した音声のうち最も音量が小さいと判断された周波数を代入しています。そのため音声信号によって周波数特性が変化します。
coco_bauer

2019/10/16 03:18

まずは、バンドパスフィルターの特性を観測(記録)してみてください。どんなバンドパスフィルターが使われているのか判らないのでは、フィルターの入力と出力の関係が適切かどうかの判断がつきませんからね。 また、質問に示されているスペクトルが測定される途中で、バンドパスフィルターの特性が変わったという可能性はあるのですか? できれば、バンドパスフィルターの特性が設定された瞬間から、次にバンドパスフィルターの特性が変更される瞬間までに限定して、スペクトルがとれると良いと思うのですが、可能ですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問