AVRマイコンで口笛をMIDIへ変換してみる
以前 YMF825Board交流会(私は交通事故で入院して参加できませんでした)で
たくまーさんが8bit Kuchibueというのを発表されてまして、いつか私もやって見たいな~と
思っていたのですが、先日作ったArduino+YMF825の入力がusartなので
解析だけならAVRマイコンでもなんとかなるのではないかと考えてやって見ました。
口笛を解析するわけですけど、取りあえず波形を見てみます
意外と素のSin波に近いのが分かります、これならFFTでピークの周波数拾って
MIDIのTONE_NOに対応させれば何とかなりそうですね。
FFTライブラリ
FFTのプログラムを最初から書く力量はありませんのでAVR(Arduino)で使えそうなのを探します
ピーク周波数が拾えればよいので精度8bitのものを探すと
ArduinoFFT が見つかりました。
FFTのライブラリ触るのが初めてなので、どっちが良いのかわからないので
並行して作業をおこないますが両者の特徴は
Modified 8bit FFT in c
- 使用メモリが少ない(256pointで512byte+α)
- 全部C++で書いているので改変し易い
- そのままでは遅い(256pointで改良しまくっても10msぐらいかかる)
- 古いのでメンテナンスされていない
ArduinoFFT
- 使用メモリ多め(256pointで1Kbyte)
- アセンブリ言語で書いてこれ以上改良出来そうもない
- 速い(256pointで7ms弱)
- 完成度高く高機能
試行錯誤の連続
最初は128pointで始めて見たのですが、低音が分解しきれず256pointへ移行
サンプリング周波数を色々変えて試した結果我慢できる精度を得るにはサンプル数256に
落ち着いたのですが、サンプリングしてから解析していると、1回の解析に120ms以上かかってしまいます
これではまるで「エコー」で聞くに堪えません
ローパスフィルタ入れてみたり、電源をADC回りで分離させたりしながら色々しながら
サンプリングのバッファを2つにして、解析しながらタイマ割り込みを行いサンプリングするようにした結果
ArduinoFFTはAtmega328ではメモリ不足になるためModified 8bit FFT in cの一択になり
ソースとにらめっこして高速化出来そうな所を探ります
FIX_MPY()の助長な処理とsqrt関数を使っている所をテーブル処理に変更して処理速度はそれなりに
なって128バイト読み込みごとに解析したのがこれ
まだ、遅れが目立ちますが解析精度がいまいち、思いっきり音痴です
精度を上げるためサンプリング周波数を下げて、代わりにデータを64byte読み込んだら
解析するようにしてみました(あっさり書いてますが実は何度もソース書き直しました)
今の所
* サンプリングレート 452us 2.212KHz
* 時間窓 452 * 256 = 115ms 8Hz
* 1/4時間窓ごとに変換するので 32Hz周期で変換
MIDIのTONE_NOへの変換は単純にテーブル参照しているだけですので
口笛の特徴として、発音開始時は少し周波数が低いとかあるので
アルゴリズムを工夫すればもっと変換精度と上げることが出来るかもしれませんので
今後の課題としてみます。