wavファイルを1分ごとに分割してみた【動画編集らくらくシリーズ③】

この【動画編集らくらくシリーズ】は、今回で3回目となります。
1と2はこちらになります↓併せてご覧くださいm(__)m

スポンサーリンク

前回の課題&今回でクリアしたいこと

前回記事「動画音声から自動的に文字を起こしてCSV化してみた」では、音声から自動文字起こしをするため、mp4の動画ファイルからwavファイルへ変換する方法を記載しました。

がしかし、これでめでたしめでたしとはいかず。。。。音声の自動文字起こしに使用した「ecognize_google」は長時間音声の文字起こしができないことが判明しました。

短時間(1分くらい)の音声であれば対応してくれることが分かりました。ので、この記事では、

  1. wavファイルを1分ごとに分割
  2. 分割したファイルをそれぞれ文字起こし
  3. 2で起こした文字をtxtに集約
  4. 3のtxtファイルをCSV化
  5. (おまけ)完了時にビープ音とアラートを出す

という流れでプログラムしていきます。

開発環境

OS:Windows10
Python 3.7.4
環境:Anaconda
エディタ:VScode

コード全体

前回作成したコードの無効化

まず、前回作成した文字起こしのmethod(関数)をコメントアウト、もしくは削除します。
該当のコードは以下↓↓

# 削除もしくはコメントアウトして起動しないようにしてください。
def audio_text_change(audio_change_wav, text_date, csv_date):
    # 文字起こし
    r = sr.Recognizer()
    with sr.AudioFile(audio_change_wav) as source:
        audio = r.record(source)
        text = r.recognize_google(audio, language="ja-JP").replace(" ", "\n")
        print(text)
    # textへの書き出し
    open_text = open(text_date, "x", encoding="utf_8")
    open_text.write(text)
    open_text.close()
    # txtをcsvに変換
    read_text = pd.read_csv(text_date)
    read_text.to_csv(csv_date, index=None)

併せて、このmethod(関数)を実行させるコードも無効化します。
対象は以下のコードです↓↓

# 削除もしくはコメントアウトして起動しないようにしてください。
audio_text_change(audio_change_wav, text_date, csv_date)

今回作成したコード全体

注:動画編集らくらくシリーズ①と②で作成したプログラムは省略しております。「前回の課題&今回でクリアしたいこと」で記載した1~5項のコードのみ記載しております。

# 音声認識
import speech_recognition as sr

# wav分割
import wave
import struct
from scipy import fromstring, int16
import numpy as np
import math

# csv化
import pandas as pd

# ビープ音
import winsound

# aleart
from tkinter import messagebox


# wavファイルをどの間隔で区切りたいか?(単位[sec])
time = 60
# 分割したいwavファイルの格納先
audio_change_wav = "ディレクトリ(絶対パス)/audio_text.wav"
# wav分割ファイルの格納先
wav_cut_dir = "ディレクトリ(絶対パス)"
# テキスト保存場所
text_date = "ディレクトリ(絶対パス)/text.txt"
# csv保存場所
csv_date = "ディレクトリ(絶対パス)/text.csv"

# wavファイルを1分毎に分割
def cut_wav(audio_change_wav, time, wav_cut_dir, text_date, csv_date):

    # wav読み込み
    wr = wave.open(audio_change_wav, "r")

    # wav情報を取得
    ch = wr.getnchannels()
    width = wr.getsampwidth()
    fr = wr.getframerate()
    fn = wr.getnframes()
    total_time = 1.0 * fn / fr
    integer = math.floor(total_time)
    t = int(time)
    frames = int(ch * fr * t)
    # 小数点切り上げ(1分に満たない最後のシーンを出力するため)
    num_cut = int(math.ceil(integer / t))
    data = wr.readframes(wr.getnframes())
    wr.close()

    X = np.frombuffer(data, dtype=int16)

    for i in range(num_cut):
        outf = wav_cut_dir + str(i) + ".wav"
        start_cut = int(i * frames)
        end_cut = int(i * frames + frames)
        print(start_cut)
        print(end_cut)
        Y = X[start_cut:end_cut]
        outd = struct.pack("h" * len(Y), *Y)

        # 書き出し
        ww = wave.open(outf, "w")
        ww.setnchannels(ch)
        ww.setsampwidth(width)
        ww.setframerate(fr)
        ww.writeframes(outd)
        ww.close()

        # txt起こし
        r = sr.Recognizer()
        with sr.AudioFile(wav_cut_dir + str(i) + ".wav") as source:
            audio = r.record(source)
            text = r.recognize_google(audio, language="ja-JP").replace(" ", "\n")
            print(text)
        # txtファイル書き出し
        open_text = open(text_date, "a", encoding="utf_8")
        if i == 0:
            first_text = "telop" + "\n" + text
            open_text.write(first_text)
            open_text.close()
        else:
            open_text.write(text)
            open_text.close()

    # 書き出されたtxtをCSVに変換
    read_text = pd.read_csv(text_date)
    read_text.to_csv(csv_date, index=True, index_label="id")

    # ビープ音
    # 周波数
    hz = 2000
    #  継続時間(ms)
    sec = 500
    winsound.Beep(hz, sec)

    # aleart
    messagebox.showinfo("動画編集らくらく終了のお知らせ", "文字起こし終わったよ!")


cut_wav(audio_change_wav, time, wav_cut_dir, text_date, csv_date)

コード説明

python標準ライブラリ「wave」使ってwavを分割する

分割は、こちらのQiita記事を参考にしました。
参考記事:音声データを1/100秒単位で分割する

今回、1分に区切りたいので60と設定しました。
単位はsecです。

time = 60

参照記事と異なる点は、
もし1分ごとに区切っていって、最後のコマが1分に満たない場合も、残りの音声を書き出す
プログラムにしています。

   # 小数点切り上げ(1分に満たない最後のシーンを出力するため)
    num_cut = int(math.ceil(integer/t))

math.ceilを使うことで、total_timeをtimeで割ったとき、端数がでたら切り上げしてくれます。
ここで算出されたnum_cutの数字分、forが回るといった仕組みです。

音声自動テキスト起こし

前回同様にrecognize_googleを使用しております。
wav分割のfor文中に入れ込み、
wav分割完了 → テキスト起こし → txtデータ書き込み
のループで回しています。

txtデータの書き出し&txtのcsv化

書き出したcsvをphotoshopで読み込むにあたり、以下の加工を加えて保存します。
1.見出しの追加
2.1列目にidを表示

txt化は前回記事とほぼ同じですが、wav分割のループに組み込んでいるため、ループでテキスト起こしされた情報を「追記」していくように引数[a]を設定します。
※前回記事では、新規作成の[x]を引数に使用。

open_text = open(text_date,"a",encoding="utf_8")

見出しの追加

CSVの完成形では見出しは以下のようにしたいと考えています。

idtelop
0はじめまして
1こんにちは

idは、CSV書き出し時にオプションを入れるだけで簡単に追加できるので次項で書きます。
telopの部分は、CSV書き出し時に追加する事が出来なかったので、txt書き出し時にindexを入れてしまいます。
そうです!パワープレイです。
CSV書き出し時に追加する方法が必ずやあると思いますが、リサーチ不足で力尽きました。。すみません。

[telop]といれたいタイミングは、一番最初にtxtを書き込む時なので、ifで「1回目」か「それ以外か」で分岐を作成します。

if i == 0:
   first_text = "telop" + "\n" + text
   open_text.write(first_text)
   open_text.close()
else:
   open_text.write(text)
   open_text.close()

1列目にidを表示

このidの追加はtxtからCSVに変換するタイミングでオプションを付けます。
つけるオプションはこの2つだけです。
index=True
index_label=”id”

read_text = pd.read_csv(text_date)
read_text.to_csv(csv_date,index=True,index_label="id")

完了時にビープ音とアラートを出す

元素材動画が長ければ長いほど処理に時間を要するので、完了したらビープ音でわかるようにプログラムします。

参考にした記事はこちらです。
[Python] ビープ音を鳴らす(Windows/Mac対応)
【Python】メッセージボックスを表示する(tkinter.messagebox)

使用するライブラリはこちら↓
注:MacとWindowsでは使用するライブラリが異なります。

# ビープ音 windowsの場合
import winsound
# アラート
from tkinter import messagebox

Beepの時間はmsで入力してください。

    # ビープ音
    # 周波数
    hz = 2000
    # 継続時間(ms)
    sec = 500
    winsound.Beep(hz,sec)

アラートに使用するmessageboxは警告や選択(はい・いいえ)などいくつかの機能を持っております。今回は、単純にお知らせできればいいだけなのでshowinfoを使用します。

# aleart
messagebox.showinfo("タイトル(見出し)","内容")

次の記事では、今まで書いてきたコードをクラスに分けて綺麗にします。

タイトルとURLをコピーしました