イントロクイズの作り方 ~soxの使い方を解説~

Linuxでsoxをシェルスクリプトと組み合わせて使う

※本記事は、Linuxを使っての作業方法の説明です。
WindowsでLinuxを利用する方法はこちら↓

※本記事には、soxと呼ばれる対話形式の音声編集ソフトを使って
大量の音声ファイルを編集するプログラム(シェルスクリプト)のサンプルを掲載しています。→こちら

音声ファイルの編集には、Audacityと呼ばれる音声編集ソフトを使うと、作業が直感的でわかりやすいものになりますが、対象とする音声ファイルが100や200になったらどうでしょうか?
今回は大量の音声ファイルの編集をスクリプトを使用してなるべく自動化するための方法を紹介します。

Audacityを使用した音声ファイルの編集方法についてはこちら↓

~Audacityやsoxの使いどころ~
例えば、
上司に「会社の宴会の余興で何か企画してくれ」
と頼まれたとします。そこで、イントロクイズをやることにし、Audacityを使えばよいということがわかりました。Audacityを使えば、

問題音源(曲の開始から10秒間だけ取り出した音声ファイル)と
正解音源(曲のサビの部分だけを10秒間だけ取り出した音声ファイル)を作成することができます。

それを上記の記事で解説しました。

そこで、早速Audacityで作業に取り掛かったのですが・・・。

ディープル

あ~・・・。疲れた。。

シママ

あ、あなた、まだやってたの?もう午前1時なんだけど・・・、

ディープル

うん。この宴会、社員旅行も兼ねて泊まり込みでやるんだ。だから、余興がいつまで続くか分からない。それに1問2~3分で終わっちゃうから、100曲は用意したいな。と思って・・・。

シママ

それで、100曲をAudacityで作ろうと・・・?

ディープル

うん・・・。

シママ

バカだね~ww そんなにたくさん作るんだったらもっとラクな方法があるよ!

ディープル

・・・。

シママ

(あっ、ディープルに軽々しくバカだね~なんて言っちゃった・・。冗談通じないからなぁ、この子。いけないいけない・・・。)

シママ

そんなにたくさん作るなら、別の方法があるよ!先に教えておけば良かったね。ごめんごめん!
soxという音声編集ソフトがあって、これをLinuxで動かせばAudacityで一曲一曲編集するよりもラクに大量に編集できるよ!

ディープル

そのやり方、教えて欲しいな・・・。

シママ

わかった!いいよ!

というわけで、今回は、Linux(ubuntu)でsoxを動かして大量の音声ファイルを処理する方法を説明します。

soxとは?

対話型音声ファイル編集ソフト sox

soxとは、対話形式で音声を編集するためのソフトです。
対話形式のソフトでは、そのソフトが動くためのコマンドを打ち込んで作業を進めていきます。

以前、対話形式でグラフを書くソフトgnuplotを紹介いたしました。
今回はそれの音声ファイル編集版と考えて頂ければOKです。

Audacityでは、ソフトに曲を取り込み、それの波形を切ったり貼ったりして編集を進めていくのですが、soxでは全て文章で編集を進めていきます。

例えば、

「sox before.mp3 after.mp3 trim 0 10」

と打ち込んで実行すればbefore.mp3の音声ファイルのうち、0秒地点(開始)から10秒間だけトリミング(trim)した音声をafter.mp3というファイル名で出力することができます。

つまり、このコマンド1本で問題音源を作成することができます。

このようにして、文章(コマンド)で音声ファイルの編集を進めていくのがsoxです。

コマンドで編集を進める意味

ディープル

ねぇ、どうしてわざわざコマンドを使って編集しなくちゃいけないの?正直、わかりにくいな・・・

シママ

Audacityで100曲のイントロクイズを作るなら、100回ソフトに取り込んで、開始から10秒間だけ切り取って・・・という作業をしなくちゃいけないじゃない?

ディープル

うん。

シママ

それって、めんどくさくない?同じことを何回も繰り返すのって、嫌じゃない?

ディープル

嫌だけど、しょうがないよ・・・

シママ

コマンドで編集することが出来れば、しょうがないものもしょうがなくなくなるのよ。
同じことを何回も繰り返すのが嫌だったらプログラミングしてしまえばいいのよ。プログラミングは文章の方がラクでしょう?

Audacityは視覚的に編集できるように作られているので、1つの曲に色々な効果を与えて1つの新たな作品を作るのには適しておりますが、
100回も同じ作業をするのであれば、コマンドで操作できるsoxを使った方が便利なのです。

同じ作業を何回も繰り返すのであれば、プログラムを組んで自動化させてしまった方がはるかに効率的であり、
プログラミングで音声編集したいのであれば、コマンドで編集できるsoxを使用したほうが都合がよいのです。

soxのコマンド

今回使用するsoxのコマンドは以下の通りです。

切り取り

コマンド①
sox 楽園の午後.mp3 楽園の午後_10.mp3 trim 0 10
コマンド① 意味
楽園の午後.mp3の音声ファイルのうち0秒から10秒間だけ切り取って、楽園の午後_10.mp3という名前で保存しなさい

コマンド②
sox 楽園の午後.mp3 楽園の午後_26-36.mp3 trim 26 10
コマンド② 意味
楽園の午後.mp3の音声ファイルのうち26秒から10秒間だけ切り取って、楽園の午後_26-36.mp3という名前で保存しなさい
つまり、このファイルは原曲「楽園の午後.mp3」の26秒~36秒だけ切り取ったファイルになります。

シママ

実際に上2つのコマンドを実行して作った音声ファイルがこちら!

楽園の午後.mp3 (原曲)

コマンド① 実行結果
楽園の午後_10.mp3 (0秒から10秒間切り取り 原曲の0~10秒の領域)

コマンド② 実行結果
楽園の午後_26-36.mp3 (26秒から10秒間切り取り 原曲の26~36秒の領域)

原曲にはこちらのサイトの素材を使用させていただきました。
————————————————————————–
【サイト名】フリー音楽素材 H/MIX GALLERY 様
【管理者】 秋山裕和 様
【アドレス】http://www.hmix.net/

————————————————————————–

フェードイン・フェードアウト

コマンド③
sox 楽園の午後_10.mp3 楽園の午後_10_in.mp3 fade t 5
コマンド③の意味
先頭から5秒間でフェードインしなさい

コマンド③実行前
コマンド③実行結果

コマンド④
sox 楽園の午後_10.mp3 楽園の午後_10_fade.mp3 fade t 0 10 5
コマンドの意味④
先頭から10秒間の時点を終了位置とし、終了5秒前からフェードアウトしなさい。
楽園の午後_10.mp3は10秒の音声ファイルです。したがって、「0 10」の部分で終了位置をsoxに教えてあげた上で、その5秒前からフェードアウトしなさいと指示しています。

コマンド④実行前
コマンド④実行結果

その他

soxでは他にも音量を上げる、複数の音声ファイルを連結する、ハイパス・ローパスフィルターをかける、など様々な編集を行うことができます。
参考サイトはこちら↓

イントロクイズ作成プログラム

サンプルプログラム

シママ

コマンドの書き方がわかったら、そのコマンドをプログラムに書いて実行すればいいね。
今回の問題、イントロクイズ作成のためのプログラムを書いてみたよ!


※サンプルプログラム開始
————————————————————————–
#!/bin/bash

files=”*”

fileary=()

for filepath in $files; do
fileary+=(“$filepath”)
done

for i in `seq -f %03g 0 3`

do
cp ${fileary[i]} $i.mp3
sox $i.mp3 $i”_”q.mp3 trim 0 10
sox $i”_”q.mp3 $i”_”q_fade.mp3 fade t 0 10 5
rm $i”_”q.mp3
echo “input ans time ${fileary[i]}”
read ans
sox $i.mp3 $i”_”a.mp3 trim $ans 10
sox $i”_”a.mp3 $i”_”a_in.mp3 fade t 3
sox $i”_”a_in.mp3 $i”_”a_in_out.mp3 fade t 0 10 3
rm $i”_”a.mp3
rm $i”_”a_in.mp3

mv $i”_”q_fade.mp3 $i”_”${fileary[i]}_q.mp3
mv $i”_”a_in_out.mp3 $i”_”${fileary[i]}_a.mp3

done
————————————————————————–

※サンプルプログラム終了

プログラムの使い方

ディープル

・・・なんのことだか、サッパリ・・・。

シママ

まぁまぁ、実行してみてよ。今、編集したい曲が3曲あって、そのファルダと同じところに、このサンプルプログラムがあるとしよう


シママ

この状態で端末(コンソール)を起動して「./sox」と打って、soxのファイルを実行してごらん?

ディープル

input ans time soxって出て止まっちゃったけど・・・


シママ

これは0と打って。これはダミープログラムなの。

ディープル

input ans time 夏の秘密基地は?


シママ

これはこの曲のサビ開始地点の入力を要求しているのよ。

シママ

ごめん。サビの部分の開始地点の判断は手動でやらなくちゃいけないの。

ディープル

1曲1曲サビが始まる時間を聴いて記録しなくちゃいけないってこと?

シママ

そう。ここだけ自動じゃないけど、勘弁ね。

ディープル

わかった。 ・・・ この曲のサビ開始地点は32秒だよ

シママ

なら32って入力して。

ディープル

次にinput ans time 楽園の午後って出たけど、これも自分で調べたサビ開始地点を入力するってことでいいよね?

シママ

そのとおり。これをずっと繰り返すと最終的にこんな画面になる。

シママ

これで、「002_楽園の午後_q」と「002_楽園の午後_a」を再生してごらん?

002_午後の楽園_q
002_午後の楽園_a

ディープル

あ!問題音源と正解音源がちゃんとできてる!qはquestion, aはanswerだよね?

シママ

そう!とりあえず、このプログラムはあげるから、これで手っ取り早く100曲つくってごらん?

ディープル

わかった!

プログラムの意味

シェルスクリプト

数日後・・・

ディープル

シママ!イントロクイズすごく盛り上がったよ!ありがとう!!

シママ

それは良かった!

ディープル

係長が「いやーこれはそう簡単にできるものじゃないよ~。よく頑張ったね。」って言ってくれたよ!

ディープル

・・・ところで、あのプログラムの意味を教えて欲しいな。

シママ

わかった!じゃあ、一つ一つ説明していくよ。もう一回プログラムを掲載するね。

※サンプルプログラム開始
————————————————————————–
#!/bin/bash

files=”*”

fileary=()

for filepath in $files; do
fileary+=(“$filepath”)
done

for i in `seq -f %03g 0 3`

do
cp ${fileary[i]} $i.mp3
sox $i.mp3 $i”_”q.mp3 trim 0 10
sox $i”_”q.mp3 $i”_”q_fade.mp3 fade t 0 10 5
rm $i”_”q.mp3
echo “input ans time ${fileary[i]}”
read ans
sox $i.mp3 $i”_”a.mp3 trim $ans 10
sox $i”_”a.mp3 $i”_”a_in.mp3 fade t 3
sox $i”_”a_in.mp3 $i”_”a_in_out.mp3 fade t 0 10 3
rm $i”_”a.mp3
rm $i”_”a_in.mp3

mv $i”_”q_fade.mp3 $i”_”${fileary[i]}_q.mp3
mv $i”_”a_in_out.mp3 $i”_”${fileary[i]}_a.mp3

done
————————————————————————–
※サンプルプログラム終了

シママ

まず、このプログラムはシェルスクリプトなの。Linuxでの作業は全部シェルでできると言っても過言じゃなくて、シェルは勉強すればするほど、複雑だなと思うかもしれないけど、
とりあえず、Linuxで端末起動して打ち込むコマンドのまとまりと思ってくれればいいよ。

ファイル名を配列に格納

3行目から9行目の部分
files=”*”

fileary=()

for filepath in $files; do
fileary+=(“$filepath”)
done
この部分ではファイル名を配列に格納しています。

files=”*”
では、シェルスクリプトファイルの存在するフォルダ(Linuxではディレクトリと呼ぶことが多いです)内全てのファイル名をfilesの変数に格納しています。

シママ

*はワイルドカードと言って、どんな数字、どんな文字列にもマッチする記号のことをいうのよ。
*では0文字以上の任意の文字列にマッチするパターンを表すから、*一文字では全てのファイル名を表すことになるの。
ちなみに「file*」のような書き方をすれば「file_a」とか「file015」のような先頭にfileのついたファイル名だけが、filesの対象になるのよ。

fileary=()
では、filearyの配列を宣言しています。

for filepath in $files; do
fileary+=(“$filepath”)
done
このループでは、filesの中身を一つ一つをfilearyという配列に格納しています。

この時点で

fileary[0]はsox
fileary[1]は夏の秘密基地
fileary[2]は午後の楽園
fileary[3]は新天地

となりました。

シママ

シェルでは、変数に格納された数値を呼び出すには$を前につける必要があるの。ファイル名の文字列がfiles→filepath→filearyへ順番に格納されていっているよね。

あと、今回わざわざファイル名をfilearyという配列に入れたのには、数字と曲名をリンクさせるという役割があるの。
ファイル名が曲名だとfor文みたいな繰り返し文で連続処理できないから、一旦ファイル名を数字にしてしまうという方針をとったのよ。

問題音源の作成

11行目~17行目の部分

for i in `seq -f %03g 0 3`

do
cp ${fileary[i]} $i.mp3
sox $i.mp3 $i”_”q.mp3 trim 0 10
sox $i”_”q.mp3 $i”_”q_fade.mp3 fade t 0 10 5
rm $i”_”q.mp3

for文を使ってループさせます。例文ではi=0からi=3までループさせています。
i=1の時を例にとって説明します。

fileary[1]は夏の秘密基地でした。これをコピーしたうえで001.mp3というファイル名に変更します。

シママ

「%03g」の部分で3桁の数字に揃えているから、1ではなく001になるのよ。
それから、””は変数かどうかを区別するための記号でアンダーバーを””で囲むことで、アンダーバーは変数に含まれない変数はiだけということをコンピュータに教えてあげることができるの。

次にsoxを使って001.mp3を最初の10秒間だけ切り取って001_q.mp3とします。

その次に001_q.mp3の後ろ5秒をフェードアウトする処理を行って001_q_fade.mp3として出力します。

最後に001_q.mp3は不要なので削除します。

正解音源の作成

18行目~24行目の部分
echo “input ans time ${fileary[i]}”
read ans
sox $i.mp3 $i”_”a.mp3 trim $ans 10
sox $i”_”a.mp3 $i”_”a_in.mp3 fade t 3
sox $i”_”a_in.mp3 $i”_”a_in_out.mp3 fade t 0 10 3
rm $i”_”a.mp3
rm $i”_”a_in.mp3

echo “input ans time ${fileary[i]}”は正解音声の開始時間の入力を要求する文章を端末上に表示するスクリプトです。
i=1なら、fileary[1]は夏の秘密基地ですから、端末上には

「input ans time 夏の秘密基地」

と表示されます。
ここで、1曲1曲サビの開始部分を聞き取ってメモし、その結果を入力していきます。この部分は残念ながら手作業でやらざるを得ません。

夏の秘密基地の曲では32秒からサビだったので32と入力し、変数ansへ格納します。

次にsoxを使って001.mp3のサビ開始部分から10秒間の部分を切り取り、001_a.mp3として出力します。

その次は、開始3秒と終了前3秒をそれぞれフェードイン、フェードアウトします。

フェードインを施したファイルは001_a_in.mp3となり、その後にフェードアウトを施したファイルは001_a_in_out.mp3という形で出力されます。

途中にできた001_a.mp3と001_a_in.mp3は不要なので削除します。

曲名の復元

以上の操作で
問題音源「001_q_fade.mp3」と正解音源「001_a_in_out.mp3」
が出来上がります。しかし、このままだと何の曲か分からないため、曲名を復元します。

配列fileary[1]には「夏の秘密基地」が格納されていることを思い出してください。

従って26、27行目
mv $i”_”q_fade.mp3 $i”_”${fileary[i]}_q.mp3
mv $i”_”a_in_out.mp3 $i”_”${fileary[i]}_a.mp3
で曲名が復元されます。

001_q_fade.mp3は001_夏の秘密基地_q.mp3に
001_a_in_out.mp3は001_夏の秘密基地_a.mp3になります。

最後に29行目のdoneで1曲の処理が終了し、i=1はi=2になって、13行目のdoに戻ります。
これを100回ループすれば、イントロクイズ100曲の完成です。

ポイント

今回はシェルスクリプトのfor文を利用して、同じ複数回の処理が1回の処理で済むようにスクリプトを書きました。
今回の処理の難しさは2点

①曲名のままでは、繰り返し処理できないこと
②サビの位置は曲ごとに異なること

まず①ですが、曲名、夏の秘密基地/午後の楽園/新天地ではループを回すことができません。これを数字に変換して、その数字と曲名を紐づけてあげなければいけません。
そこで配列を使用します。当然配列の中には文字列を入れることができるので、内容物を曲名、配列の番号を数字とすることで、数字と曲名の紐づけができるようになります。

②については、サビの開始部分は曲ごとに異なり、サビ開始の判断はコンピュータにはできません
(少なくとも私、しままるはやり方を知りません。AIでも使わないとできないのではないでしょうか?)
従って、1曲1曲聴いてサビ開始位置のデータを取得する作業が必要になります。これがこの作業を行うにあたって一番面倒な点だと思います。

ただし、100曲全部をAudacityで編集するよりは明らかにラクです。

まとめ

今回は、soxという音声編集ソフトを利用して大量の音声ファイルをシェルスクリプトで処理する方法をイントロクイズの作成というお題で説明しました。

ディープル

普段、パソコンでやっている作業も、もしかしたらLinuxのシェルスクリプトを使うことで効率化できるかもしれないね。

シママ

そう!今回はイントロクイズの作成を例に説明したけど、
グラフの作成とか、ファイルの改名とか、同じ作業を何回も繰り返すような作業をやるときにはシェルスクリプトが使えるかな?と考えてみるといいかもね!

原曲の出典

原曲にはこちらのサイトの素材を使用させていただきました。
————————————————————————–
【サイト名】フリー音楽素材 H/MIX GALLERY 様
【管理者】 秋山裕和 様
【アドレス】http://www.hmix.net/

————————————————————————–

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です