リー効果の波について:DAFの生成をPythonizeする

画像 統計によると、世界人口の1〜4%が音声障害の影響を受けており、頻繁な音の延長(音節、単語)および/またはそのリズミカルな流れに違反する音声の頻繁な停止が特徴です。 一般の人々では、この現象はst音として知られています。



現時点では、世界は万能薬を知らず、eliminating音を100%除去しますが、これまたはその成功がこの言語障害をほとんどのst音から止める最も興味深い方法があります。 この方法はリー効果に基づいています。リー効果は、音声聴覚求心の遅延が音声の滑らかさに及ぼす影響であり、DAF(遅延聴覚フィードバック)と呼ばれます。



以下では、PythonとPyQtを使用して膝の上に簡単な音声フィードバックジェネレーターを構築する例を見ていきます。 ああ、楽しいよ!



何に何を、なぜ



潜水艦のエンジニアであるバーナード・リー( リー 、1951)にちなんで名付けられたリー効果は、普通の人がヘッドフォンで自分のスピーチを聞くと、特殊な機器を使用して80-200ミリ秒遅れるという事実に現れます(会話の瞬間) st音を引き起こし、st音を非常に連想させます。 同時に、st音を起こしやすい人では、リー効果はまったく逆の効果があります。 これがDAFメソッドの基礎です。 ヘッドフォンで音声を再生する際の遅延の意味は、音声センター-ウェルニッケ聴覚センターとブロックの音声モーターセンター( 暗号メタファー:遅延=自己同期ストリーム暗号のガンマ生成機能 )の動作を同期することです 。 さまざまな研究により、50〜75ミリ秒の範囲の遅延により、正常な音声および加速された音声のin音が60〜80%減少することが明らかになっています。 190ミリ秒の遅延は75ミリ秒よりわずかに効果的であることが判明しましたが、最適な遅延値は被験者の感覚に基づいて個別に選択されます。



音声を正規化するためのハードウェアベースのアプローチのアイデアは、世界と同じくらい古いです。「フィードバック調整」の原理で動作する最初のデバイスは、1959年に設計されました。 、そして今、便利にDAFを生成する方法がいくつかあります:別々のミニデバイスの助けを借りて、Vedroid用のソフトウェアの形で、Apple(アプリケーションストアのキーワード「DAF」で検索すると、そのようなソリューションの選択全体が表示されます)とPC(ここでと さらに間違って、次の段落を参照してください)。



なぜこの投稿



モバイルプラットフォームのアプリケーションのコストは数ドル以内です。 許可された。 ただし、Windowsの場合、「個人的なニーズのみ」の基本バージョンでは30ドル相当のプログラムが1つしかありません(名前は付けません-検索エンジンの最初のリンクに同じキーワードがあります)。 ここで、このような些細な関数の自作の実装が取得するコードの行数が私にとって興味深いものになりました。 この興味の結果は、ボンネットの下にシンプルなDAFジェネレーターを隠すGUIインターフェイスウィンドウだけでした。それを他の人と共有したい-誰かが役に立つかもしれません。



試用。 CLIインターフェース



はじめに、テストスクリプトの形で概念をスケッチしましょう。 「 Python3 + PyAudioバンドルを使用します。ここで、 PyAudioはサウンドを操作するためのモジュールです。 カーネルは次のようになります。



CHANNELS = 2 RATE = 44100 def genDAF(delay): bufferSize = floor(delay / 1000 * RATE) device = PyAudio() try: streamIn = device.open( format=paFloat32, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=bufferSize ) streamOut = device.open( format=paFloat32, channels=CHANNELS, rate=RATE, output=True, frames_per_buffer=bufferSize ) except OSError: print('genDAF: error: No input/output device found! Connect and rerun') return print('CTRL-C to stop capture') while streamIn.is_active(): start = clock() audioData = streamIn.read(bufferSize) streamOut.write(audioData) actualDelay = floor((clock() - start) * 1000) print('Actual Delay: {} ms'.format(actualDelay))
      
      





genDAFプロシージャは、遅延値をミリ秒単位で取得し、音声録音に必要なバッファーサイズ(44.1 kHzの最適ビットレートに基づいて)を計算します。その後、 オーディオ入力および出力接続 (別名マイクとスピーカー)がある場合、入力の2つのストリームを作成しますおよび出力。 次に、メインループで、録音されたオーディオデータの読み取りとインスタント再生が開始されますが、読み取り/書き込み操作のペアを完了するのに必要な実際の遅延は、バックグラウンドに対してカウントされます。 約20行のコードが必要でした。



スポイラーの下での完全なソースCLI実装:



dafgen_cli.py
 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Usage: python3 dafgen_cli.py <delay_in_ms> from pyaudio import PyAudio, paFloat32 from math import floor from time import clock import sys CHANNELS = 2 RATE = 44100 def genDAF(delay): bufferSize = floor(delay / 1000 * RATE) device = PyAudio() try: streamIn = device.open( format=paFloat32, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=bufferSize ) streamOut = device.open( format=paFloat32, channels=CHANNELS, rate=RATE, output=True, frames_per_buffer=bufferSize ) except OSError: print('genDAF: error: No input/output device found! Connect and rerun') return print('CTRL-C to stop capture') while streamIn.is_active(): start = clock() audioData = streamIn.read(bufferSize) streamOut.write(audioData) actualDelay = floor((clock() - start) * 1000) print('Actual Delay: {} ms'.format(actualDelay)) def main(): if len(sys.argv) != 2: print('Usage: python3 {} <delay_in_ms>'.format(sys.argv[0])) sys.exit(1) try: delay = int(sys.argv[1]) except ValueError: print('main: error: Invalid input type') sys.exit(1) if not 50 <= delay <= 200: print('main: error: Delay must be in [50; 200] ms') sys.exit(1) print('Delay: {} ms\n'.format(delay)) try: genDAF(delay) except KeyboardInterrupt: print('Stopped') if __name__ == '__main__': main()
      
      







ファイナル GUIインターフェース



ターミナルの黒い背景にある緑色の文字はロマンチックですが、常に便利であるとは限りません。 グラフィックのフレームワークをツールのバンドルに追加すると、「 Python3 + PyAudio + PyQt5 」が取得されます。



デザイナーでいくつかのボタン、スライダー、2つのテキストフィールドをスケッチしましょう。



画像






メインDAF生成コードを2つのクラスに分散することでロジックを追加します:コントロールアプリケーション(MainApp)と、メインウィンドウがハングしないように_genDAFメソッドのwhileループを実行する別のスレッドのクラス(Worker)です。 完全なコードは段落の最後に記載されており、現在は主要部分のみです。



管理アプリケーション:

 class MainApp(QMainWindow, Ui_DAFGen): _CHANNELS = 2 _RATE = 44100 def __init__(self): super().__init__() self.setupUi(self) # ... # ... def _startCapture(self): bufferSize = floor(self.delaySlider.value() / 1000 * self._RATE) device = PyAudio() try: streamIn = device.open( format=paFloat32, channels=self._CHANNELS, rate=self._RATE, input=True, frames_per_buffer=bufferSize ) streamOut = device.open( format=paFloat32, channels=self._CHANNELS, rate=self._RATE, output=True, frames_per_buffer=bufferSize ) except OSError: QMessageBox.critical(self, 'Error', 'No input/output device found! Connect and rerun.') return self._workerThread = Worker(bufferSize, streamIn, streamOut) self._workerThread._trigger.connect(self._updateActualDelay) # ... self._workerThread.start()
      
      





2番目のスレッド:

 class Worker(QThread): _trigger = pyqtSignal(float) def __init__(self, bufferSize, streamIn, streamOut): QThread.__init__(self) self._bufferSize = bufferSize self._streamIn = streamIn self._streamOut = streamOut def __del__(self): self.wait() def _genDAF(self): while self._streamIn.is_active(): start = clock() audioData = self._streamIn.read(self._bufferSize) self._streamOut.write(audioData) actualDelay = clock() - start self._trigger.emit(actualDelay) def run(self): self._genDAF()
      
      





ネタバレの下でのGUI実装のロジックのソース:



dafgen.py
 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Usage: python3 dafgen.py from PyQt5.QtWidgets import * from PyQt5.QtCore import * from ui_dafgen import Ui_DAFGen from pyaudio import PyAudio, paFloat32 from math import floor from time import clock import sys class Worker(QThread): _trigger = pyqtSignal(float) def __init__(self, bufferSize, streamIn, streamOut): QThread.__init__(self) self._bufferSize = bufferSize self._streamIn = streamIn self._streamOut = streamOut def __del__(self): self.wait() def _genDAF(self): while self._streamIn.is_active(): start = clock() audioData = self._streamIn.read(self._bufferSize) self._streamOut.write(audioData) actualDelay = clock() - start self._trigger.emit(actualDelay) def run(self): self._genDAF() class MainApp(QMainWindow, Ui_DAFGen): _CHANNELS = 2 _RATE = 44100 def __init__(self): super().__init__() self.setupUi(self) self.stopButton.setEnabled(False) self._updateDelay() self.delaySlider.valueChanged.connect(self._updateDelay) self.startButton.clicked.connect(self._startCapture) self.stopButton.clicked.connect(self._stopCapture) self.quitButton.clicked.connect(QApplication.quit) def _updateDelay(self): self.delayEdit.setPlainText(str(self.delaySlider.value()) + ' ms') def _startCapture(self): bufferSize = floor(self.delaySlider.value() / 1000 * self._RATE) device = PyAudio() try: streamIn = device.open( format=paFloat32, channels=self._CHANNELS, rate=self._RATE, input=True, frames_per_buffer=bufferSize ) streamOut = device.open( format=paFloat32, channels=self._CHANNELS, rate=self._RATE, output=True, frames_per_buffer=bufferSize ) except OSError: QMessageBox.critical(self, 'Error', 'No input/output device found! Connect and rerun.') return self._workerThread = Worker(bufferSize, streamIn, streamOut) self._workerThread._trigger.connect(self._updateActualDelay) self.startButton.setEnabled(False) self.delaySlider.setEnabled(False) self.stopButton.setEnabled(True) self._workerThread.start() def _stopCapture(self): self._workerThread.terminate() self.actualDelayEdit.clear() self.startButton.setEnabled(True) self.delaySlider.setEnabled(True) self.stopButton.setEnabled(False) def _updateActualDelay(self, t): newValue = floor(t * 1000) self.actualDelayEdit.setPlainText(str(newValue) + ' ms') def main(): app = QApplication(sys.argv) win = MainApp() win.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
      
      







結論とコード



実際に私が伝えたかったすべて。 気軽に使用してください。



また、プロジェクト全体へのリンクも残します。さらに、PyQt DesignerのGUIコードとテンプレートがあります。



ご清聴ありがとうございました!



文学



Missulovin L. Ya。、Yurova M. S.「AIR」タイプの装置を使用した青少年および成人のst音の克服//科学および方法論的電子ジャーナル「Concept」。 -2015。-いいえ、S23。 -S. 46-50。 -URLe-koncept.ru/2015/75287.htm



All Articles