はじめに
Cython初心者です。備忘録として。
やりたいこと
特定のディレクトリ内にある複数の音声データ(.wavや.mp3など)を読み込み、それぞれのファイルについて無音部分ごとに分割する。読み込まれた音声データや出力される音声データは別のディレクトリに移動させる。
何故Cythonなのか
大きな音声データを扱うための前処理として行う際に、Pythonだと速度が足りないため。
実行環境
OS : Windows10
ディレクトリ構成は以下のような感じ。
sample
|- datas_input # 読み込む音声ファイル
|- datas_output # 出力される音声ファイル
| |- outputs # 分割された後の音声ファイルが入る
|- main.py # 実行ファイル
|- sounds.pyx # Cythonによるモジュール
|- setup.py # Cythonコードをコンパイルするためのファイル
必要なライブラリ・モジュール
事前にpydubをインストールしておく。
参考はこちら
また、忘れずにpip install cython
もしておく。
from glob import glob
from pydub import AudioSegment
from pydub.silence import split_on_silence
from os.path import basename
import shutil
処理内容
sounds.pyx
cdef split(data):
cdef int n = 0
cdef str file_path = ''
cdef list data_list = []
sound = AudioSegment.from_file(data)
chunks = split_on_silence(sound, min_silence_len = 1000, silence_thresh = -50, keep_silence = 100)
for n, chunk in enumerate(chunks):
file_path = 'datas_output/outputs/output' + str(n) + '_' + basename(data)
data_list.append(file_path)
chunk.export(file_path)
return data_list
cpdef load():
cdef list sounds = []
cdef list sound_list = []
cdef list new_sound_list = []
cdef str data = ''
sounds = glob('datas_input/*')
if len(sounds) == 0:
print('There is no data')
return None
for data in sounds:
sound_list.append(shutil.move(data, 'datas_output/'))
for data in sound_list:
new_sound_list.extend(split(data))
return new_sound_list
簡単な説明
-
glob('datas_input/*')
でdatas_input
にある全てのファイル名のリストを一括で取得。 -
shutil.move(data, 'datas_output/')
でdata
をdatas_output/
に移動。 -
AudioSegment.from_file(data)
でdata
を読み込み。 -
split_on_silence(sound, min_silence_len = 1000, silence_thresh = -50, keep_silence = 100)
でsound
を無音部分ごとにカット。参考はこちら -
chunk.export(file_path)
でfile_path
に出力。
Cythonを使うための処理
setupのためのファイル。
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext' : build_ext},
ext_modules = [Extension('sounds', ['sounds.pyx'])]
)
呼び出し側のPythonコード
こちらはCythonで作られたモジュールをimportする側。
main.py
import sounds
def main():
sound_list = sounds.load()
if sound_list == None:
exit()
for data in sound_list:
print('[data] : ' + data)
# ...処理...
if __name__ == '__main__':
main()
実行
main.py
を実行すると、datas_input
に入っていた音声データが全てdatas_output
に移動する。さらに、そこにsplitされた後の音声データも保存されているはずである。テスト用データは、こちらからダウンロードしておくとよい。上手くいけば、以下のような結果が得られる。
$ python setup.py build_ext --inplace
$ python main.py
[data] : datas_output/outputs/output0_〇〇.mp3
[data] : datas_output/outputs/output1_〇〇.mp3
[data] : datas_output/outputs/output2_〇〇.mp3
[data] : datas_output/outputs/output0_△△.mp3
・
・
・
エラーが出たら
同じディレクトリ内にffmpeg.exe
とffmprobe.exe
があるかどうかチェックする。それ以外の場合はエラーメッセージをググる。