(この記事は、2019年にQiitaに上げた記事の再投稿です。内容が古くなっている可能性がありますのでご了承ください。)

はじめに

音声分析って、面倒ですよね…

分析ソフト(GUI)で音声ファイルを開いて、F0平均値を取得して、Excelにコピペして、あれ、この結果、どのファイルのだっけ…(絶望)

そんな貴方におすすめ、音声分析ソフトPraatのマクロ機能1Praat script」!

Praat scriptを使って、F0分析をバッチ処理でぶん回し、結果をまとめてcsvに出力しましょう。

できたcsvはPandas, R, Excelなどでお好きなように弄ってください。

退屈な分析を楽チンに。そう、Praat scriptならね。

環境

appendInfoLine(praatVersion$)
> 6.1.04

Praat scriptは後方互換性があるので、Praatが上記バージョン以上なら問題なく動くと思います。

(不具合があった場合はコメントで教えていただければ幸いです。)

コード

GitHub - Syuparn/praat_batch_analysis: Extract F0 and Intensity of all .wav files, then save to .csv table

  • f0statistics.praat

指定したディレクトリ内の全wavファイルのF0平均、最大値、最小値を(1つの)csvファイルに集計し出力

  • f0contours.praat

指定したディレクトリ内の各wavファイルのF0時系列データを、音声ファイルと同名のcsvファイルに出力 (単位は[Hz])

  • intensitystatistics.praat

指定したディレクトリ内の全wavファイルのインテンシティ平均、最大値、最小値を(1つの)csvファイルに集計し出力 (単位は[dB])

ループ内の分析処理を変えればフォルマント等別の分析もバッチ処理できると思います。(丸投げ)

使い方

(例:f0contours.praat (他2つも同様))

Praatを起動して

「Praat」→「Open Praat script」→「Run」(or Ctrl+R) で実行します。

実行するとフォームが出てくるので、wavファイルのあるディレクトリを指定します。

終わり!

これで、ディレクトリ内の全wavファイルの分析結果がcsvファイルに書き出されました。

コマンドラインから実行

GUIを使わずにコマンドラインからスクリプトを実行することもできます。

> .\Praat.exe --run --utf8 C:\path\to\f0contours.praat C:\path\to\wavs 75 600 0

(ただし、デフォルト引数が代入されないため、すべての引数を明示的に渡す必要があります)

コード詳細

Praat Scriptの文法について

(マニアックな話になるので、「とにかく使いたい!」という場合は読み飛ばしてください)

Praat scriptは、基本的には多くの手続き型言語と同じ文法です。 ぱっと見でも大体のコードの流れが掴めると思います。

Praat script公式リファレンス http://www.fon.hum.uva.nl/praat/manual/Scripting.html

一方、他の言語と大きく違う箇所が2つあります。

ユーザー関数はない(procedureしか定義できない)

Praat scriptでは、組み込み関数以外に関数は存在しません。ユーザーが定義できるのはprocedureだけです。procedureは戻り値を返すことができません(VBAのsubプロシージャのようなもの)。

# ("#": 行頭コメント、";": 行中コメント)

procedure hello(.name$)
  appendInfoLine("hello, ", .name$)
endproc

# 呼び出しは先頭に"@"
@hello("Tom") ; "hello, Tom"

ローカル変数はprocedureのフィールド

Praat scriptでは、頭に".“をつけるとローカル変数、付けないとグローバル変数になります。

foo$ = "global"

procedure hoge()
  .foo$ = "local"
  appendInfoLine(foo$) ; "global"
  appendInfoLine(.foo$) ; "local"
endproc

@hoge()
# appendInfoLine(.foo$) ; error

ここまでは普通の言語と同じです。 違うのは、procedure内の変数に外部からアクセスできるところです。

言い換えると、ローカル変数はスコープを抜けても永遠に生き続けます。

procedure myProc()
  .val = 1
endproc

@myProc()
appendInfoLine(myProc.val) ; 1

procedureから値を返したい時に、このトリックを使っています。

procedure add(.x, .y)
  # ローカル変数.returnに結果を束縛
  .return = .x + .y
endproc

@add(2, 3)
# ローカル変数add.returnを参照
appendInfoLine(add.return) ; 5

最後に

当記事では、Praat scriptを使ってF0とインテンシティの分析、集計を自動化しました。

ですが、Praat scriptで自動化できるのはこれだけではありません… PraatのGUIで可能な全ての処理はPraat scriptで自動化可能です。

Praatメイン画面から 「Praat」→「New Praat script」→「Edit」→「Paste History」で GUIで行った作業の履歴をコード化したものが得られます2。 「この作業何度も繰り返しているような…」と思ったら、ぜひこのコマンドを使ってみてください。 コードを汎用化すれば、自動化の始まりです!

後はPraatにまかせて、コーヒーを飲んで一休みしましょう。


  1. マクロと言ってもただのコマンドではなく、れっきとしたチューリング完全な言語です。 ↩︎

  2. 残念ながら、表示やマウスでの範囲選択は上手くコード化されませんが… ↩︎