Practice 3: PyHARK の使い方
PyHARK の機能
- PyHARK で何ができるのか
- HARK Designer で設計したネットワークを Python でも記述できる
- PyHARK の機能
- Pythonの多様なライブラリにHARKの機能を追加
- オンライン処理に加えてオフライン処理もサポート
- PyHARKによるPythonプログラミングは3通り
- PyHARKの関数型機能に基づいた Python プログラミング
- HARK Designer のネットワークプログラムからPyHARKによるPythonプログラミムへの変換
- n2py: HARK Designer のネットワークプログラムからPythonプログラミムへの自動変換(Practice3-4)
Practice 3 で学ぶこと
- PyHARKの設計の背景と方針
- 音源定位を取り上げ、HARKネットワークプログラミングとPyHARK, Pythonプログラミングの対応
- Practic3-1: PyHARK(オンライン・ファイル入力)
- Practic3-2: PyHARK(オンライン・マイク入力)
- Practic3-3: PyHARK による音声認識(オフライン)
- Practic3-4: n2py による自動変換(オンライン/オフライン)
HARKのネットワークプログラムからPyHARKの関数型プログラミング
HARK Designer | Python with PyHARK |
---|---|
Node | node by network.create |
Node Property | node.xxx .add_input("PARAM", VALUE) |
link | node_xxx .add_input("NAME", node_yyy["NAME"]) |
subnetwork with I/O terminals | function call by publisher and subscriber |
上記のPyHARKの機能を使って、直接Pythonプログラムを書くと、HARKの機能がPythonで使えます。
PyHARK での音源定位 (Practice 1の演習の復習)
HARKネットワークと PyHARKプログラムとの対応の概略を知る
Practice 1での音源定位のネットワークを、下記のようなPyHARKプログラムに変換したい。
#!/usr/bin/env python import hark import ... class HARK_Localization(hark.NetworkDef): ... class HARK_Loop(hark.NetworkDef): ... class HARK_Main(hark.NetworkDef): ... def main(): ...
Practice3-1: PyHARKによる音源定位を動かして,挙動を知る
- ターミナルを開いてPythonプログラムを実行する
- ウィンドウがポップアップし,音源定位結果が表示される
- ウェイトなしのためPCの性能によっては定位結果が高速に流れる
practice3-1.py
をpractice3-1w.py
にすると実時間に近い速度になる
cd practice3/data python practice3-1.py input.wav
Practice3-1: PyHARKによるファイル入力オンライン音源定位
practice3-1.n
のPython practice3-1.py
への変換
HARK Designerで設計していたネットワークを Python でも記述できる
- Pythonの多様なライブラリにHARKの機能を追加
- オンライン処理に加えてオフライン処理もサポート
- 本章での説明の順序は以下の通り
- Practice3-1 では,ファイル入力によるオンライン音源定位(practice1-1の改良版)を取り上げる
- HARK Designer によるネットワークファイル:
practice3-1.n
- PyHARK によるPythonプログラム:
practice3-1.py
Practice3-1: HARK Designer のネットワークファイル
- ネットワークファイル
practice3-1.n
の構造を知る - MAINネットワークと2つのサブネットワークをPyHARKで変換
- main関数の作成
Practice3-1: MAIN ネットワークのネットワークファイル
- HARK Designer でのMAINネットワーク
- ネットワークファイル
practice3-1.n
のヘッダー部とMAIN ネットワーク部分
#!/usr/bin/env batchflow <?xml version="1.0"?> <Document> <Network type="subnet" name="MAIN"> <Node name="node_LOOP_1" type="LOOP" x="520" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> </Node> <Node name="node_Constant_1" type="Constant" x="100" y="100"> <Parameter name="VALUE" type="string" value="input.wav" description="The value"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_InputStream_1" type="InputStream" x="300" y="100"> <Parameter name="TYPE" type="string" value="" description="Type of stream: stream, fd, or FILE (default stream)"/> <Parameter name="RETRY" type="int" value="" description="If set to N, InputStream will retry N times on open fail"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" ... </Node> <Link from="node_Constant_1" output="VALUE" to="node_InputStream_1" input="INPUT"/> <Link from="node_InputStream_1" output="OUTPUT" to="node_LOOP_1" input="INPUT"/> <NetOutput name="OUTPUT" node="node_LOOP_1" terminal="OUTPUT" object_type="any" description="Dynamic"/> </Network>
Practice3-1: sub_Localization サブネットワークのネットワークファイル
- HARK Designer での
sub_Localization
サブネットワーク - ネットワークファイル
practice3-1.n
のsub_Localizaton
サブネットワーク部分
<Network type="subnet" name="sub_localization"> <Node name="node_LocalizeMUSIC_1" type="LocalizeMUSIC" x="370" y="100"> <Parameter name="MUSIC_ALGORITHM" type="string" value="SEVD" description="Sound Source Localization Algorithm. If SEVD, NOISECM will be ignored"/> <Parameter name="TF_CHANNEL_SELECTION" type="object" value="<Vector<int>" description="Microphone channels for localization. If vacant, all channels will be used."/> <Parameter name="LENGTH" type="subnet_param" value="LENGTH" description="The length of a frame (per channel)."/> <Parameter name="SAMPLING_RATE" type="subnet_param" value="SAMPLING_RATE" description="Sampling Rate (Hz)."/> <Parameter name="TF_INPUT_TYPE" type="string" value="FILE" description="Load form TF file or Input terminal."/>. <Parameter name="A_MATRIX" type="string" value="tf.zip" description="Filename of a transfer function matrix."/>. <Parameter name="WINDOW" type="int" value="50" description="The number of frames used for calculating a correlation function."/> <Parameter name="WINDOW_TYPE" type="string" value="MIDDLE" description="Window selection to accumulate a correlation function. If PAST, the past WINDOW frames from the current frame are used for the accumulation. If MIDDLE, the current frame will be the middle of the accumulated frames. If FUTURE, the future WINDOW frames from the current frame are used for the accumulation. FUTURE is the default from version 1.0, but this makes a delay since we have to wait for the future information. PAST generates a internal buffers for the accumulation, which realizes no delay for localization."/> <Parameter name="PERIOD" type="int" value="50" description="The period in which the source localization is processed."/> <Parameter name="NUM_SOURCE" type="int" value="2" description="Number of sources, which should be less than number of channels."/>. <Parameter name="MIN_DEG" type="int" value="-180" description="source direction (lower)."/> <Parameter name="MAX_DEG" type="int" value="180" description="source direction (higher)."/> <Parameter name="LOWER_BOUND_FREQUENCY" type="int" value="3000" description="Lower bound of frequency (Hz) used for correlation function calculation."/> <Parameter name="UPPER_BOUND_FREQUENCY" type="int" value="6000" description="Lower bound of frequency (Hz) used for correlation function calculation."/> <Parameter name="SPECTRUM_WEIGHT_TYPE" type="string" value="A_Characteristic" description="MUSIC spectrum weight for each frequency bin."/> <Parameter name="A_CHAR_SCALING" type="float" value="1.0" description="Scaling factor of the A-Weight with respect to frequency"/> <Parameter name="MANUAL_WEIGHT_SPLINE" type="object" value="<Matrix<float> <rows 2> <cols 5> <data 0.0 2000.0 4000.0 6000.0 8000.0 1.0 1.0 1.0 1.0 1.0> >" description="MUSIC spectrum weight for each frequency bin. This is a 2 by M matrix. The first row represents the frequency, and the second row represents the weight gain. "M" represents the number of key points for the spectrum weight. The frequency range between M key points will be interpolated by spline manner. The format is "<Matrix<float> <rows 2> <cols 2> <data 1 2 3 4> >"."/> <Parameter name="MANUAL_WEIGHT_SQUARE" type="object" value="<Vector<float> 0.0 2000.0 4000.0 6000.0 8000.0>" description="MUSIC spectrum weight for each frequency bin. This is a M order vector. The element represents the frequency points for the square wave. "M" represents the number of key points for the square wave weight. The format is "<Vector<float> 1 2 3 4>"."/> <Parameter name="ENABLE_EIGENVALUE_WEIGHT" type="bool" value="false" description="If true, the spatial spectrum is weighted depending on the eigenvalues of a correlation matrix. We do not suggest to use this function with GEVD and GSVD, because the NOISECM changes the eigenvalue drastically. Only useful for SEVD."/> <Parameter name="MAXNUM_OUT_PEAKS" type="int" value="-1" description="Maximum number of output peaks. If MAXNUM_OUT_PEAKS = NUM_SOURCE, this is compatible with HARK version 1.0. If MAXNUM_OUT_PEAKS = 0, all local maxima are output. If MAXNUM_OUT_PEAKS < 0, MAXNUM_OUT_PEAKS is set to NUM_SOURCE. If MAXNUM_OUT_PEAKS > 0, number of output peaks is limited to MAXNUM_OUT_PEAKS."/> <Parameter name="DEBUG" type="bool" value="true" description="Debug option. If the parameter is true, this node outputs sound localization results to a standard output."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SourceTracker_1" type="SourceTracker" x="590" y="100"> <Parameter name="THRESH" type="float" value="25" description="Power threshold for localization results. A localization result with higher power than THRESH is tracked, otherwise ignored."/> <Parameter name="PAUSE_LENGTH" type="float" value="1200" description="Life duration of source in ms. When any localization result for a source is found for more than PAUSE_LENGTH / 10 iterations, the source is terminated. [default: 800]"/> <Parameter name="MIN_SRC_INTERVAL" type="float" value="20" description="Source interval threshold in degree. When the angle between a localization result and a source is smaller than MIN_SRC_INTERVAL, the same ID is given to the localization result. [default: 20]"/> <Parameter name="MIN_ID" type="int" value="0" description="Minimum ID of source locations. MIN_ID should be greater than 0 or equal."/> <Parameter name="DEBUG" type="bool" value="false" description="Output debug information if true [default: false]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SourceIntervalExtender_1" type="SourceIntervalExtender" x="820" y="100"> <Parameter name="PREROLL_LENGTH" type="int" value="80" description="Preroll length in frame. [default: 50]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_plotQuickSourceKivy_1" type="plotQuickSourceKivy" x="1110" y="100"> </Node> <Node name="node_CMIdentityMatrix_1" type="CMIdentityMatrix" x="100" y="190"> <Parameter name="NB_CHANNELS" type="int" value="8" description="The number of input channels."/> <Parameter name="LENGTH" type="int" value="512" description="The length of a frame (per channel)."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_LocalizeMUSIC_1" output="OUTPUT" to="node_SourceTracker_1" input="INPUT"/> <Link from="node_SourceTracker_1" output="OUTPUT" to="node_SourceIntervalExtender_1" input="SOURCES"/> <Link from="node_SourceIntervalExtender_1" output="OUTPUT" to="node_plotQuickSourceKivy_1" input="SOURCES"/> <Link from="node_CMIdentityMatrix_1" output="OUTPUT" to="node_LocalizeMUSIC_1" input="NOISECM"/> <NetInput name="INPUT" node="node_LocalizeMUSIC_1" terminal="INPUT" object_type="Matrix<complex<float> >" description="Multi-channel audio signals. In this matrix, a row is a channel, and a column is a sample."/> <NetOutput name="OUTPUT" node="node_plotQuickSourceKivy_1" terminal="OUTPUT" object_type="any" description=""/> </Network>
Practice3-1: LOOP サブネットワークのネットワークファイル
- HARK Designer でのLOOPサブネットワーク
- ネットワークファイル
practice3-1.n
のLOOP ネットワーク部分
<Network type="iterator" name="LOOP"> <Node name="node_MultiFFT_1" type="MultiFFT" x="430" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> <Parameter name="ADVANCE" type="int" value="160" description="The shift length beween adjacent frames (in samples)[default: 160]."/> <Parameter name="USE_WAIT" type="bool" value="false" description="If true, real recording is simulated [default: false]."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_sub_localization_1" type="sub_localization" x="640" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The length of a frame (per channel)."/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling Rate (Hz)."/> </Node> <Node name="node_AudioStreamFromWave_1" type="AudioStreamFromWave" x="100" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> <Parameter name="ADVANCE" type="int" value="160" description="The shift length beween adjacent frames (in samples)[default: 160]."/> <Parameter name="USE_WAIT" type="bool" value="false" description="If true, real recording is simulated [default: false]."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_MultiFFT_1" output="OUTPUT" to="node_sub_localization_1" input="INPUT"/> <Link from="node_AudioStreamFromWave_1" output="AUDIO" to="node_MultiFFT_1" input"node_sub_localization_1" input="INPUT"/> <NetInput name="INPUT" node="node_AudioStreamFromWave_1" terminal="INPUT" object_type="Stream" description="An audio input stream (IStream)."/> <NetCondition name="CONDITION" node="node_AudioStreamFromWave_1" terminal="NOT_EOF"/> <NetOutput name="OUTPUT" node="node_sub_localization_1" terminal="OUTPUT" object_type="any" description=""/> </Network> </Document>
Practice3-1: 変換された PyHARK によるPythonプログラム
practice3-1.py
HARK ネットワークファイルから MyHARKを使ったPythonプログラムへの変換
- practice3-1.py PyHARKによる practice3-1.n のプログラムの概要
- ネットワークファイルからPyHARKを用いたPythonプログラムへの変換の原則:
- すべてのネットワークは,
hark.NetworkDef
を継承したネットワークをクラスとして定義 build()
メソッド中にネットワークの構造を記述- 必要なノードを
network.create
で作成 - ノードの接続関係は,入力端子に対して
node_xxx.add_input("NAME", node_yyy["NAME"])
で定義 - ノードのパラメータを
node_xxx.add_input("PARM", VALUE)
で定義
Python プログラムでの必要なモジュールのImport
import sys # コマンドライン引数処理 import threading # ネットワーク実行用スレッドの管理 import numpy as np # 音響信号などの配列データ処理 import soundfile as sf # 音響信号ファイル読み書き import hark # PyHARK関連モジュール import hark.base # この3つのモジュールは import hark.node # この順番でimportすること import hark.core # from hark.modules.plot.kivynodes.plotQuickSourceKivy import plotQuickSourceKivy # 定位結果表示用
Python プログラム practice3-1.py
の全体像
具体的なプログラムは以下の通り
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import threading import numpy as np import soundfile as sf import hark import hark.base import hark.node import hark.core from hark.modules.plot.kivynodes.plotQuickSourceKivy import plotQuickSourceKivy class HARK_Localization(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_cm_identity_matrix = network.create(hark.node.CMIdentityMatrix, dispatch=hark.RepeatDispatcher) node_constant_for_operation_flag = network.create(hark.node.Constant, dispatch=hark.RepeatDispatcher) node_localize_music = network.create(hark.node.LocalizeMUSIC) node_source_tracker = network.create(hark.node.SourceTracker) node_source_interval_extender = network.create(hark.node.SourceIntervalExtender) node_plotsource_kivy = network.create(plotQuickSourceKivy.plotQuickSourceKivy) except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_cm_identity_matrix .add_input("NB_CHANNELS", 8) .add_input("LENGTH", 512) , node_constant__for_operation_flag .add_input("VALUE", True) , node_localize_music .add_input("INPUT", input["SPEC"]) .add_input("NOISECM", node_cm_identity_matrix["OUTPUT"]) .add_input("OPERATION_FLAG", node_constant__for_operation_flag["OUTPUT"]) .add_input("MUSIC_ALGORITHM", "SEVD") .add_input("A_MATRIX", "tf.zip") .add_input("WINDOW_TYPE", "MIDDLE") .add_input("LOWER_BOUND_FREQUENCY", 3000) .add_input("UPPER_BOUND_FREQUENCY", 6000) .add_input("SPECTRUM_WEIGHT_TYPE", "A_Characteristic") .add_input("ENABLE_EIGENVALUE_WEIGHT", False) .add_input("ENABLE_OUTPUT_SPECTRUM", True) , node_source_tracker .add_input("INPUT", node_localize_music["OUTPUT"]) .add_input("THRESH", 25.0) .add_input("PAUSE_LENGTH", 1200.0) #.add_input("MIN_SRC_INTERVAL", 20.0) , node_source_interval_extender .add_input("SOURCES", node_source_tracker["OUTPUT"]) .add_input("PREROLL_LENGTH", 80) , node_plotsource_kivy .add_input("SOURCES", node_source_interval_extender["OUTPUT"]) , ] output.add_input("OUTPUT", node_source_interval_extender["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r class HARK_Loop(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_audio_stream_from_memory = network.create( hark.node.AudioStreamFromMemory, dispatch=hark.TriggeredMultiShotDispatcher, name="AudioStreamFromMemory") node_multi_fft = network.create(hark.node.MultiFFT) node_sub_localization = network.create(HARK_Localization, name="Localization") except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_audio_stream_from_memory .add_input("INPUT", input["INPUT"]) .add_input("CHANNEL_COUNT", 8) , node_multi_fft .add_input("INPUT", node_audio_stream_from_memory["AUDIO"]) , node_sub_localization .add_input("SPEC", node_multi_fft["OUTPUT"]) , ] output.add_input("OUTPUT", node_sub_localization["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r class HARK_Main(hark.NetworkDef): # メインネットワークに相当するクラス。 # 入力として8ch音響信号を受け取り、 # フーリエ変換、MUSIC法による音源定位、音源追跡を行い、 # その結果を図示する。 def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する. # - 全体の入出力を扱う Publisher と Subscriber # - HARK_Loop サブネット try: node_publisher = network.create(hark.node.PublishData,dispatch=hark.RepeatDispatcher,name="Publisher") node_subscriber = network.create(hark.node.SubscribeData,name="Subscriber") loop = network.create(HARK_Loop, name="HARK_Loop") except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ loop.add_input("INPUT", node_publisher["OUTPUT"]) , node_subscriber.add_input("INPUT", loop["OUTPUT"]) , ] except BaseException as ex: print(ex) # ノード一覧のリストを返す return r def main(): # コマンドライン引数の処理 if len(sys.argv) < 2: print("no input file") return wavfilename = sys.argv[1] # メインネットワークを構築 network = hark.Network.from_networkdef(HARK_Main, name="HARK_Main") # メインネットワークへの入出力を構築 publisher = network.query_nodedef("Publisher") subscriber = network.query_nodedef("Subscriber") # subscriber がデータを受け取ったとき # (メインネットワークが結果を出力したとき)に # 実行される動作を定義する。 # ここでは pass を用いることで「何もしない」ことを指示する。 def received(data): pass subscriber.receive = received try: # ネットワーク実行用スレッドを開始 th = threading.Thread(target=network.execute) th.start() # 入力ファイル読み込み audio, rate = sf.read(wavfilename, dtype=np.int16) # フレーム分割 advance = 160 # 2023講習会VMは numpy==1.21.5 # for numpy>=1.20.0 frames = np.lib.stride_tricks.sliding_window_view(audio, advance, axis=0)[::advance, :, :] # for numpy < 1.20.0 # frames = np.lib.stride_tricks.as_strided( # audio, # shape=(int(audio.shape[0]/advance), advance, audio.shape[1]), # strides=(advance * audio.shape[1] * audio.strides[1], audio.shape[1]*audio.strides[1], audio.strides[1]) # ) # フレームごとに処理 for t, f in enumerate(frames): # もしネットワーク実行用スレッドが停止していたら # ループを抜け処理全体を停止させる if not th.is_alive(): break # ネットワークに1フレーム分の音響信号を送信 publisher.push(f) # リアルタイム処理と同等程度の処理時間となるように # 音響信号送信間隔を調整する # time.sleep(advance / rate) except BaseException as ex: print(ex) except: network.stop() finally: # 終了処理 publisher.close() if th.ident is not None: th.join() if __name__ == '__main__': main() # end of file
practice3-1.py: PyHARKによるオンライン音源定位プログラムの詳細
- PyHARK化の原則(再掲)
- すべてのネットワークは,
hark.NetworkDef
を継承したネットワークをクラスとして定義 build()
メソッド中にネットワークの構造を記述- 必要なノードを
network.create
で作成 - ノードの接続関係は,入力端子に対して
node_xxx.add_input("NAME", node_yyy["NAME"])
で定義 - ノードのパラメータを
node_xxx.add_input("PARM", VALUE)
で定義
Python クラス HARK_Localization (音源定位サブネットワーク)
- HARK Designerの音源定位サブネットワーク subLocalizaton
hark.NetworkDef
を継承したクラスとしてHARK_Localization
クラスの定義
- PyHARKの
network.create
で必要な5つのノードの作成 node_localize_music
のパラメータの記述とnode_cm_identity_matrix
との接続(下図)
対応するプログラムは下記node_localize_music
におけるnode_cm_identity_matri
x からの接続の記述(上記プログラム参照)HARK_Localization
クラスのbuild()
のパラメータinput
をnode_localize_music
で呼び出す(上記プログラム参照)node_localize_music ノードのパラメータの設定(上記プログラム参照)
node_localize_music
で使用したノードのリストを作りbuild()
の返値とする(上記プログラム参照)
class HARK_Localization(hark.NetworkDef): # hark.NetworkDefを継承したクラス # build() メソッドを定義し,サブネットの構造を記述 def build( self, # オブジェクト自身を表す変数 network: hark.Network, # ノードs生成等を行うためのエントリポイント input: hark.DataSourceMap, # このサブネットへの入力を表す変数 output: hark.DataSinkMap): # このサブネットからの出力を表す変数 # LocalizeMUSIC (音源定位) node_localize_music = network.create(hark.node.LocalizeMUSIC) # CMIdentityMatrix (雑音相関行列用の単位行列作成) node_cm_identity_matrix = network.create( hark.node.CMIdentityMatrix, dispatch=hark.RepeatDispatcher) # SourceTracker (音源追跡) node_source_tracker = network.create(hark.node.SourceTracker) # SourceIntervalExtender (定位開始時刻調整) node_source_interval_extender = network.create(hark.node.SourceIntervalExtender) # plotQuickSourceKivy (音源定位結果可視化) node_plotsource_kivy = network.create(plotQuickSourceKivy.plotQuickSourceKivy)
class "HARK_Localization(hark.NetworkDef): def build(self, network, input, output): (上記参照) ...... # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: # 使用したノードを格納したリストを作り build() の返値とする r = [ node_cm_identity_matrix .add_input("NB_CHANNELS", 8) .add_input("LENGTH", 512) , node_constant__for_operation_flag .add_input("VALUE", True) , node_localize_music # パラメータ input を LocalizeMUSIC の INPUT端子 ("INPUT")に接続(上図) .add_input("INPUT", input["INPUT"]) # CMIdentityMatrix のOUTPUT端子を NOISECM入力端子へ接続(上図) .add_input("NOISECM", node_cm_identity_matrix["OUTPUT"]) .add_input("OPERATION_FLAG", node_constant__for_operation_flag["OUTPUT"]) # LocalizeMUSIC の Property における値の設定(下図) .add_input("MUSIC_ALGORITHM", "SEVD") .add_input("A_MATRIX", "tf.zip") .add_input("WINDOW_TYPE", "MIDDLE") .add_input("LOWER_BOUND_FREQUENCY", 3000) .add_input("UPPER_BOUND_FREQUENCY", 6000) .add_input("SPECTRUM_WEIGHT_TYPE", "A_Characteristic") .add_input("ENABLE_EIGENVALUE_WEIGHT", False) .add_input("ENABLE_OUTPUT_SPECTRUM", True) , node_source_tracker .add_input("INPUT", node_localize_music["OUTPUT"]) .add_input("THRESH", 25.0) .add_input("PAUSE_LENGTH", 1200.0) .add_input("MIN_SRC_INTERVAL", 20.0) , node_source_interval_extender .add_input("SOURCES", node_source_tracker["OUTPUT"]) .add_input("PREROLL_LENGTH", 80) , node_plotsource_kivy .add_input("SOURCES", node_source_interval_extender["OUTPUT"]) , ]
Practice3-1: Python LOOPサブネットワーク
- HARK DesignerのLOOPサブネットワーク(下図)を
- PyHARKを使用したPythonプログラムに置き換える(下記プログラム)
- 必要な3つのノードを
network.create
で作成
AudioStreamFromWave/Mic
のかわりにAudioStreamFromMemory
を使用
MultiFFT
(フーリエ変換)
自作した音源定位サブネットワークHARK_Localization
のクラスを指定 - 作成したノードのリストを
build()
の返値とする
clpreass HARK_Loop(hark.NetworkDef): def build(self, network, input, output) ... # AudioStreamFromWave/Mic のかわりに AudioStreamFromMemory を使用 node_audio_stream_from_memory = network.create( hark.node.AudioStreamFromMemory, dispatch=hark.TriggeredMultiShotDispatcher, name="AudioStreamFromMemory") # MultiFFT (フーリエ変換) node_multi_fft = network.create(hark.node.MultiFFT) # 音源定位サブネットワーク HARK_Localization(自作)のクラスを指定 node_sub_localization = network.create(HARK_Localization, name="Localization") r = [ node_audio_stream_from_memory .add_input("INPUT", input["INPUT"]) .add_input("CHANNEL_COUNT", 8), node_multi_fft .add_input("INPUT", node_audio_stream_from_memory["AUDIO"]), node_sub_localization .add_input("SPEC", node_multi_fft["OUTPUT"]), ] output.add_input("OUTPUT", node_sub_localization["OUTPUT"]) return r
Practice3-1: Python MAINネットワーク
- HARK Designer のMAINネットワーク(除く,
Constant
とInputStream
)を - PyHARKを使ってPythonプラグラムに変換
- MAINネットワークをクラスとして定義作成
- ネットワーク全体の入出力を扱うための特殊な2つのノードpublisher と subscriber を作成
- LOOPサブネットを作成
Constant
とInputStream
は作成せず,PyHARKではなく,Python で実装- MAINネットワークのノードの接続と返値の記述
- 入力は publisher["OUTPUT"],出力は subscriber["INPUT"]であることに注意
- 使用したノードを格納したリストを作り,
build()
の返値とする
class HARK_Main(hark.NetworkDef): # サブネットをクラスとして定義 def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # ネットワーク全体の入出力を扱うための特殊な2つのノード # publisher と subscriber を作成 node_publisher = network.create( hark.node.PublishData, dispatch=hark.RepeatDispatcher, name="Publisher" ) node_subscriber= network.create( hark.node.SubscribeData, name="Subscriber" ) # LOOPサブネットを作成 loop = network.create(HARK_Loop, name="HARK_Loop") # LOOPサブネットの入出力 loop.add_input("INPUT", node_publisher["OUTPUT"]), # MAINネットワークへの入力 node_subscriber.add_input("INPUT", loop["OUTPUT"]), # MAINネットワークからの出力 # 使用したノードを格納したリストを作り,build() の返値とする r = [loop, node_subscriber] return r
Practice3-1: Python main
関数
main
関数の構造(Constant
とInputStream
はここで定義)main
関数の入力の定義main
関数のpubliser
と返値の記述
def main(): ... # メインネットワークを構築 network = hark.Network.from_networkdef(HARK_Main, name="HARK_Main") # メインネットワークへの入出力を構築 publisher = network.query_nodedef("Publisher") subscriber = network.query_nodedef("Subscriber") # subscriber がデータを受け取ったとき # (メインネットワークが結果を出力したとき)に # 実行される動作を定義する。 # ここでは pass を用いることで「何もしない」ことを指示する。 def received(data): pass subscriber.receive = received ......
def main(): (上述参照) ...... # WAVファイル読み込み audio, rate = sf.read("input.wav", dtype=np.int16) # 信号を一定間隔 (160サンプル) ごとに分割 # (numpy.lib.stride_tricks.sliding_window_view を使用) frames = sliding_window_view(audio, 160, axis=0)[::160, :, :] # ネットワーク実行用のスレッドを作成し起動 th = threading.Thread(target=network.execute) th.start() ......
def main(): ...... try: for f in frames: if not th.is_alive(): # ネットワークのスレッドが停止していたら, break # それ以上の処理は行わない publisher.push(f) # 分割した音響信号をネットワークに送信 time.sleep(0.01) # リアルタイム処理と同等程度の処理時間となるように送信間隔を調節 finally: # 終了処理 publisher.close() if th.ident is not None: th.join() ......
Practice3-2: PyHARK マイク入力によるオンライン音源定位
PyHARKによるプログラミング: practice-3-1r.py
- 本章での説明の順序は以下の通り
- Practice3-2 では,マイク入力によるオンライン音源定位(practice1-2の改良版)を取り上げる
- HARK Designer によるネットワークファイル:
practice3-1r.n
(以下のプログラム参照) practice3-1r.n
のpractice3-1.n
からの変更点は,- マイク入力(対応するPyHARKによるpythonプログラム:
practice3-2.py
) - 音源分離,音声認識も含む(対応するPyHARKによるpythonプログラム:
practice3-3.py
)
- マイク入力(対応するPyHARKによるpythonプログラム:
#!/usr/bin/env batchflow <?xml version="1.0"?> <Document> <Network type="subnet" name="MAIN"> <Node name="node_LOOP_1" type="LOOP" x="520" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> </Node> <Node name="node_Constant_1" type="Constant" x="100" y="100"> <Parameter name="VALUE" type="string" value="input.wav" description="The value"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_InputStream_1" type="InputStream" x="290" y="100"> <Parameter name="TYPE" type="string" value="" description="Type of stream: stream, fd, or FILE (default stream)"/> <Parameter name="RETRY" type="int" value="" description="If set to N, InputStream will retry N times on open fail"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_Constant_1" output="VALUE" to="node_InputStream_1" input="INPUT"/> <Link from="node_InputStream_1" output="OUTPUT" to="node_LOOP_1" input="INPUT"/> <NetOutput name="ASR-A" node="node_LOOP_1" terminal="ASR-A" object_type="any" description="Dynamic"/> <NetOutput name="DUMMY" node="node_LOOP_1" terminal="DUMMY" object_type="any" description="Dynamic"/> </Network> <Network type="subnet" name="sub_separation"> <Node name="node_GHDSS_1" type="GHDSS" x="100" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> <Parameter name="ADVANCE" type="int" value="160" description="The shift length beween adjacent frames (in samples)[default: 160]."/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling rate (Hz) [default: 16000]."/> <Parameter name="LOWER_BOUND_FREQUENCY" type="int" value="0" description="Lower bound of frequency (Hz). [default: 0]"/> <Parameter name="UPPER_BOUND_FREQUENCY" type="int" value="8000" description="Upper bound of frequency (Hz). [default: 8000]"/> <Parameter name="TF_INPUT_TYPE" type="string" value="FILE" description="Load form TF file or Input terminal."/> <Parameter name="TF_CONJ_FILENAME" type="string" value="tf.zip" description="Filename of a pre-measured transfer function for separation."/> <Parameter name="INITW_FILENAME" type="string" value="" description="Filename of an initial separation matrix. If specified, a matrix in INITW_FILENAME is used as an initial separation matrix. Otherwise, initial separation matrix is estimated from the geometrical relationship or pre-measured TF according to TF_CONJ."/> <Parameter name="SS_METHOD" type="string" value="ADAPTIVE" description="The calculation method for SS step size parameter corresponding to the blind separation part. "FIX" uses a fixed step size,"LC_MYU" uses the same value as LC_MYU, and "ADAPTIVE" adaptively estimates an optimal step size. [default: ADAPTIVE]"/> <Parameter name="SS_SCAL" type="float" value="1.0" description="Scaling factor for SS step size. [default: 1.0]"/> <Parameter name="SS_MYU" type="float" value="0.001" description="SS step size value. [default 0.001]"/> <Parameter name="NOISE_FLOOR" type="float" value="0.0" description="Noise floor value. [default 0.0]"/> <Parameter name="LC_CONST" type="string" value="DIAG" description="The calculation method for geometric constraints. "FULL" uses all elements of a matrix, and "DIAG" only uses diagonal parts. [default: FULL]"/> <Parameter name="LC_METHOD" type="string" value="ADAPTIVE" description="The calculation method for LC step size corresponding to geometric constraints. "FIX" uses a fixed value, and "Adaptive" adaptively estimates an optimal step size. [default: ADAPTIVE]"/> <Parameter name="LC_MYU" type="float" value="0.001" description="LC step size value. [default 0.001]"/> <Parameter name="UPDATE_METHOD_TF_CONJ" type="string" value="POS" description="Switching method of TF_CONJ data. [default: POS]"/> <Parameter name="UPDATE_METHOD_W" type="string" value="ID" description="Switching method of separation matrix, W. [default: ID]"/> <Parameter name="UPDATE_ACCEPT_DISTANCE" type="float" value="300" description="Distance allowance to switch separation matrix in [mm]. available when when UPDATE_METHOD_W is POS or ID_POS. [default: 300.0]"/> <Parameter name="EXPORT_W" type="bool" value="false" description="Separation matrix W is exported if true. [default: false]"/> <Parameter name="EXPORT_W_FILENAME" type="string" value="" description="The filename to export W."/> <Parameter name="UPDATE" type="string" value="STEP" description="The update method of separation matrix. "STEP" updates W sequentially, i.e., based on SS and then on LC cost. "TOTAL" updates W based on an integrated value of SS and LC cost [default: STEP]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SaveWavePCM_1" type="SaveWavePCM" x="580" y="200"> <Parameter name="BASENAME" type="string" value="sep_" description="Basename of files. [default: sep_]"/> <Parameter name="ADVANCE" type="int" value="160" description="The shift length beween adjacent frames (in samples)[default: 160]."/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling rate (in samples)[default: 16000]."/> <Parameter name="BITS" type="string" value="int24" description="Bit format of samples. int16 and int24 bits are supported."/> <Parameter name="INPUT_BITS" type="string" value="auto" description="Bit format of input wav file."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_Synthesize_1" type="Synthesize" x="370" y="200"> <Parameter name="LENGTH" type="int" value="512" description="Size of window length in sample. [default: 512]"/> <Parameter name="ADVANCE" type="int" value="160" description="The length in sample between a frame and a previous frame. [default: 160]"/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling rate (Hz) [default: 16000]."/> <Parameter name="MIN_FREQUENCY" type="int" value="125" description="Minimum frequency (Hz) [default: 125]"/> <Parameter name="MAX_FREQUENCY" type="int" value="7900" description="Maximum frequency (Hz) [default: 7900]"/> <Parameter name="WINDOW" type="string" value="HAMMING" description="A window function for overlap-add. WINDOW should be CONJ, HAMMING, RECTANGLE, or HANNING. [default: HAMMING]"/> <Parameter name="OUTPUT_GAIN" type="float" value="1.0" description="Output gain factor. [default: 1.0]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_Synthesize_1" output="OUTPUT" to="node_SaveWavePCM_1" input="INPUT"/> <Link from="node_GHDSS_1" output="OUTPUT" to="node_Synthesize_1" input="INPUT"/> <NetInput name="SPEC" node="node_GHDSS_1" terminal="INPUT_FRAMES" object_type="Matrix<complex<float> >" description="Input multi-channel spectrum. A row is a channel, and a column is a spectrum for the corresponding channel."/> <NetInput name="SOURCE" node="node_GHDSS_1" terminal="INPUT_SOURCES" object_type="Vector<ObjectRef>" description="Source locations with ID. Each element of the vector is a source location with ID specified by "Source"."/> <NetOutput name="DUMMY" node="node_SaveWavePCM_1" terminal="OUTPUT" object_type="Map<int,ObjectRef>" description="The same as input."/> <NetOutput name="OUTPUT" node="node_GHDSS_1" terminal="OUTPUT" object_type="Map<int,ObjectRef>" description="Separated spectrum with a source ID(key), and the value is the separated spectrum for each sound source (Vector<complex<float> >)."/> </Network> <Network type="subnet" name="sub_recognition"> <Node name="node_Delta_1" type="Delta" x="1070" y="130"> <Parameter name="FBANK_COUNT" type="int" value="41" description="The size of the input feature vector."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_FeatureRemover_1" type="FeatureRemover" x="370" y="310"> <Parameter name="SELECTOR" type="object" value="<Vector<int> 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81>" description="Component indices in a feature vector to remove. E.g. <Vector<int> 13> to remove 14th comopnent (The index start with 0)."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_MSLSExtraction_1" type="MSLSExtraction" x="800" y="130"> <Parameter name="FBANK_COUNT" type="subnet_param" value="FBANK_COUNT" description="Size of the static part of MSLS feature vector. [default: 13]"/> <Parameter name="NORMALIZATION_MODE" type="string" value="SPECTRAL" description="The domain to perform normalization. CEPSTRAL or SPECTRAL. [default: CEPSTRAL]"/> <Parameter name="USE_LEGACY_MODE" type="bool" value="true" description="For more than 14 dimensions must use false. This parameter is preparing only for compatibility with HARK 2.x or earlier. [default: true]"/> <Parameter name="USE_HTK_LIFTER" type="bool" value="false" description="Use HTK liftering vector if true. [default: false]"/> <Parameter name="LIFTERING_COEF" type="int" value="22" description="The HTK liftering coefficient used in Cepstral mode. [default: 22]"/> <Parameter name="USE_POWER" type="bool" value="true" description="Use power feature if true. [default: false]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_MelFilterBank_1" type="MelFilterBank" x="570" y="100"> <Parameter name="LENGTH" type="subnet_param" value="LENGTH" description="Size of window length in sample. [default: 512]"/> <Parameter name="SAMPLING_RATE" type="subnet_param" value="SAMPLING_RATE" description="Sampling rate in Hz. [default: 16000]"/> <Parameter name="CUTOFF" type="int" value="8000" description="Cutoff frequency in Hz. Mel-filterbanks are placed between 0 Hz and CUTOFF Hz. [default: 8000]"/> <Parameter name="MIN_FREQUENCY" type="int" value="63" description="Minimum frequency (Hz) [default: 63]"/> <Parameter name="MAX_FREQUENCY" type="int" value="8000" description="Maximum frequency (Hz) [default: 8000]"/> <Parameter name="FBANK_COUNT" type="subnet_param" value="FBANK_COUNT" description="The number of Mel filter banks. [default: 13]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_PreEmphasis_1" type="PreEmphasis" x="350" y="150"> <Parameter name="LENGTH" type="subnet_param" value="LENGTH" description="window length in sample [default: 512]"/> <Parameter name="SAMPLING_RATE" type="subnet_param" value="SAMPLING_RATE" description="Sampling rate in Hz [default: 16000]"/> <Parameter name="PREEMCOEF" type="float" value="0.97" description="pre-emphasis coefficient [default: 0.97]"/> <Parameter name="INPUT_TYPE" type="string" value="SPECTRUM" description="The domain to perform pre-emphasis [default: WAV]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SpeechRecognitionClient_1" type="SpeechRecognitionClient" x="1130" y="310"> <Parameter name="MFM_ENABLED" type="bool" value="false" description="MFM is enbaled if true. [default: true]"/> <Parameter name="HOST" type="string" value="127.0.0.1" description="Hostname or IP of Julius/Julian server. [default: 127.0.0.1]"/> <Parameter name="PORT" type="int" value="5530" description="Port number of Julius/Julian server. [default: 5530]"/> <Parameter name="SOCKET_ENABLED" type="bool" value="true" description="send data via socket if true. [default: true]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SpectralMeanNormalizationIncremental_1" type="SpectralMeanNormalizationIncremental" x="620" y="310"> <Parameter name="FBANK_COUNT" type="int" value="13" description="Size of a static part of a feature vector. [default: 13]"/> <Parameter name="PERIOD" type="int" value="20" description="Period to calculate SM. If 1, SM calculated in every frame. If 0, SM_ALGORITHM is used for all frames. [default: 20]"/> <Parameter name="SM_ALGORITHM" type="string" value="INCREMENTAL" description="Algorithm to decide the initial SM until reaching PERIOD + IGNORE_FRAMES. If INCREMENTAL, SM is calculated in every frame. If PREV_SM, SM is taken from the previous source. If ZERO, SM is zeroed. If FILE, SM is loaded from SM_FILENAME."/> <Parameter name="SM_FILENAME" type="string" value="" description="csv file name of the initial SM until reaching PERIOD + IGNORE_FRAMES."/> <Parameter name="SM_HISTORY_FILENAME" type="string" value="" description="csv file name of the initial spectral history for an initial SM"/> <Parameter name="IGNORE_FRAMES" type="int" value="0" description="Number of first ingnored frames to calculate SM [default: 0]"/> <Parameter name="BASENAME" type="string" value="smn_" description="Basename of SMN files. The filename will be BASENAME+id+.csv [default: smn_]"/> <Parameter name="OUTPUT_FNAME" type="string" value="out.txt" description="No Description Available"/> <Parameter name="SM_EXPORT_FILENAME" type="string" value="" description="csv file name of the export SM which follows SM_EXPORT_ALGORITHM. If vacant, the exporting is disabled."/> <Parameter name="SM_EXPORT_ALGORITHM" type="string" value="LAST_SRC" description="Algorithm to decide the SM for exporting. If LAST_SRC, SM of the last source is saved. If SRC_AVERAGE, SM of all the sources are averaged and saved. If FRAME_AVERAGE, SM of all the frames in all sources are averaged and saved."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_MelFilterBank_1" output="OUTPUT" to="node_MSLSExtraction_1" input="FBANK"/> <Link from="node_MSLSExtraction_1" output="OUTPUT" to="node_Delta_1" input="INPUT"/> <Link from="node_Delta_1" output="OUTPUT" to="node_FeatureRemover_1" input="INPUT"/> <Link from="node_PreEmphasis_1" output="OUTPUT" to="node_MelFilterBank_1" input="INPUT"/> <Link from="node_PreEmphasis_1" output="OUTPUT" to="node_MSLSExtraction_1" input="SPECTRUM"/> <Link from="node_FeatureRemover_1" output="OUTPUT" to="node_SpectralMeanNormalizationIncremental_1" input="INPUT"/> <Link from="node_SpectralMeanNormalizationIncremental_1" output="OUTPUT" to="node_SpeechRecognitionClient_1" input="FEATURES"/> <Link from="node_SpectralMeanNormalizationIncremental_1" output="OUTPUT" to="node_SpeechRecognitionClient_1" input="MASKS"/> <NetOutput name="ASR-A" node="node_SpeechRecognitionClient_1" terminal="OUTPUT" object_type="Vector<ObjectRef>" description="The same as SOURCES."/> <NetInput name="SPEC" node="node_PreEmphasis_1" terminal="INPUT" object_type="Map<int,ObjectRef>" description="ObjectRef is a spectrum (Vector<complex<float> >) or a wave form (Vector<float>)."/> <NetInput name="SOURCES" node="node_SpeechRecognitionClient_1" terminal="SOURCES" object_type="Vector<ObjectRef>" description="Source locations with ID. Each element of the vector is a source location with ID specified by "Source"."/> </Network> <Network type="subnet" name="sub_localization"> <Node name="node_LocalizeMUSIC_1" type="LocalizeMUSIC" x="320" y="100"> <Parameter name="MUSIC_ALGORITHM" type="string" value="SEVD" description="Sound Source Localization Algorithm. If SEVD, NOISECM will be ignored"/> <Parameter name="TF_CHANNEL_SELECTION" type="object" value="<Vector<int> 0 1 2 3 4 5 6 7>" description="Microphone channels for localization. If vacant, all channels will be used."/> <Parameter name="LENGTH" type="subnet_param" value="LENGTH" description="The length of a frame (per channel)."/> <Parameter name="SAMPLING_RATE" type="subnet_param" value="SAMPLING_RATE" description="Sampling Rate (Hz)."/> <Parameter name="TF_INPUT_TYPE" type="string" value="FILE" description="Load form TF file or Input terminal."/> <Parameter name="A_MATRIX" type="string" value="tf.zip" description="Filename of a transfer function matrix."/> <Parameter name="WINDOW" type="int" value="50" description="The number of frames used for calculating a correlation function."/> <Parameter name="WINDOW_TYPE" type="string" value="MIDDLE" description="Window selection to accumulate a correlation function. If PAST, the past WINDOW frames from the current frame are used for the accumulation. If MIDDLE, the current frame will be the middle of the accumulated frames. If FUTURE, the future WINDOW frames from the current frame are used for the accumulation. FUTURE is the default from version 1.0, but this makes a delay since we have to wait for the future information. PAST generates a internal buffers for the accumulation, which realizes no delay for localization."/> <Parameter name="PERIOD" type="int" value="50" description="The period in which the source localization is processed."/> <Parameter name="NUM_SOURCE" type="int" value="2" description="Number of sources, which should be less than number of channels."/> <Parameter name="MIN_DEG" type="int" value="-180" description="source direction (lower)."/> <Parameter name="MAX_DEG" type="int" value="180" description="source direction (higher)."/> <Parameter name="LOWER_BOUND_FREQUENCY" type="int" value="3000" description="Lower bound of frequency (Hz) used for correlation function calculation."/> <Parameter name="UPPER_BOUND_FREQUENCY" type="int" value="6000" description="Upper bound of frequency (Hz) used for correlation function calculation."/> <Parameter name="SPECTRUM_WEIGHT_TYPE" type="string" value="A_Characteristic" description="MUSIC spectrum weight for each frequency bin."/> <Parameter name="A_CHAR_SCALING" type="float" value="1.0" description="Scaling factor of the A-Weight with respect to frequency"/> <Parameter name="MANUAL_WEIGHT_SPLINE" type="object" value="<Matrix<float> <rows 2> <cols 5> <data 0.0 2000.0 4000.0 6000.0 8000.0 1.0 1.0 1.0 1.0 1.0> >" description="MUSIC spectrum weight for each frequency bin. This is a 2 by M matrix. The first row represents the frequency, and the second row represents the weight gain. "M" represents the number of key points for the spectrum weight. The frequency range between M key points will be interpolated by spline manner. The format is "<Matrix<float> <rows 2> <cols 2> <data 1 2 3 4> >"."/> <Parameter name="MANUAL_WEIGHT_SQUARE" type="object" value="<Vector<float> 0.0 2000.0 4000.0 6000.0 8000.0>" description="MUSIC spectrum weight for each frequency bin. This is a M order vector. The element represents the frequency points for the square wave. "M" represents the number of key points for the square wave weight. The format is "<Vector<float> 1 2 3 4>"."/> <Parameter name="ENABLE_EIGENVALUE_WEIGHT" type="bool" value="false" description="If true, the spatial spectrum is weighted depending on the eigenvalues of a correlation matrix. We do not suggest to use this function with GEVD and GSVD, because the NOISECM changes the eigenvalue drastically. Only useful for SEVD."/> <Parameter name="MAXNUM_OUT_PEAKS" type="int" value="-1" description="Maximum number of output peaks. If MAXNUM_OUT_PEAKS = NUM_SOURCE, this is compatible with HARK version 1.0. If MAXNUM_OUT_PEAKS = 0, all local maxima are output. If MAXNUM_OUT_PEAKS < 0, MAXNUM_OUT_PEAKS is set to NUM_SOURCE. If MAXNUM_OUT_PEAKS > 0, number of output peaks is limited to MAXNUM_OUT_PEAKS."/> <Parameter name="DEBUG" type="bool" value="true" description="Debug option. If the parameter is true, this node outputs sound localization results to a standard output."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SourceTracker_1" type="SourceTracker" x="540" y="100"> <Parameter name="THRESH" type="float" value="25" description="Power threshold for localization results. A localization result with higher power than THRESH is tracked, otherwise ignored."/> <Parameter name="PAUSE_LENGTH" type="float" value="1200" description="Life duration of source in ms. When any localization result for a source is found for more than PAUSE_LENGTH / 10 iterations, the source is terminated. [default: 800]"/> <Parameter name="MIN_SRC_INTERVAL" type="float" value="20" description="Source interval threshold in degree. When the angle between a localization result and a source is smaller than MIN_SRC_INTERVAL, the same ID is given to the localization result. [default: 20]"/> <Parameter name="MIN_ID" type="int" value="0" description="Minimum ID of source locations. MIN_ID should be greater than 0 or equal."/> <Parameter name="DEBUG" type="bool" value="false" description="Output debug information if true [default: false]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_SourceIntervalExtender_1" type="SourceIntervalExtender" x="770" y="100"> <Parameter name="PREROLL_LENGTH" type="int" value="80" description="Preroll length in frame. [default: 50]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_plotQuickSourceKivy_1" type="plotQuickSourceKivy" x="1060" y="100"> </Node> <Node name="node_CMIdentityMatrix_1" type="CMIdentityMatrix" x="50" y="190"> <Parameter name="NB_CHANNELS" type="int" value="8" description="The number of input channels."/> <Parameter name="LENGTH" type="int" value="512" description="The length of a frame (per channel)."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_LocalizeMUSIC_1" output="OUTPUT" to="node_SourceTracker_1" input="INPUT"/> <Link from="node_SourceTracker_1" output="OUTPUT" to="node_SourceIntervalExtender_1" input="SOURCES"/> <Link from="node_SourceIntervalExtender_1" output="OUTPUT" to="node_plotQuickSourceKivy_1" input="SOURCES"/> <Link from="node_CMIdentityMatrix_1" output="OUTPUT" to="node_LocalizeMUSIC_1" input="NOISECM"/> <NetOutput name="OUTPUT" node="node_plotQuickSourceKivy_1" terminal="OUTPUT" object_type="any" description=""/> <NetInput name="INPUT" node="node_LocalizeMUSIC_1" terminal="INPUT" object_type="Matrix<complex<float> >" description="Multi-channel audio signals. In this matrix, a row is a channel, and a column is a sample."/> </Network> <Network type="iterator" name="LOOP"> <Node name="node_MultiFFT_1" type="MultiFFT" x="630" y="100"> <Parameter name="LENGTH" type="subnet_param" value="LENGTH" description="FFT length in sample. [default: 512]"/> <Parameter name="WINDOW" type="string" value="CONJ" description="A window function for FFT. WINDOW should be CONJ, HAMMING, RECTANGLE, or HANNING. [default: CONJ]"/> <Parameter name="WINDOW_LENGTH" type="subnet_param" value="LENGTH" description="Window length of the window function. [default: 512]"/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Node name="node_sub_separation_1" type="sub_separation" x="1090" y="100"> </Node> <Node name="node_sub_recognition_1" type="sub_recognition" x="1330" y="170"> <Parameter name="FBANK_COUNT" type="int" value="40" description="The size of the input feature vector."/> <Parameter name="LENGTH" type="int" value="512" description="Size of window length in sample. [default: 512]"/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling rate in Hz. [default: 16000]"/> </Node> <Node name="node_sub_localization_1" type="sub_localization" x="840" y="190"> <Parameter name="LENGTH" type="int" value="512" description="The length of a frame (per channel)."/> <Parameter name="SAMPLING_RATE" type="int" value="16000" description="Sampling Rate (Hz)."/> </Node> <Node name="node_AudioStreamFromWave_1" type="AudioStreamFromWave" x="300" y="100"> <Parameter name="LENGTH" type="int" value="512" description="The frame length of each channel (in samples) [default: 512]."/> <Parameter name="ADVANCE" type="int" value="160" description="The shift length beween adjacent frames (in samples)[default: 160]."/> <Parameter name="USE_WAIT" type="bool" value="false" description="If true, real recording is simulated [default: false]."/> <Parameter name="HARKMW.PROCESS" type="string" value="local" description="Specify a name that indicates the machine to be executed. [default: local]"/> <Parameter name="HARKMW.TOPIC" type="string" value="local" description="Specifies the prefix of the topic name used for data transmission and reception by MQTT. [default: local] In actual transmission, '/<terminal name>' is added to the value specified here. e.g.) 'local/VALUE'"/> </Node> <Link from="node_MultiFFT_1" output="OUTPUT" to="node_sub_separation_1" input="SPEC"/> <Link from="node_sub_localization_1" output="OUTPUT" to="node_sub_separation_1" input="SOURCE"/> <Link from="node_sub_separation_1" output="OUTPUT" to="node_sub_recognition_1" input="SPEC"/> <Link from="node_sub_localization_1" output="OUTPUT" to="node_sub_recognition_1" input="SOURCES"/> <Link from="node_MultiFFT_1" output="OUTPUT" to="node_sub_localization_1" input="INPUT"/> <Link from="node_AudioStreamFromWave_1" output="AUDIO" to="node_MultiFFT_1" input="INPUT"/> <NetInput name="INPUT" node="node_AudioStreamFromWave_1" terminal="INPUT" object_type="Stream" description="An audio input stream (IStream)."/> <NetOutput name="ASR-A" node="node_sub_recognition_1" terminal="ASR-A" object_type="any" description="Dynamic"/> <NetOutput name="DUMMY" node="node_sub_separation_1" terminal="DUMMY" object_type="Map<int,ObjectRef>" description="The same as input."/> <NetCondition name="CONDITION" node="node_AudioStreamFromWave_1" terminal="NOT_EOF"/> </Network> </Document>
- まずマイク入力のチェックを行う
- PyHARK によるPythonプログラム: b>
ractice3-2.py
の解説
Practice3-2: PyHARKによるマイクのチェックとオンライン音源定位の稼働
- ターミナルを開いてオーディオデバイスを確認
- 使いたいデバイス名か番号を覚えておく
- プログラムを実行する ("-d 2" でデバイス番号かデバイス名を指定)
- マイルアレイに向かって発声
- 定位結果が表示される
- マイクの向きを変えると定位結果はどう変わる?
- Ctrl-C で修了
- 動かない場合の対処法
- Ctrl-Z で一時停止,kill %1 などでジョブ停止
- マイクアレイを抜いて,差し直す
$ cd practice3/data $ python practice3-2.py -l 0 Ensoniq AudioPCI: ES1371 DAC2/ADC (hw:0,0), ALSA (2 in, 0 out) 1 Ensoniq AudioPCI: ES1371 DAC1 (hw:0,1), ALSA (0 in, 2 out) 2 TAMAGO-XX: USB Audio (hw:1,0), ALSA (8 in, 0 out) 3 sysdefault, ALSA (128 in, 0 out) 4 samplerate, ALSA (128 in, 0 out) 5 speexrate, ALSA (128 in, 0 out) 6 pulse, ALSA (32 in, 32 out) 7 upmix, ALSA (8 in, 0 out) 8 vdownmix, ALSA (6 in, 0 out) * 9 default, ALSA (32 in, 32 out)
$ python practice3-2.py -d 2
マイク入力オンライン音源定位プログラム practice3-2.py
の詳細
Practice3-2: practice3-2.py
の全体構造
- 全体の基本構造はファイル入力版
practice3-1.py
と同じ#!/usr/bin/env python import hark # 必要なモジュールを import import argparse # コマンドライン引数処理 import sounddevice as sd # マイクアレイで録音 class HARK_Localization(hark.NetworkDef): # 音源定位サブネットワーク def build(self, network, input, output): ...... class HARK_Main_Loop(hark.NetworkDef): # 波形データを受け取りFFT実行 def build(self, network, input, output): # 入力:8ch音響信号 ⇒ フーリエ変換、MUSIC法による音源定位、音源追跡 ⇒ 結果の表示 class HARK_Main(hark.NetworkDef): # メインネットワーク def build(self, network, input, output): ...... def main(): # main関数 ...... if __name__ == '__main__': main()
practice3-2.py
は次の通り:#! /usr/bin/env python # -*- coding: utf-8 -*- import sys import threading import time import argparse import tempfile import numpy as np import hark import sounddevice as sd import soundfile as sf # import plotQuickWaveformKivy # import plotQuickSpecKivy # import plotQuickMusicSpecKivy import plotQuickSourceKivy class HARK_Localization(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_cm_identity_matrix = network.create( hark.node.CMIdentityMatrix, dispatch=hark.RepeatDispatcher ) node_constant__for_operation_flag = network.create( hark.node.Constant, dispatch=hark.RepeatDispatcher ) node_localize_music = network.create(hark.node.LocalizeMUSIC) node_source_tracker = network.create(hark.node.SourceTracker) node_source_interval_extender = network.create(hark.node.SourceIntervalExtender) node_plotsource_kivy = network.create(plotQuickSourceKivy.plotQuickSourceKivy) except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_cm_identity_matrix .add_input("NB_CHANNELS", 8) .add_input("LENGTH", 512) , node_constant__for_operation_flag .add_input("VALUE", True) , node_localize_music .add_input("INPUT", input["SPEC"]) .add_input("NOISECM", node_cm_identity_matrix["OUTPUT"]) .add_input("OPERATION_FLAG", node_constant__for_operation_flag["OUTPUT"]) .add_input("MUSIC_ALGORITHM", "SEVD") .add_input("A_MATRIX", "tf.zip") .add_input("WINDOW_TYPE", "MIDDLE") .add_input("LOWER_BOUND_FREQUENCY", 3000) .add_input("UPPER_BOUND_FREQUENCY", 6000) .add_input("SPECTRUM_WEIGHT_TYPE", "A_Characteristic") .add_input("ENABLE_EIGENVALUE_WEIGHT", False) .add_input("ENABLE_OUTPUT_SPECTRUM", True) , node_source_tracker .add_input("INPUT", node_localize_music["OUTPUT"]) .add_input("THRESH", 25.0) .add_input("PAUSE_LENGTH", 1200.0) #.add_input("MIN_SRC_INTERVAL", 20.0) , node_source_interval_extender .add_input("SOURCES", node_source_tracker["OUTPUT"]) .add_input("PREROLL_LENGTH", 80) , node_plotsource_kivy .add_input("SOURCES", node_source_interval_extender["OUTPUT"]) , ] output.add_input("OUTPUT", node_source_interval_extender["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r class HARK_Main_Loop(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_audio_stream_from_memory = network.create( hark.node.AudioStreamFromMemory, dispatch=hark.TriggeredMultiShotDispatcher, name="AudioStreamFromMemory" ) node_multi_fft = network.create(hark.node.MultiFFT) node_sub_localization = network.create( HARK_Localization, name="Localization" ) except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_audio_stream_from_memory .add_input("INPUT", input["INPUT"]) .add_input("CHANNEL_COUNT", 8) , node_multi_fft .add_input("INPUT", node_audio_stream_from_memory["AUDIO"]) , node_sub_localization .add_input("SPEC", node_multi_fft["OUTPUT"]) , ] output.add_input("OUTPUT", node_sub_localization["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r class HARK_Main(hark.NetworkDef): '''メインネットワークに相当するクラス。 入力として8ch音響信号を受け取り、 フーリエ変換、MUSIC法による音源定位、音源追跡を行い、 その結果を図示する。 ''' def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する. # - 全体の入出力を扱う Publisher と Subscriber # - HARK_Main_Loop サブネット try: node_publisher = network.create( hark.node.PublishData, dispatch=hark.RepeatDispatcher, name="Publisher" ) node_subscriber = network.create( hark.node.SubscribeData, name="Subscriber" ) loop = network.create( HARK_Main_Loop, name="HARK_Main_Loop" ) except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ loop .add_input("INPUT", node_publisher["OUTPUT"]) , node_subscriber .add_input("INPUT", loop["OUTPUT"]) , ] except BaseException as ex: print(ex) # ノード一覧のリストを返す return r def main(): def int_or_str(text): """Helper function for argument parsing.""" try: return int(text) except ValueError: return text parser = argparse.ArgumentParser(add_help=False) parser.add_argument( '-l', '--list-devices', action='store_true', help='show list of audio devices and exit') args, remaining = parser.parse_known_args() if args.list_devices: print(sd.query_devices()) parser.exit(0) parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parser]) parser.add_argument( 'filename', nargs='?', metavar='FILENAME', help='audio file to store recording to') parser.add_argument( '-d', '--device', type=int_or_str, help='input device (numeric ID or substring)') parser.add_argument( '-r', '--samplerate', type=int, default=16000, help='sampling rate') parser.add_argument( '-c', '--channels', type=int, default=8, help='number of input channels') parser.add_argument( '-t', '--subtype', type=str, help='sound file subtype (e.g. "PCM_24")') args = parser.parse_args(remaining) if args.samplerate is None: device_info = sd.query_devices(args.device, 'input') # soundfile expects an int, sounddevice provides a float: args.samplerate = int(device_info['default_samplerate']) if args.channels is None: device_info = sd.query_devices(args.device, 'input') args.channels = device_info['max_input_channels'] if args.filename is None: args.filename = tempfile.mktemp(prefix='practice3-2_', suffix='.wav', dir='') # メインネットワークを構築 network = hark.Network.from_networkdef(HARK_Main, name="HARK_Main") # メインネットワークへの入出力を構築 publisher = network.query_nodedef("Publisher") subscriber = network.query_nodedef("Subscriber") # subscriber がデータを受け取ったとき # (メインネットワークが結果を出力したとき)に # 実行される動作を定義する。 # ここでは pass を用いることで「何もしない」ことを指示する。 def received(data): pass subscriber.receive = received def callback(indata, frames, time, status): # print(indata.shape, time.currentTime) publisher.push(indata.T) try: # ネットワーク実行用スレッドを開始 th = threading.Thread(target=network.execute) th.start() with sd.InputStream(samplerate=args.samplerate, blocksize=160, device=args.device, dtype=np.int16, channels=args.channels, callback=callback) as stream: print('#' * 75) print('press Ctrl+C to stop the recording') print('#' * 75) th.join() except BaseException as ex: print(ex) except: network.stop() finally: # 終了処理 publisher.close() if th.ident is not None: th.join() if __name__ == '__main__': main() # end of file
Practice3-2:
sub_Localization
関数class HARK_Localization(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_cm_identity_matrix = network.create( hark.node.CMIdentityMatrix, dispatch=hark.RepeatDispatcher ) node_constant__for_operation_flag = network.create( hark.node.Constant, dispatch=hark.RepeatDispatcher ) node_localize_music = network.create(hark.node.LocalizeMUSIC) node_source_tracker = network.create(hark.node.SourceTracker) node_source_interval_extender = network.create(hark.node.SourceIntervalExtender) node_plotsource_kivy = network.create(plotQuickSourceKivy.plotQuickSourceKivy) except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_cm_identity_matrix .add_input("NB_CHANNELS", 8) .add_input("LENGTH", 512) , node_constant__for_operation_flag .add_input("VALUE", True) , node_localize_music .add_input("INPUT", input["SPEC"]) .add_input("NOISECM", node_cm_identity_matrix["OUTPUT"]) .add_input("OPERATION_FLAG", node_constant__for_operation_flag["OUTPUT"]) .add_input("MUSIC_ALGORITHM", "SEVD") .add_input("A_MATRIX", "tf.zip") .add_input("WINDOW_TYPE", "MIDDLE") .add_input("LOWER_BOUND_FREQUENCY", 3000) .add_input("UPPER_BOUND_FREQUENCY", 6000) .add_input("SPECTRUM_WEIGHT_TYPE", "A_Characteristic") .add_input("ENABLE_EIGENVALUE_WEIGHT", False) .add_input("ENABLE_OUTPUT_SPECTRUM", True) , node_source_tracker .add_input("INPUT", node_localize_music["OUTPUT"]) .add_input("THRESH", 25.0) .add_input("PAUSE_LENGTH", 1200.0) #.add_input("MIN_SRC_INTERVAL", 20.0) , node_source_interval_extender .add_input("SOURCES", node_source_tracker["OUTPUT"]) .add_input("PREROLL_LENGTH", 80) , node_plotsource_kivy .add_input("SOURCES", node_source_interval_extender["OUTPUT"]) , ] output.add_input("OUTPUT", node_source_interval_extender["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r
Practice3-2:
main
関数main
関数の構造main
関数でMAINネットワークの作成・データ受信時の動作定義main
関数のpublisher
と返り値の記述
def main(): parser = argparse.ArgumentParser(add_help=False) # コマンドライン引数処理 parser.add_argument( '-l', '--list-devices', action='store_true', # -l が指定:デバイス一覧を出力して終了 help='show list of audio devices and exit') args, remaining = parser.parse_known_args() if args.list_devices: print(sd.query_devices()) parser.exit(0) parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, parents=[parser]) parser.add_argument( '-d', '--device', type=int_or_str, help='input device (numeric ID or substring)') # -d が指定 parser.add_argument( '-r', '--samplerate', type=int, help='sampling rate') # -r が指定 parser.add_argument( # -c が指定 '-c', '--channels', type=int, default=1, help='number of input channels') args = parser.parse_args(remaining)
def main(): ...... network = hark.Network.from_networkdef( # メインネットワークを作成 HARK_Main, name="HARK_Main") publisher = network.query_nodedef("Publisher") subscriber = network.query_nodedef("Subscriber") def received(data): # subscriber がデータをたときに実行される動作を定義 pass subscriber.receive = received th = threading.Thread(target=network.execute) # 新たなスレッドを作成しネットワーク実行 th.start() ......
def main(): ...... # 録音時のコールバック関数を定義. 得られた配列を publisher に渡す def callback(indata, frames, time, status): publisher.push(np.copy(indata.T)) # HARKに適したデータの配列 [nch, samples] にするため行列を転置 try: with sd.InputStream(samplerate=args.samplerate, device=args.device, dtype=np.int16, channels=args.channels, callback=callback) as stream: print('press Ctrl+C to stop the recording') th.join() # オーディオデバイスで録音開始 ......
practice3-2.py
の音声認識- HARK Designer による音声認識(Practice2)
- PyHARKによるPythonプログラムに変換(practice3-2.py)
import hark class HARK_Localization(hark.NetworkDef): def build(self, network, input, output): ...... class HARK_Separation(hark.NetworkDef): def build(self, network, input, output): ...... class HARK_Recognition(hark.NetworkDef): def build(self, network, input, output): ...... class HARK_Main(hark.NetworkDef): def build(self, network, input, output): node_publisher = network.create(hark.node.PublishData, dispatch=hark.RepeatDispatcher, name="Publisher") node_subscriber = network.create(hark.node.SubscribeData, name="Subscriber") node_audio_stream_from_memory = network.create(hark.node.AudioStreamFromMemory, dispatch=hark.TriggeredMultiShotDispatcher) node_multi_fft = network.create(hark.node.MultiFFT) node_localization = network.create(HARK_Localization, name="HARK_Localization") node_separation = network.create(HARK_Separation, name="HARK_Separation") node_recognition = network.create(HARK_Separation, name="HARK_Recognition") node_audio_stream_from_memory.add_input("INPUT", node_publisher["OUTPUT"]).add_input("CHANNEL_COUNT", 8) node_multi_fft.add_input("INPUT", node_audio_stream_from_memory["AUDIO"]) node_localization.add_input("INPUT", node_multi_fft["OUTPUT"]) node_separation.add_input("SPEC", node_multi_fft["OUTPUT"]).add_input("SRC_INFO", node_localization["OUTPUT"]) node_recognition.add_input("SPEC", node_separation[“SPEC"]).add_input("SRC_INFO", node_localization["OUTPUT"]) node_subscriber.add_input("INPUT", node_separation["OUTPUT"]) r = [node_publisher, node_subscriber, node_audio_stream_from_memory, node_multi_fft, node_localization, node_separation, node_recognition] return r ......
practice3-2r.py 実行前準備 音声認識エンジンの起動
- Kaldidecoderを起動
cd practice2/data sh 1_run_ASR.sh [INFO] This software includes work that is distributed under the Apache License 2.0 . ...... [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.1125 seconds in looped compilation. [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.107063 seconds in looped compilation.
- 起動処理が終わり表示が落ち着くまで待つ
practice3-2r.py 実行前準備 オーディオデバイスの確認
- ターミナルを開きオーディオデバイスを確認
- 使いたいデバイス名か番号を覚えておく(例えば,TAMAGO-XXX あるいは2)
cd practice3/data python practice3-2r.py -l 0 Ensoniq AudioPCI: ES1371 DAC2/ADC (hw:0,0), ALSA (2 in, 0 out) 1 Ensoniq AudioPCI: ES1371 DAC1 (hw:0,1), ALSA (0 in, 2 out) 2 TAMAGO-XX: USB Audio (hw:1,0), ALSA (8 in, 0 out) 3 sysdefault, ALSA (128 in, 0 out) 4 samplerate, ALSA (128 in, 0 out) 5 speexrate, ALSA (128 in, 0 out) 6 pulse, ALSA (32 in, 32 out) 7 upmix, ALSA (8 in, 0 out) 8 vdownmix, ALSA (6 in, 0 out) * 9 default, ALSA (32 in, 32 out)
Practice3-2: Pythonで practice3-2r.py を動かす
- 入力デバイスを指定してプログラムを実行(-d デバイス番号 or デバイス名)
python practice3-2r.py -d 2
- マイクにむかって発話
- 定位・分離・認識が実行される
[INFO] 5.77266 sec, RT=1.36793 source_id = 7, azimuth = 79.982063, elevation = 36.869900, sec = 1668056389, usec = 904003 ### Recognition: 2nd pass (RL heuristic best-first) STAT: 00 sentence1: 一 週間 ばかり ニューヨーク を 取材 し た wseq1: 一+名詞/数詞 週間+接尾辞 ばかり+助詞/副助詞 ニューヨーク+名詞/固有名詞 を+助詞/格助詞 取材+名詞 し+動詞/サ行変格/連用形 た+助動詞/連体形 ......
- Ctrl-C で終了
- 動かない場合の対処法
- Ctrl-Z で一時停止,kill %1 などでジョブ停止
- マイクアレイを抜いて,差し直す
Practice3-2 PyHARK オンライン音源定位・分離・音声認識プログラム
- practice3-2r.py のプログラムの構造
#!/usr/bin/env python import hark # 必要なモジュールを import import ... class HARK_Localization(hark.NetworkDef): # 音源定位サブネットワーク ...... class HARK_Separation(hark.NetworkDef): # 音源分離サブネットワーク ...... class HARK_Recognition(hark.NetworkDef): # 音声認識サブネットワーク ...... class HARK_Main(hark.NetworkDef): # メインネットワーク ...... def main(): main関数 ...... if __name__ == '__main__': main()
- 音源定位サブネットワーク(既に説明済み)
- 音源分離サブネットワーク
- 音声認識サブネットワーク
- メインネットワーク
Practice3-2: PyHARK 音源分離サブネットワーク
- HARK Designer における音源分離サブネットワーク
- PyHARKを用いて,次の方針で Pythonプログラムに変換
- すべてのネットワークは,hark.NetworkDef を継承したネットワークをクラスとして定義
- build() メソッド中にネットワークの構造を記述
- 必要なノードをnetwork.create で作成
- ノードの接続関係は,入力端子に対して node_xxx.add_input("NAME", node_yyy["NAME"]) で定義
- ノードのパラメータをnode_xxx.add_input("PARM", VALUE)で定義
- クラス HARK_Separation のPythonプログラム
class HARK_Separation(hark.NetworkDef): # 音源分離サブネットワーク def build(self, build() メソッド中にネットワークの構造を記述 network: hark.Network input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_ghdss = network.create(hark.node.GHDSS) # GHDSS node_synthesize = network.create(hark.node.Synthesize) # Synthesize node_save_wave_pcm = network.create(hark.node.SaveWavePCM) # SaveWavePCM except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_ghdss # GHDSS ノードの接続とパラメータの設定 .add_input("INPUT_FRAMES", input["SPEC"]) .add_input("INPUT_SOURCES", input["SRC_INFO"]) .add_input("TF_INPUT_TYPE", "FILE") .add_input("TF_CONJ_FILENAME", "tf.zip") .add_input("LC_CONST", "DIAG") .add_input("UPDATE_METHOD_W", "ID") , node_synthesize # Synthesize ノードの接続 .add_input("INPUT", node_ghdss["OUTPUT"]) , node_save_wave_pcm # SaveWavePCM ノードの接続 .add_input("INPUT", node_synthesize["OUTPUT"]) .add_input("BASENAME", "ghdss_{srcid}_") , ] output.add_input("OUTPUT", node_ghdss["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r
Practice3-2 Python 音声認識ネットワーク
- practice3-2r.py のプログラムの構造
#!/usr/bin/env python import hark # 必要なモジュールを import import ... class HARK_Localization(hark.NetworkDef): # 音源定位サブネットワーク ...... class HARK_Separation(hark.NetworkDef): # 音源分離サブネットワーク ...... class HARK_Recognition(hark.NetworkDef): # 音声認識サブネットワーク ...... class HARK_Main(hark.NetworkDef): # メインネットワーク ...... def main(): main関数 ...... if __name__ == '__main__': main()
- 音源定位サブネットワーク(既に説明済み)
- 音源分離サブネットワーク(たった今説明)
- 音源認識サブネットワーク
- メインネットワーク
Practice3-2: PyHARK 音声認識サブネットワーク
- HARK Designer における音声認識サブネットワーク
- PyHARKを用いて,次の方針で Pythonプログラムに変換
- すべてのネットワークは,hark.NetworkDef を継承したネットワークをクラスとして定義
- build() メソッド中にネットワークの構造を記述
- 必要なノードをnetwork.create で作成
- ノノードの接続関係は,入力端子に対して node_xxx.add_input("NAME", node_yyy["NAME"]) で定義
- ノードのパラメータをnode_xxx.add_input("PARM", VALUE)で定義
- クラス HARK_Recognition のPythonプログラム
class HARK_Recognition(hark.NetworkDef): # 音声認識サブネットワーク def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): # 必要なノードを作成する try: node_pre_emphasis = network.create(hark.node.PreEmphasis) # PreEmphasis node_mel_filter_bank = network.create(hark.node.MelFilterBank) # MelFilterBank node_msls_extraction = network.create(hark.node.MSLSExtraction)# MSLSExtraction node_delta = network.create(hark.node.Delta) # Delta node_feature_remover = network.create(hark.node.FeatureRemover)# FeatureRemover node_spectral_mean_normalization_incremental = network.create( hark.node.SpectralMeanNormalizationIncremental) # SpectralMeanNormalizationIncremental node_speech_recognition_client = # SpeechRecognitionClient network.create(hark.node.SpeechRecognitionClient) node_save_features = network.create(hark.node.SaveHTKFeatures) # SaveHTKFeatures except BaseException as ex: print(ex) # ノード間の接続(データの流れ)とパラメータを記述し, # ネットワークに含まれるノードの一覧を含むリストを作成する try: r = [ node_pre_emphasis # EMPHASIS ノードの接続 .add_input("INPUT", input["SPEC"]) .add_input("INPUT_TYPE", "SPECTRUM") , node_mel_filter_bank # MelFilterBank ノードの接続 .add_input("INPUT", node_pre_emphasis["OUTPUT"]) .add_input("FBANK_COUNT", 40) , node_msls_extraction # MSLSExtractionノードの接続とパラメータの設定 .add_input("FBANK", node_mel_filter_bank["OUTPUT"]) .add_input("SPECTRUM", node_pre_emphasis["OUTPUT"]) .add_input("FBANK_COUNT", 40) .add_input("NORMALIZATION_MODE", "SPECTRAL") .add_input("USE_POWER", True) , node_delta # Delta ノードの接続 .add_input("INPUT", node_msls_extraction["OUTPUT"]) , node_feature_remover # FeatureRemoverノードの接続とパラメータの設定 .add_input("INPUT", node_delta["OUTPUT"]) .add_input("SELECTOR", " ".join(map(str, range(40, 81+1)))) , # SpectralMeanNormalizationIncrementalノードの接続とパラメータの設定 node_spectral_mean_normalization_incremental .add_input("INPUT", node_feature_remover["OUTPUT"]) .add_input("SM_HISTORY", False) # ToDo .add_input("NOT_EOF", True) # ToDo .add_input("FBANK_COUNT", 40) .add_input("PERIOD", 1) .add_input("BASENAME", "") .add_input("OUTPUT_FNAME", "") , node_speech_recognition_client # FeatureRemoverノードの接続とパラメータの設定 .add_input("FEATURES", node_spectral_mean_normalization_incremental["OUTPUT"]) .add_input("MASKS", node_spectral_mean_normalization_incremental["OUTPUT"]) .add_input("SOURCES", input["SOURCE"]) #.add_input("MFM_ENABLED", False) .add_input("HOST", "localhost") #.add_input("PORT", 5530) .add_input("SOCKET_ENABLED", True) , node_save_features # SaveFeatureノードの接続とパラメータの設定 .add_input("FEATURES", node_spectral_mean_normalization_incremental["OUTPUT"]) .add_input("SOURCES", input["SOURCE"]) .add_input("BASENAME", "feature_") , ] output.add_input("OUTPUT", node_spectral_mean_normalization_incremental["OUTPUT"]) except BaseException as ex: print('error: {}'.format(ex)) # ノード一覧のリストを返す return r ここまでできた%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Practice3-3: PyHARK オフライン音源定位・分離・認識システム
Practice3-2: Python プログラム(全体構造)
Practice3-2: Python main関数
- main関数の構造
- main関数の入力の定義
- main関数のpubliserhと返り値の記述
Practice3-2: PyHARKによる音声認識(Practice2のPyHARK化)
Practice3-2: 音声認識エンジンの起動
- Kaldidecoderを起動
- 起動処理が終わり表示が落ち着くまで待つ
cd practice2/data sh 1_run_ASR.sh ⏎ [INFO] This software includes work that is distributed under the Apache License 2.0 . ...... [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.1125 seconds in looped compilation. [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.107063 seconds in looped compilation.
Practice3-2: オーディオデバイスの確認
- ターミナルを開きオーディオデバイスを確認
- 使いたいデバイス名か番号を覚えておく(例えば,TAMAGO-XXX あるいは2)
cd practice3/data python practice3-2r.py -l 0 Ensoniq AudioPCI: ES1371 DAC2/ADC (hw:0,0), ALSA (2 in, 0 out) 1 Ensoniq AudioPCI: ES1371 DAC1 (hw:0,1), ALSA (0 in, 2 out) 2 TAMAGO-XX: USB Audio (hw:1,0), ALSA (8 in, 0 out) 3 sysdefault, ALSA (128 in, 0 out) 4 samplerate, ALSA (128 in, 0 out) 5 speexrate, ALSA (128 in, 0 out) 6 pulse, ALSA (32 in, 32 out) 7 upmix, ALSA (8 in, 0 out) 8 vdownmix, ALSA (6 in, 0 out) * 9 default, ALSA (32 in, 32 out)
Practice3-2: Python practice3-2r を動かす
- 入力デバイスを指定してプログラムを実行(-d デバイス番号 or デバイス名)
- マイクにむかって発話
- 定位・分離・認識が実行される
- Ctrl-C で終了
- 動かない場合の対処法
- Ctrl-Z で一時停止,kill %1 などでジョブ停止
- マイクアレイを抜いて,差し直す
python practice3-2r.py -d 2
Practice3-2 Python プログラム(全体構造)
- 音源定位サブネットワーク(既に説明済み)
- 音源分離サブネットワーク
- 音源認識サブネットワーク
- メインネットワーク
Practice3-2: PyHARK 音源分離サブネットワーク
- HARK_Separation クラス
class HARK_Separation(hark.NetworkDef): def build(......): ...... # 使用したノードを格納したリストを作り build() の返値とする r = [ node_ghss, node_synthesize, node_save_save_pcm, ] return r
- HARK_Separation クラスの入出力
class HARK_Separation(hark.NetworkDef): def build(......): ...... # 使用したノードを格納したリストを作り build() の返値とする r = [ node_ghss, node_synthesize, node_save_save_pcm, ] return r
Practice3-2 Python 音声認識
Practice3-2: PyHARK 音声認識サブネットワーク
class HARK_Recognition(hark.NetworkDef): def build(self, network: hark.Network, input: hark.DataSourceMap, output: hark.DataSinkMap): node_feature_remover = network.create(hark.node.FeatureRemover) node_delta = network.create(hark.node.Delta) node_mel_filter_bank = network.create(hark.node.MelFilterBank) node_msls_extraction = network.create(hark.node.MSLSExtraction) node_pre_emphasis = network.create(hark.node.PreEmphasis) node_spectral_mean_normalization = network.create( hark.node.SpectralMeanNormalizationIncremental) node_speech_recognition_client = network.create(hark.node.SpeechRecognitionClient)
- HARK_Recognition のノード
- ヘッダー部
class HARK_Recognition(hark.NetworkDef): def build(......):
node_pre_emphasis = network.create(hark.node.PreEmphasis) node_mel_filter_bank = network.create(hark.node.MelFilterBank) node_msls_extraction = network.create(hark.node.MSLSExtraction) node_delta = network.create(hark.node.Delta) node_feature_remover = network.create(hark.node.FeatureRemover) node_spectral_mean_normalization = network.create(hark.node.SpectralMeanNormalizationIncremental) node_speech_recognition_client = network.create(hark.node.SpeechRecognitionClient) ......
- ヘッダー部
class HARK_Separation(hark.NetworkDef): def build(self, network, input, output): ......
(node_pre_emphasis .add_input("INPUT", input ["SPECC"]) .add_input("INPUT_TYPE", "SPECTRUM")) (node_mel_filter_bank .add_input("INPUT", node_pre_emphasis["OUTPUT"]) .add_input("FBANK_COUNT", 40)) ......
- ヘッダー部
class HARK_Separation(hark.NetworkDef): def build(self, network, input, output): ......
(node_feature_remover .add_input("INPUT", node_delta["OUTPUT"]) .add_input("SELECTOR", " ".join(map(str, range(40, 81+1))))) 40 41 42 ... 81 (node_spectral_mean_normalization .add_input("INPUT", node_feature_remover["OUTPUT"]) .add_input("NOT_EOF", True) .add_input("SM_HISTORY", False) .add_input("PERIOD", 1) .add_input("BASENAME", "") .add_input("OUTPUT_FNAME", "")) ......
- ヘッダー部: inputはサブネットへの入力
class HARK_Separation(hark.NetworkDef): def build(self, network, input, output): ......
(node_speech_recognition_client .add_input("FEATURES", node_spectral_mean_normalization["OUTPUT"]) .add_input("MASKS", node_spectral_mean_normalization["OUTPUT"]) .add_input("SOURCES", input["SRC_INFO"]) .add_input("MFM_ENABLED", False) .add_input("HOST", "localhost") .add_input("PORT", 5530) .add_input("SOCKET_ENABLED", True)) ......
- サブネットの出力
class HARK_Separation(hark.NetworkDef): def build(self, network, input, output): ......
output.add_input("OUTPUT", node_speech_recognition_client["OUTPUT"])
r = [ node_white_noise_adder, node_pre_emphasis, node_mel_filter_bank, node_msls_extraction, node_delta, node_spectral_mean_normalization, node_speech_recognition_client, ] return r 大丈夫か
Practice3-3 PyHARK オフライン音声認識
オンライン処理とオフライン処理の違い
- オンライン処理
- データを逐次的に(1フレームずつ)処理
- HARK Middleware による処理とほぼ同じ
- マイク入力を用いたリアルタイム処理と好相性
- オフライン処理(バッチ処理)
- データをまとめて処理
- 通常のPythonプログラミングと高い整合性
Practice3-3: 動かしてみる
- Kaldidecoderを起動
- 起動処理が終わり表示が落ち着くまで待つ
- practice3-3 を入力ファイルを input.wav 動かす
- 定位・分離・認識が行われる
cd practice2/data sh 1_run_ASR.sh [INFO] This software includes work that is distributed under the Apache License 2.0 . ...... [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.1125 seconds in looped compilation. [INFO] Removed 1 orphan nodes. [INFO] Removing 2 orphan components. [INFO] Added 1 components, removed 2 [INFO] Spent 0.107063 seconds in looped compilation.
python practice3-3.py input.wav
[INFO] 5.77266 sec, RT=1.36793 source_id = 7, azimuth = 79.982063, elevation = 36.869900, sec = 1668056389, usec = 904003 ### Recognition: 2nd pass (RL heuristic best-first) STAT: 00 sentence1: 一 週間 ばかり ニューヨーク を 取材 し た wseq1: 一+名詞/数詞 週間+接尾辞 ばかり+助詞/副助詞 ニューヨーク+名詞/固有名詞 を+助詞/格助詞 取材+名詞 し+動詞/サ行変格/連用形 た+助動詞/連体形 ......
Practice3-3: Python プログラム
- ファイル入力モジュール
- 必要なモジュールのインポート
#!/usr/bin/env python import sys import numpy as np import soundfile as sf from numpy.lib.stride_tricks import sliding_window_view import hark
def main(): if len(sys.argv) < 2: print("no input file") return wavfilename = sys.argv[1]
audio, rate = sf.read(wavfilename, dtype=np.float32) nch = audio.shape[1] frame_size, advance = 512, 160 frames = sliding_window_view(audio, frame_size, axis=0)[::advance, :, :]
- 全フレームまとめてFFT
multi_fft = hark.node.MultiFFT() spec = multi_fft(INPUT=frames)
noise_cm = np.broadcast_to( np.eye(nch, dtype=np.complex64).flatten(), (frames.shape[0], frame_size//2+1, nch*nch))
localize_music = hark.node.LocalizeMUSIC() music_spec = localize_music( INPUT=spec.OUTPUT, A_MATRIX='tf.zip', MUSIC_ALGORITHM='SEVD', NOISECM=noise_cm, WINDOW_TYPE='PAST', ENABLE_OUTPUT_SPECTRUM=True)
- 音源追跡
source_tracker = hark.node.SourceTracker() src_info = source_tracker( INPUT=music_spec.OUTPUT, THRESH=26.0, PAUSE_LENGTH=1200.0, MIN_SRC_INTERVAL=20.0)
ghdss = hark.node.GHDSS() ghdss_output = ghdss( INPUT_FRAMES=spec.OUTPUT, INPUT_SOURCES=src_info.OUTPUT, TF_CONJ_FILENAME='tf.zip’)
- 分離音保存: 分離音スペクトルを音響信号に変換し保存
synthesize = hark.node.Synthesize() synthesize_output = synthesize(INPUT=ghdss_output.OUTPUT) save_wave_pcm = hark.node.SaveWavePCM() save_wave_pcm_output = save_wave_pcm(INPUT=synthesize_output.OUTPUT)
pre_emphasis = hark.node.PreEmphasis() pre_emphasized_spectrum = pre_emphasis(INPUT=ghdss_output.OUTPUT, INPUT_TYPE="SPECTRUM") mel_filter_bank = hark.node.MelFilterBank() mel_spectrum = mel_filter_bank(INPUT=pre_emphasized_spectrum.OUTPUT, FBANK_COUNT=40) msls_extraction = hark.node.MSLSExtraction() msls = msls_extraction(FBANK=mel_spectrum.OUTPUT, SPECTRUM=pre_emphasized_spectrum.OUTPUT, FBANK_COUNT=40, NORMALIZATION_MODE="SPECTRAL", USE_POWER=True)
- 音響特徴抽出
feature_remover = hark.node.FeatureRemover() asr_features = feature_remover(INPUT=msls.OUTPUT, SELECTOR=" ".join(map(str, range(40, 81+1)))) smn = hark.node.SpectralMeanNormalizationIncremental() normalized_features = smn(INPUT=asr_features.OUTPUT, NOT_EOF=True, SM_HISTORY=False, PERIOD=1)
speech_recognition_client = hark.node.SpeechRecognitionClient() asr_result = speech_recognition_client( FEATURES=normalized_features.OUTPUT, MASKS=normalized_features.OUTPUT, SOURCES=src_info.OUTPUT, MFM_ENABLED=False, HOST="localhost", PORT=5530, SOCKET_ENABLED=True)
Practice3 まとめ
- HARKをPython上で使うPyHARK
- オンライン処理・オフライン処理
- データの流れを事前に記述して,フレームごとにデータ処理を行うオンライン処理
- 全データに対してそれぞれの処理を一括で行うオフライン処理
次は Practice3-4 に挑戦