サウンドデザインに関する文書の翻訳

2009年7月28日火曜日

波形を描く

再生中の音の波形を描画したい場合があるだろうね。オーディオデータの入出力を操作するMinimの中のクラスは全てAudioSourceクラスの派生クラスだ(ただしAudioSnippetは除く)。
AudioSourceクラスは3つのAudioBufferメンバを定義し、AudioSourceクラスを拡張したクラス群に継承される。AudioPlayerクラスはまさにそのようなクラスで、AudioPlayerオブジェクトによってこれらのバッファにアクセスすることができる。バッファはleft、right、mixという名前。
それぞれ左チャンネル、右チャンネル、そして左右のミックスを含んでいる。あなたが再生しているファイルがモノラルだとしても、3つの全てのバッファは取得できるし値も返ってくる。モノラルのファイルを再生してみると、単純に全てのバッファが同じ情報を持っているということがわかるだろう。では波形を描いてみよう。前回(メタデータを抽出する)のdraw関数をこのように再定義する:

void draw()
{
background(0);
stroke(255);
// 線で隣の値をつなぐことで波形を描く
// 値は-1から1の間にノーマライズ(均一化)されているのでそれぞれ値を50倍する
// 拡大しなかったらただの線にしか見えないかも
for(int i = 0; i < song.bufferSize() - 1; i++)
{
line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50);
line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50);
}
}


この描画コードはsongクラスがどんな種類の入力や出力でも機能する。何故なら全ての入出力はAudioSourceクラスを拡張していて、バッファを提供する形式になっているから。と言っても上のコードには2つ問題点がある。setup関数はデフォルトだと100×100になってしまうのと、僕らはバッファがどれだけ長いかを知らない(つまりsong.bufferSize()がどんな数を返すのかということ)。最初の問題の解決は簡単で、ウィンドウサイズを512×200にすればいいだけ。2番目の問題は、loadFileを呼ぶ時にバッファの長さを指定することで解決可能。ということでsetup関数はこうなる:

void setup()
{
size(512, 200);

minim = new Minim(this);

// サンプルバッファのサイズを512に指定
// デフォルトのバッファサイズは1024
song = minim.loadFile("mysong.wav", 512);
song.play();
}

これで僕らはバッファの中身と全く同じ大きさの表示用スクリーンを持っていることになる。もしバッファサイズを指定しなければ、1024サンプルになる。

訳注:前回のサンプルから書き換える場合、変数名をgrooveからsongに変えておかないと動きません。

2009年7月26日日曜日

メタデータを抽出する

メタデータとはファイルについての情報のこと。実際のコンテンツと対応するもの。AudioPlayerに読み込んだ後、ファイルのメタデータを取得できる。これやりたい理由のほとんどはID3タグの情報を表示だと思う。短い例を示す:

import ddf.minim.*;

Minim minim;
AudioPlayer groove;
AudioMetaData meta;

void setup()
{
size(512, 256, P3D);

minim = new Minim(this);
// groove.mp3はスケッチのdataフォルダに入れておくこと
groove = minim.loadFile("groove.mp3");
meta = groove.getMetaData();

// serif.vlwはスケッチのdataフォルダに入れておくこと。PDEのToolsメニューからCreate Font...で。
textFont( loadFont("serif.vlw") );
textMode(SCREEN);
}

int ys = 15;
int yi = 15;

void draw()
{
background(0);
int y = ys;
text("File Name: " + meta.fileName(), 5, y);
text("Length (in milliseconds): " + meta.length(), 5, y+=yi);
text("Title: " + meta.title(), 5, y+=yi);
text("Author: " + meta.author(), 5, y+=yi);
text("Album: " + meta.album(), 5, y+=yi);
text("Date: " + meta.date(), 5, y+=yi);
text("Comment: " + meta.comment(), 5, y+=yi);
text("Track: " + meta.track(), 5, y+=yi);
text("Genre: " + meta.genre(), 5, y+=yi);
text("Copyright: " + meta.copyright(), 5, y+=yi);
text("Disc: " + meta.disc(), 5, y+=yi);
text("Composer: " + meta.composer(), 5, y+=yi);
text("Orchestra: " + meta.orchestra(), 5, y+=yi);
text("Publisher: " + meta.publisher(), 5, y+=yi);
text("Encoded: " + meta.encoded(), 5, y+=yi);
}

void stop()
{
// 使い終わったらMinimオーディオクラスをcloseしよう
groove.close();
// 終了前にMinimをstopしよう
minim.stop();

super.stop();
}

ファイルの再生

Minimを作ったひとつの大きな動機は、Processingで使える既存のライブラリでは、どっちもオーディオファイルをステレオでプレイバックできなかったこと。それMinimでできるよ!Minimだとファイル再生はめちゃめちゃ簡単。君のスケッチのデータフォルダ(訳注:processingで画像や音声などのデータを使用する場合、作業フォルダの中にdataという名前のフォルダを作って、その中にファイルを入れます)にファイルを入れて、このコードを書くだけ:

import ddf.minim.*;

Minim minim;
AudioPlayer song;

void setup()
{
size(100, 100);

minim = new Minim(this);

// this loads mysong.wav from the data folder
song = minim.loadFile("mysong.wav");
song.play();
}

void draw()
{
background(0);
}

void stop()
{
song.close();
minim.stop();

super.stop();
}


Minimは典型的な非圧縮のファイルならWAV、AIFF、AUとかは全部再生できるし、javazoomのMP3SPIパッケージのおかげでmp3だって再生できる。

セットアップとシャットダウン

Minimを使うには、まずMinimオブジェクトをインスタンス化する必要がある。そしてそれを使うことで、君はオーディオファイルを読み込んだり、入力や出力を得ることができる。あとそれから、プログラムが終わる前に、Minimから取得する音声入出力クラスは全てcloseして、minimインスタンスをstopしておくようにね。Audio IOクラスにはAudioPlayer、AudioSample、AudioSnippet、AudioInputとAudioInputがある。これが今言ってることの例:

Minim minim;
AudioPlayer player;
AudioInput input;

void setup()
{
size(100, 100);

minim = new Minim(this);
player = minim.loadFile("song.mp3");
input = minim.getLineIn();
}

void draw()
{
// ここに処理を書く
}

void stop()
{
// Minim.loadFile()から得たAudioPlayer
player.close();
// Minim.getLineIn()から得たAudioInput
input.close();
minim.stop();

// これはあなたが自身で定義してオーバーライドした
// stopメソッドを呼ぶ
// あなたのアプリケーションが通常通り全てをクリーンアップできるように
// 呼ばれなければならない
super.stop();
}


Ess とSoniaのユーザはこの慣習に慣れてると思う。何でこんなことするかってのは全ての音声入出力はスレッドを分けて扱われていて、通常の手順で終わることが許されなければならないから。プログラムの実行中に、保持しているリソースを解放するためにオーディオクラスをcloseすることもあるかもね。