SoundFont からサンプル抜出しのループ対応

これの続き → SoundFont から PCM データ抜出し - yoyaのメモ


ループ対応しました。変更内容 → http://openpear.org/changeset/2959

IO_SoundFont 1.0.2 としてリリースしました。

使い方

yoya@sakura:~/svn/IO_SoundFont$ php sample/sfextractsample.php emuaps_8mb.sf2 1

のように SoundFont ファイルの次の引数に秒数を指定して実行すると、SoundFont内の PCM データを抜き出す際に指定秒数ループして wav に保存します。

エンベロープ ADSR をかけてないので不自然な音に聞こえると思います。減衰(Decay)ないので。
次の課題にします。

備考

直観で実装してたら、emuaps_8mb.sf2 の Glockenspiel D6 のようにループの短いサンプルでノイズが混ざったり、Flute では loopStart 前後で音程が変わりました。

WebAudio で鳴らす時は SoundFont の loopEnd をそのまま設定してるので気にしませんでしたが、End ポイントのオフセット自体でなく、その1つ次のオフセットを指すようです。

図にするとこんな感じ。(等幅フォントでご覧ください)

 +start  loopStart loopEnd (end は分からないので省略)
 |       |         |    
+---------------------------
| | | | | | | | | | |
+---------------------------
        <---------> 実際の loop 範囲 ○
        <-----------> 期待してた範囲 ×

(end はまだよく分かりません。実用上はどうでも良さそうなので理解は後回し)

違和感がそのままコードにコメントとして残ってしまいました。

$loopCount = $looptime * $sampleRate / ($endLoop - $startLoop /*+ 1*/);
$loopCount = ceil($loopCount); // round up
$sampleData = substr($data, $start * 2 , ($startLoop - $start) * 2);
$sampleData .= str_repeat(substr($data, $startLoop * 2 , ($endLoop - $startLoop /*+ 1*/) * 2), $loopCount);
$sampleData .= substr($data, ($endLoop /*+ 1*/) * 2 , ($end - $endLoop + 1) * 2);

コメントを削るかどうか迷ってます。