iPhoneでDSP
ようやくautocorrelationのグラフがiPhoneデバイス上でサクサク動くようになった。
写真はトランペットでハイC(4A♯ in C)を吹いたとき。基準となる4Aよりちょっと上が正の最大振幅になっている。スクリーンショットを撮ると最新データしか写らないのだが、実際には古いデータも線を細く、色を薄くしながら表示しているので、次々に姿を変えながら動く生き物みたいだ。
それで、iPhone上でサクサク動くようになった理由だが、結局のところコードの徹底的なスリム化だった。
例えば、inline関数を使う。InstrumentsのCPUをサンプリングしてどの部分がCPUを消費しているか調べ、何度も繰り返し呼ばれる部分をinline化する。
まず、8.24形式の固定小数点のかけ算。私の場合次のような具合だ。
inline SInt32 multiply(SInt32 value1, SInt32 value2){return (SInt32) (((SInt64)value1 * (SInt64)value2) >> 24);}
これらは8.24と8.24同士のかけ算だが、相当呼ばれるので、inline化の効果が大きかった。
それから、squared magnitude。
inline float squareMagnitude(float f1, float f2){return (float) sqrt(pow(f1, 2) + pow(f2, 2));}
さらに、高速フーリエ計算は完全に8.24の複素数で演算するようにした。
また、オブジェクトではなく配列を使うというのもやはり効果的だった。NotificationCenter経由でNSMutableArrayを渡したりせず、所有者を明確にした上でfloat*を使う。これによって不可解な挙動がなくなった。
その他、aurioTouchサンプルが大変参考になる。32bitで1.15の固定小数点を使って複素数を表現したり、SInt32*をSInt16*、SInt8*にダイナミックに読みかえてコンパクトな演算をしている。ARMのアセンブリも使っている。コメントと食い違う実装があったり、あれを作った本人が本当に把握できているのかなんだか疑わしくなるが、ここに挙げたのもaurioTouchで勉強させてもらったし、C/C++とObjective-Cの受け渡し、OpenGL-ESなどもあり、iPhoneでDSPをやる人には宝の宝庫だと思う。