waveファイルをずたずたにして再構築するためのライブラリです。ライブラリ本体のほかに、waveファイルをかんたんにレンダリングするための render.rb というスクリプトと、リアルタイムでプレイするための play.rb というスクリプトが付属しています。
音を鳴らす部分にOpenALを利用していて、OpenALに触る部分はC拡張で書かれているため、ビルドが必要です。わたしは手元の mac でしかためしていませんが、OpenALがインストールされていれば Linux とかでも動くと思います。
$ cd /path/to/wavezutzutz
$ bundle install
$ bundle exec rake build
でビルドできます。
$ bundle exec ruby render.rb bpm source.wav score.txt > dest.wav
として使用します。bpmには出力したいテンポ、souce.wavにはずたずたにするwaveファイル、score.txtには楽譜ファイル、dest.wavには出力先のwaveファイル名をそれぞれ指定してください。
楽譜ファイルは以下のような感じで記述できます
a--- 0--- b--- --0- a--- 0--- b--- --0- a--0 a--0 a--0 a--0 a--- 0--- b--- --0-
c--- ---- c--- c--- d-0- e--- 0--- e--- f--- ---- ---- 0--- g--- g--- g--- 0---
a--- 0--- b--- --0- a--- 0--- b--- --0- a--0 a--0 a--0 a--0 a--- 0--- b--- --0-
c--- ---- c--- c--- d-0- e--- 0--- e--- f--- ---- ---- 0--- g--- g--- g--- 0---
r--- ---- ---- 0--- a0-- z--- z--- 0--- g--- g--- g--- 0--- e--- ---- ---- 0---
c--- ---- c--- c--- d-0- e--- 0--- e--- f--- ---- ---- 0--- g--- g--- g--- 0---
R--- ---- ---- 0--- a0-- z--- z--- 0--- g--- g--- g--- 0--- e--- ---- ---- 0---
C--- ---- c--- c--- d-0- e--- 0--- e--- f--- ---- ---- 0--- g--- g--- g--- 0---
/--- ---- 0--- c-0- a0-- 0--- g--- ---0 n--0 n--- ---- 0--- tttt tttt tttt 0---
/--- ---- 0--- c-0- a0-- 0--- g--- ---0 n--0 n--- ---- 0--- tttt tttt tttt 0---
*--- y--- 0--- c-0- a0-- 0--- g--- ---0 n--0 n--- ---- 0--- tttt tttt tttt 0---
*--- y--- 0--- c-0- a0-- 0--- g--- ---0 n--0 n--- ---- 0--- tttt tttt tttt 0---
小文字aからzまでの文字それぞれにずたずたにされたwaveファイルの"破片"がアサインされていて、大文字AからZにはそれぞれの小文字にアサインされた音の逆再生がアサインされています。-は音をのばす(タイ)を意味し、0は休符を意味します。*を指定すると、a-zのうちどれかをランダムで鳴らし、/を指定するとA-Zのどれかをランダムで鳴らします。1文字が64分音符ひとつ分の長さです。空白文字は無視されます。
$ bundle exec ruby play.rb bpm souce.wav
として使用します。 実行すると、sという変数にセットアップ済みのシーケンサーが代入された状態で pry が立ち上がるので、pry の REPL 上で演奏を行います。
s.set_sequence(sequence) でシーケンスをセットします、sequenceには、楽譜文字列そのものか、楽譜文字列を返すラムダを渡すことができます。楽譜文字列の記法は上記の楽譜ファイルに従います。ラムダを渡された場合、シーケンスがループする毎にラムダの内容が評価され、その結果帰った楽譜文字列を演奏することになります。
# set score string
s.set_sequence "a--- ---- ---- 0---"
# or set lambda which returns score string
s.set_sequence ->{"#{[*"a".."z"].sample}--- ---- ---- 0---"}
s.play を実行することで、シーケンサーの演奏が始まります。s.stop を実行することでシーケンサーの演奏を止めることができます。
演奏中にset_sequence を再度実行することで、音を聞きながらリアルタイムにシーケンスを設定することができるようになっています。
ちなみに、s.play をする前に s.rec_file(file_name)で録音ファイル(wav)を指定することで、プレイを録音することが可能です。s.stopした段階で書き出されます。
Rubyのラムダはクロージャになっているため、以下のようなプレイが可能です
pry > first_note = "a"
pry > s.set_sequence ->{"#{first_note}--- ---- ---- 0--- z--- ---- ---- 0---"}
pry > s.play
pry >
pry > first_note = "b" #シーケンスの最初の音が b に変わる
pry > first_note = "c" #シーケンスの最初の音が c に変わる
今回は単純に最初の音を変える例ですが、クロージャにいくつかのパラメータを渡しておいて、演奏中にそのパラメーターをいじることで動的に作曲をしていくみたいなことが可能になっています。
ライブラリは入力となるwaveファイルを解析したりずたずたにする部分である WaveZutaZuta::Wave と、サンプラー/waveレンダラーとして振る舞う WaveZutaZuta::Sampler::Renderer, リアルタイムプレイ用のサンプラーのクラスWaveZutaZuta::Sampler::Player, シーケンスを組んで演奏するための WaveZutaZuta::Sequencer に別れています。
Waveファイルを解析したりずたずたにできます。
WaveZutaZuta::Wave.new(wave_file_path)
として生成できます
pcm_metaオブジェクトを返します。pcm_metaオブジェクトは、waveファイルのfmtチャンクの内容などを保持したオブジェクトで、以下のアクセサを持ちます
pcm_meta.format # => waveファイルのフォーマットidを返します
pcm_meat.channels # => waveファイルのチャンネル数を返します
pcm_meat.samplerate # => waveファイルのサンプリングレートを返します
pcm_meat.bytepersec # => waveファイルのデータ速度を返します
pcm_meat.blockalign # => waveファイルのブロックサイズを返します
pcm_meat.bitswidth # => waveファイルの量子化bit数を返します
formとlengthは整数値を取ります。waveファイル内のリニアpcmデータから、from秒目からlength秒間のリニアpcmデータを返します.
formとlengthは整数値を取ります。waveファイル内のリニアpcmデータから、from サンプル目からlengthサンプル数のリニアpcmデータを返します。fromは0始まりです。
pcmデータをサウンドスロットに保持し、サウンドスロットに保持したデータを使ってwaveデータを構築することができます。
WaveZutaZuta::Sampler::Renderer.new(pcm_meta, bpm)
として生成できます。pcm_metaには、上述のpcm_metaオブジェクトを渡します。
一般的には、以下のような手順で使うことになると思います。
sampler = WaveZutaZuta::Sampler.new(pcm_meta, bpm)
# samplerのサウンドスロットに波形データをサンプリングする
sampler.set_sound(:sound_a, linear_pcm_data_a)
sampler.set_sound(:sound_b, linear_pcm_data_b)
# sampler 内部に保持されているバッファに、サンプリングされた波形データを書き込んで行く
sampler.play_sound(:sound_a, 16) # :sound_a にサンプリングした音を1拍分書き込み
sampler.play_sound(:sound_b, 16) # :sound_b にサンプリングした音を1拍分書き込み
sampler.play_rest(16 * 2) # 無音を2拍分書き込み
# 書き込みされた音をwaveファイルのバイナリとして読み出す
wave_data = sampler.to_wave
# waveファイルをファイルに書き出し
File.open(out, "w") do |f|
f.binmode
f.write(wave_data)
end
keyという名前でpcm_dataをサンプリングします。pcm_dataはバイナリ表現のリニアpcmデータを取ります。
keyという名前で保存してあったpcm_dataを内部バッファに書き込みます。lengthには64分音符いくつ分の長さのデータを書き込むかを指定します
無音を内部バッファに書き込みます。lengthには64分音符いくつ分の長さのデータを書き込むかを指定します
内部バッファに書き込まれた波形データを、waveのバイナリ表現として返します。
pcmデータをサウンドスロットに保持し、サウンドスロットに保持したデータを使ってリアルタイムにサウンドを鳴らすことができます。
WaveZutaZuta::Sampler::Player.new(pcm_meta, bpm)
として生成できます。pcm_metaには、上述のpcm_metaオブジェクトを渡します。Rendererとほぼ同じインターフェイスですが、to_waveメソッドが存在しません。
WaveZutaZuta::Sampler::Player を wrap したシーケンサーです。play.rbから使うことを意図しています。
MIT License