Harmoni という名前の iOS アプリを App Store にサブミットしました。このシンセアプリはゲームエンジン Unity を使って実装されています。
ここでは Unity を使ってシンセを実装するにあたっての心得(?)について記します。
サンプリングベースのリズムマシン等であれば basic 版でも実装可能ですが、スクリプトで合成した波形を使うには、Pro 版でないとキツいです。後述しますが、実装にオーディオフィルタを使うためです。
合成した波形を Unity 側に食わせる方法は色々ありますが、レイテンシを考慮した場合に最も優れているのはオーディオフィルタとして実装する方法です。他の方法では、どうしても大きなレイテンシが生じてしまいます。オーディオフィルタであれば、これを防ぐことが可能です。
まず、次のようにしてダミーのオーディオクリップを再生します。
function Start() {
audio.clip = AudioClip.Create("(null)", 0xfffffff, 1,
kSampleRate, false, true,
function(data:float[]){});
audio.Play();
}
同スクリプト内に OnAudioFilterRead を実装します。通常はこの中でオーディオをフィルタリングすることになりますが、ここでは入力を全く無視して、合成した波形を出力します。
function OnAudioFilterRead(data : float[], channels : int) {
for (var i = 0; i < data.Length; i += 2) {
synth.Run();
data[i ] = synth.l_out;
data[i+1] = synth.r_out;
}
}
Harmoni ではディオフォニックの FM シンセを実装しました(紹介文ではモノフォニックとなっていますが、リリースを奇麗にするために内部的にはディオフォニックにしています)。iPhone 4S や new iPad であれば問題無く動きますが、iPhone 4 ではサンプリングレートを半分に落とす必要がありました。
iOS ではこのようにモデル毎のチューニングが可能ですが、Android 版を作るとなれば、かなりのマージンを設ける必要が生じるでしょう。
正直なところ、スクリプトによる波形合成には非常に大きな無駄があります。ネイティブで実装するのと比較して 1/10 のスペックも実現できないでしょう。
でも逆に言えば、多大な労力を払ってネイティブ実装したとしても、得られるのは 10 倍のスペックだけです。例えば Smule の Ocarina が 10 倍のスペックになったとして、同時に 10 音鳴らせるようになって喜ぶユーザーがいるでしょうか?
スペックが必要なアプリを作りたい場合は、覚悟してネイティブに走りましょう。そうでなければ、スクリプト言語や Unity を使ってシンセを開発するというのは、許される選択肢だと思います。