pythonでmpeg4ファイルを文字起こし

# はじめに
LINEって、音声でも投稿できて、投稿すると音声再生ボタンが出ます。そこからダウンロードもできて、ダウンロードするとMPEG4ファイルです。
音声にしか出せない情報（声色とか）があるとか、発信者は楽というメリットがある一方、同じ時間を共有しないといけないとか、あとで読み返すのが大変とか、一方的に話すので会話が曖昧になるというデメリットもあると思います。

まぁそういうメリデメある状態ではあるけど、文字起こしするという方法もあるよねということで、やってみました。

## ソース
https://github.com/yo16/recognize_audio_file

※ "もじおこし"を変換すると"文字興し"になってたから、気にせず使ってたけど、少なくとも今は"文字起こし"が主流のようなので、この記事では"文字起こし"で。ソース内に"文字興し"が入ってますが、あまりお気になさらず。

## 使っているもの
- [FFmpeg](https://www.ffmpeg.org/)
- [SpeechRecognition · PyPI](https://pypi.org/project/SpeechRecognition/)


# 説明
## 1. 準備
mpeg4形式を、wav形式へ変換するために、[FFmpeg](https://www.ffmpeg.org/)というプログラムを使います。
どのOSでもダウンロード版がありますが、windowsの場合はダウンロードして、`/bin`以下のexeをどこかへコピーするだけ。

誰かがビルドしたexeをダウンロードして実行するなんて、セキュリティ的には危なすぎるので、自己責任でお願いします。

そのexeに対して、下記のコマンドを実行すると、mpeg4形式をwav形式へ変換できます。

```winbatch
ffmpeg.exe -i _10452999.m4a _10452999.wav
```

## 2. ソース（全体）
上記のexeを起動するためにパスを通す必要がありますが、私の個人的な思いとして、特定のプログラムのためだけに、windows全体設定に手を入れたくないです。なので、`.env`ファイルに`ffmpeg.exe`のパスを設定し、利用しました。
```.env
FFMPEG_PATH="D:\\ProgramFiles\\ffmpeg\\bin\\ffmpeg.exe"
```

それを読み込む部分
```python
## ffmpegをパスに追加
load_dotenv()
ffmpeg_path = os.getenv("FFMPEG_PATH")
```

それを踏まえて、全体を実行
```python
if __name__=="__main__":
    text = getText("./data/_10453009.m4a")
    print(text)
```

## 3. メイン処理（getText()）
まずffmpegを利用して、`.m4a`ファイルを`.wav`ファイルへ変換します。

コメントに書いた通り、変換するpythonモジュールがありましたが、内部的にffmpegを使っているし、なんかうまく動かなかったので`subprocess`で自分でキックしています。うまく動かなかった理由はおそらく、上に書いたこだわりのPATHの関係だと思いますが、こだわったままにしました。

そして`wav2`ファイルからテキストに文字起こしする関数を呼びます。
```python
# .m4aファイルを文字興しする
def getText(m4a_file_path):
    # .m4aファイルを、.wavファイルへ変換
    tmp_dir = "./tmp"
    os.makedirs(tmp_dir, exist_ok=True)
    m4a_filename_without_extension = os.path.splitext(os.path.basename(m4a_file_path))[0]
    wav_audio_path = f"{tmp_dir}/{m4a_filename_without_extension}.wav"

    # ffmpeg.exeを直接コマンドで実行する
    # この代わりに実行するモジュールがあったが、pathの関係か、うまく動かないのでこの形になった
    command = [ffmpeg_path, "-i", m4a_file_path, wav_audio_path, "-y"]
    subprocess.run(command, check=True)


    # wavファイルから文字興しする
    text = wav2text_speech_recognition(wav_audio_path)
    return text
```

## 4. wavを文字起こし（wav2text_speech_recognition）
wavファイルのデータをsourceとして、Recgnizerに与えて、`recognize_google()`を呼んでいるだけです。知っていればすぐのコードですが、こういう正解の１つを見つけるのがなかなかしんどい。
```python
def wav2text_speech_recognition(wav_audio_path):
    # 音声認識
    # Initialize the recognizer
    r = sr.Recognizer()

    # Transcribe the audio file
    with sr.AudioFile(wav_audio_path) as source:
        audio_data = r.record(source)
        text = r.recognize_google(audio_data, language="ja-JP")

    return text
```
- `speech_recognition`で利用している、`recognize_google`は、googleの[Speech-to-Text AI](https://cloud.google.com/speech-to-text?_gl=1*1co8hjh*_up*MQ..&gclid=Cj0KCQjwwO20BhCJARIsAAnTIVR2VbEiFKUwlcEL4sV3-a1hCv-qW26louZ2G-9fQGnp1Kt23xl5OZgaAqPjEALw_wcB&gclsrc=aw.ds&hl=ja)を使っている模様。
    - １か月で60分間の音声認識が無料
    - おそらく１か月で60分の制限を超えた時点で、利用できなくなると思われる（ipアドレスか何かでカウントされている？）


# おわりに
いちおうできたものの、`speech_recognition`はGoogleの音声認識を使うためだけに利用しているので、それならば、直接Googleの音声認識を使えばいいんじゃないかと後で気づきました。

でもGoogle公式の[google-api-python-client](https://github.com/googleapis/google-api-python-client)は、GCPにプロジェクトを作ったりSAを作ったりしないといけないかもしれない。

`speech_recognition`を使えば、なぜかそれは回避できる。なぜかというか、ちゃんとソースを見ればわかるんだと思いますが、とりあえず今日は動くところまで。

業務で使うとか、お金を払うことに問題がない場合は、素直にGCPでプロジェクトを作ってgoogle-api-python-clientです。

ご利用は計画的に。