善悪の彼岸

社会人5年目、ものづくりと哲学と研究が好き

【Python】聞きたい情報を強調し、聞きたくない情報を検閲する耳能力拡張デバイスのプロトタイプを作った【Pyaudio】

問題意識

  • 我々の生活は情報にあふれている
  • 私たちの耳は認知を回避できない
  • 聞きたくないものも耳に入るし、聞きたい情報を選別することできない
  • それに対して目に入るものを制限するというのは行われている(Twitterのミュート機能など)
    聞きたくもないうわさ話

コンセプト

  • もし、聞きたくない情報を減衰させることができたら面白いんじゃないか?→耳感覚減少

    もし聞きたくないことだけシャットアウトできたら…

  • もし、聴きたい情報のみに耳をフォーカスすることができたら?→耳感覚増強

    逆に聞きたい情報に耳をフォーカスできたら?

やりたいこと

  • 会話の中で特定の言葉が聞こえたら、声が大きくなったり小さくなったりする

システム図

システム図

ユースケース

耳感覚減少(特定の言葉が聞こえたらミュートする)のユースケース

スパイダーマンのネタバレを聞きたくないAさんの場合

  • 聞きたくない話題について情報を防げる(ネタバレ防止等)

耳感覚増強(特定の言葉が聞こえたら耳能力が高くなる)のユースケース

大好きなCさんの情報をなんとしても集めたいBさんの場合

作ってみた

要素技術調査

  • Pyaudioを使ってマイクから入力した音声をそのままスピーカーに流す
  • 入力した音声からSpeech Recognitionを使って文字起こしをする
  • 文字起こしの結果から、音声のフィードバックの仕方を変化させる  - Pycawを使ってWindowsのマスターボリュームをPythonから操作する

Pyaudioを使ってマイクから入力した音声をそのままスピーカーに流す

  • Pyaudioを使えばマイクからの音の入力を並列処理できるということらしい。常にマイクから音を取り続けていることが必要なので、スレッドを作ってそちらで常に処理を行っておく必要があるがPyaudioのノンブロッキングモードを使えば勝手にPyaudioでThreadを作ってくれて実行してくれるようだ。
  • なのでStreamがOpenしている(音をマイクから収集してスピーカーに流している間)間に音声認識なり、音調変換なりを行えば良さそう

WindowsPyaudioインストール

py -m pip install PyAudio-0.2.11-cp39-cp39-win_amd64.whl

linuxPyaudioインストール

  • portaudioというライブラリに依存しておりそのままだとpip経由でpyAudioインストールしようとするとエラーを吐くため
sudo apt-get install portaudio19-dev

でportaudioをインストールしてから

pip install pyaudio

でOK

実装コード

# coding: UTF-8
import speech_recognition as sr
import pyaudio
import time

class AudioFilter():
    def __init__(self):# classの初期設定
        self.p = pyaudio.PyAudio()
        self.channels = 2 #マイクがモノラルの場合は1
        self.rate = 48000 #DVDレベルなので重かったら16000
        self.format = pyaudio.paInt16
        self.stream = self.p.open(
            format = self.format,
            channels = self.channels,
            rate = self.rate,
            output = True,
            input = True,
            stream_callback=self.callback)#音声が流れてきた時に叩くCallBack関数を指定する


#  format  : ストリームを読み書きするときのデータ型
#  channels: ステレオかモノラルかの選択 1でモノラル 2でステレオ
#  rate    : サンプル周波数
#  output  : 出力モード
    
    # コールバック関数(再生が必要なときに呼び出される)
    def callback(self, in_data, frame_count, time_info, status):
        out_data = in_data
        return (out_data, pyaudio.paContinue)
    # 音声取り込みをやめるとき
    def close(self):
        self.p.terminate() 

if __name__ == "__main__": #importされた場合に実行しないようにするらしい
    #AudioFileterのインスタンスを作る
    af = AudioFilter()
    #ストリーミングを始める
    af.stream.start_stream()

    # ノンブロッキングなのでこの中で音声認識・音の変換などを行う
    while af.stream.is_active():
        print("なんの処理をしてもOK")
        #r = sr.Recognizer()
        #with sr.Microphone() as source: # pyaudioを使ってマイクを認識?
        #    r.adjust_for_ambient_noise(source)
        #    print("音声を読み取っています")
        #    audio = r.listen(source)
        #    try:
        #        query = r.recognize_google(audio, language='ja-JP')
        #        print(query)
        #    except:
        #        print("エラー")
    # ストリーミングを止める
    af.stream.stop_stream()
    af.stream.close()
    af.close()

結果

  • 若干実際の音声に対して遅れて出力されるが、音質的には問題なさそう

参考資料

入力した音声からSpeech Recognitionを使って文字起こしをする

実行環境

SpeechRecognitionのinstall

  • SpeechRecognitionをpip経由でインストールする
pip install SpeechRecognition

実装したコード

import speech_recognition as sr
import pyaudio

if __name__ == "__main__": #importされた場合に実行しないようにするらしい
    r = sr.Recognizer()
    with sr.Microphone() as source: # pyaudioを使ってマイクを認識?
        r.adjust_for_ambient_noise(source)
        print("音声を読み取っています")
        audio = r.listen(source)
        try:
            query = r.recognize_google(audio, language='ja-JP')
            print(query)
        except:
            print("エラー")

実行結果

  • こんにちはといった場合
    こんにちは聞き取り

まとめ

  • そこそこの精度は出る。
  • マイク入力の終わりを指定してないけど、何故か音声の終わりは検知している
  • アホほど実装が簡単

参考資料

Pycawを使ってWindowsのマスターボリュームをPythonから操作する

chamekichi.hatenadiary.jp

設計と実装

要求

  • マイクから入力した音声をそのままスピーカーに流す
  • 検閲させるキーワードを設定する
  • 文字起こしの内容から検閲ワードを見つける
  • 検閲ワードを見つけたらマイクから得た音声に何かしらの加工をかけて(まずは簡単にP音を10秒流す)検閲ワードをユーザーに聞かせないようにする

詳細タスク

  • 検閲ワードをユーザーに入力させて配列に入れる
    • KeyInoutクラス key_input関数
  • STTで文字起こししたセンテンスに検閲ワードが含まれていないか検索する
    • AudioCensorshipクラス character_search関数
  • 検閲ワードが含まれていた場合は、Pycawでスピーカーからの音量を予め設定していたボリュームに◯秒変える
    • AudioControllerクラス set_enhanced_volume関数
    • Timerクラス is_time_out関数

コード

github.com

できたもの

  • 耳感覚を増強する例
  • スパイダーマンというキーワードが出るとゲインが1.5倍になる
  • わかりづらくて申し訳ないですが、画面下側のコンソールにマイクから読み取ったテキストを表示しています


www.youtube.com

  • 耳感覚を減少させる(聞きたくないキーワードを検出するとゲインを下げる)例
  • スパイダーマンというキーワードが出るとミュートがかかる
  • ミュートしている間も画面下側のコンソールにマイクから読み取ったテキストを表示しています


www.youtube.com

感想と反省

  • 耳感覚減少では、いきなり音が全く聞こえなくなるのでビビる
    • 検閲ワードがあったら音がかなり小さくなるくらいでいいかも
    • ただ、確かにキーワードが出てからは会話が聞こえなくなるので、聞きたくない情報をカットすることはできる
  • 耳感覚増強では、誰かがキーワードを喋るといきなり外界からの音が大きくなるので、かなり恐怖を感じる
    • 自分の五感のコントロールを自分ができないというのはかなり怖い
    • 五感を支配されるディストピアみを感じた
    • 今まで耳が聞こえなかった人が聞こえるようになると、最初は全てが雑音で非常に不快だと聞いたことがあるが、ちょっと似たような感覚を得た。身体拡張は必ずしも最初から快適ではないのかもしれない。
    • 耳感覚増強の場合は、全体的にボリュームを上げるというよりは、聞きたいこと以外はカットするというほうがいいかもしれない。

課題

  • 検閲ワードを検出した瞬間の会話は防ぎようがない
    • 一文字毎にテキスト化するSSTライブラリ等を使う必要がある
  • 会話が一度途切れないと、テキスト化されない
    • Speech Recognitionの設定で逃れられるかも
  • 単純なボリュームの増減による音声加工しかできないので一部の声だけを聞こえなくする・強調する等ができない
    • 音源定位技術を使って発話者の位置を特定し、特定の声だけを消すなどできるかも
  • ノートPCが重い
    • ラズパイに移植する
  • イヤホンをつけているだけだと変換前の外の音声が聞こえてしまう