音響合成ライブラリMozziスライドPDFArduino単体で音響合成を行うMozziとは?何故こんなことができるのかインストールArduinoから線を出すサインウェーブを鳴らすOscilオブジェクトupdateControlでパラメータを変更する足して和音を作ってみる電子工作創作表現(2019/10/18)スライドPDFArduino単体で音響合成を行うArduino単体の機能で作れる音には限界がある「Mozzi」を使うとかなり幅が広がる今週から、何度かにわたって音響合成ライブラリのMozziを解説していこうと思います。以前Arduinoに圧電素子をつないで簡単な音を出してみるのをやってみましたが、Arduinoの基本ライブラリだけだとああいったビープ音を出すのが関の山という感じです。そこでもっと幅広い表現ができるようにと作られたのがこの「Mozzi」です。Mozziとは?タイマー機能を活用した音響合成ライブラリオシレータ・エンベロープ・LPFなどMozziは、ArduinoでPWMに使われるタイマー機能を使って実現された音響合成ライブラリです。オシレータやエンベロープなど、ベーシックなシンセサイズをするための機能が備わっています。https://sensorium.github.io/Mozzi/に情報がまとめられています。高速な音響処理を必要とする中の仕組みを少しだけ話すと、PWMに使われているマイコンのタイマー機能を使い、ハイとローの切り替えを物凄く細かく切り替えていくことで実現しています。ハイレゾ音源等で使われる「DSD」という技術が近いそうです。音響合成は常に出力を変化させ続けなくてはならないので、通常のanalogReadやanalogWriteの一部、またdelay関数などArduinoの主要な機能が一部使えなくなります。詳しくは後ほど解説しますが、楽器として音を出しながらNeoPixelをコントロールする、といったことは難しくなります。はじめのうちは、Mozziを使用するArduinoは音響のみに用途を絞るのがおススメです。インストールhttps://sensorium.github.io/Mozzi/download/ZipをダウンロードしてインストールMozziはライブラリマネージャに登録されていないので、「ライブラリのZIPファイルをダウンロードした後、スケッチ>ライブラリをインクルード>.ZIP形式のライブラリをインストール」からインストールをする必要があります。インストールができたら、ファイル>スケッチ例にMozziが追加されるので、ここからサンプルファイルを開くことができるようになります。Arduinoから線を出す9番ピンとGNDにオーディオ出力を付ける(モノラル)PWMとして使いたいピンは3か11を使うハードウェア側について。Mozziでは9番ピンから音声出力が出るので、オーディオの端子は9番ピンとGNDに接続する必要があります。サンプル基板はイヤホン等で試せるよう3.5ミリのステレオジャックを使っていますが、RCA端子でも良いと思います。基板取付用端子はピン配置が特殊な形状をしていることが多いので、DIP化キットと呼ばれるものを使えばユニバーサル基板にもはんだ付けして使うことができます。(例:http://akizukidenshi.com/catalog/g/gK-06204/)サインウェーブを鳴らすオシレータOscilでサイン波を鳴らすsetup/loopに加えてupdateControl()とupdateAudio()が増えるまずは01.Basics>SineWaveのスケッチから、Mozziの基本構造を読み解いていきます。サンプルからコメントを省いたソースコードを以下に記載します。Mozziで音を出すには、setupでstartMozziを呼び、loop内でaudioHookを呼ぶようにします。updateAudioはオーディオ出力を決定する関数なので、ここは必要最低限の計算を書くようにします。updateControlはボリュームやボタンのコントロール等の入力を反映させるためのコードを記述します。audioHook();}Oscilオブジェクトオシレータを作るためのクラス。サイン波や矩形波のような波形データを用意するtablesフォルダに様々な波形のテーブルが用意されているこのコードで最も重要なのが、出す音の波形を決めるオシレータです。このクラスに出したい波形のデータを格納して、周波数を設定した後updateAudio内で呼び出すことで様々な音を発します。サンプルコードでは、2048バッファのサイン波を入れて、setupで440ヘルツに設定しています。next関数を呼ぶごとに次の位相へと進んでいくので、updateAudioでnextを呼び続けることによってサイン波が出力され、440Hzの音がなるという仕組みです。この波形データはtablesフォルダの中にたくさん定義されていて、使うことができますし、ここのフォーマットにならえば自分で作ることも可能です。2048や512のような数字はバッファサイズで、データの細かさなのでこの数値が大きいほど音の解像度は高くなります。プログラム領域のメモリを多く消費するようになるので、この辺りはコンパイル時に使用量を確認しながら使うバッファサイズを決めるようにする必要があります。//ピンクノイズupdateControlでパラメータを変更するアナログ入力はmozziAnalogRead()を使うupdateControlが呼ばれる頻度はstartMozziのCONTROL_RATEで決定このままではただ音が流れるだけなので、インタラクティブ性を持たせてみます。ボリューム抵抗の値を持ってくるにはanalogRead()関数を使っていましたが、Mozziでは音響処理を邪魔しないmozziAnalogReadという関数が別で用意されています。使い方はanalogReadと全く同じで、0番ピンから取得してきたアナログ入力の値を、setFreqでそのまま周波数としてつかいます。アナログ値は0~1023なので、1000hzまでのサイン波をグリグリと変化させることができます。このupdateControlはupdateAudioよりも少ない頻度で呼ばれて、ソースコード頭にあるCONTROL_RATEで周波数が決定します。64hzか128hzくらいあれば十分でしょう。周波数は2の累乗を指定します。243の間でクリップする単音のサイン波では味気ないですが、コントロールしながらオシレータを合成することもできます。オシレータを二つ、ここではaSinとbSinを用意してnextの値を足せば2つのサイン波が合成されます。updateAudioのreturnに入れる値はSTANDARDモードで-244~243の間にしなくてはならず、その範囲を超える値を入れるとバッファオーバーフローが起きてグリッチ音が鳴りだします。サイン波の範囲は先ほどのテーブルを見ると-127~127なので、二つが重なると最大254まで行く可能性があります。コンプレッサーのようなエフェクターがあれば収まるように叩けますが、そうもいかないのでここではザックリ4で割って音が割れないようにおさめています。