次に音量エンベロープ(時間的な音量変化)についてです。
Mozziには Ead
というエンベロープ用のクラスが用意されています。(他に”ADSR”エンベロープも用意されています)
32行目の kEnvelope.start(attack,decay)
でアタックとディケイの設定を行っています。
これにより音の立ち上がりと減衰を表現できます。
また、オシレーターに対する音量エンベロープのトリガーを、EventDelay
で実装しています。
Arduinoには delay()
という命令が用意されており、プログラムの定期動作を制御できますが、この delay()
処理はMozziのオーディオ処理とぶつかってしまうので使えません。
コンパイルはできますが、うまく動作しなくなってしまいます。(同様の理由でmillis()
, micros()
, delayMicroseconds()
も使えません)
このため、Mozzi用のスケジューリング(遅延)処理であるEventDelay
が用意されています。
本スケッチはEventDelay
とランダムジェネレータであるmozzi_rand
を用いて、
ランダムなタイミングで音を出力し、音量エンベロープにより減衰処理を行っています。
今回はサイン波のテーブルを用いています。
(サンプルのEnvelope/”Ead_Envelope.ino”(Tim Barrass 2012.)
を参考にしています。)
1#include <MozziGuts.h>
2#include <Oscil.h> //オシレーターのテンプレート
3#include <tables/sin2048_int8.h> // サイン波のテーブル
4#include <Ead.h> // アタック, ディケイのための指数関数
5#include <EventDelay.h> //Arduinoのdelayの代わり
6#include <mozzi_midi.h> //MIDI変換用
7#include <mozzi_rand.h> //ランダム用
8
9#define CONTROL_RATE 256 //コントロールレートの設定
10
11Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA);
12EventDelay kDelay; // 遅延処理によるエンベロープトリガー
13Ead kEnvelope(CONTROL_RATE); //エンベロープ用インスタンス
14
15int gain;
16int pin = 0;
17
18void setup(){
19 randSeed(); // ランダムジェネレータの初期化 (スケッチのループ毎に異なる値を出す)
20 startMozzi(CONTROL_RATE); // Mozziの初期化と処理開始
21 kDelay.start(1000);
22 aSin.setFreq(440); // 周波数を指定
23
24}
25
26void updateControl(){
27
28 if(kDelay.ready()){
29 unsigned int duration = rand(200u) + 200; //duration(音の長さ)をランダムに設定
30 unsigned int attack = rand(75); //アタックをランダムに設定
31 unsigned int decay = duration - attack; //ディケイを設定
32 kEnvelope.start(attack,decay); //エンベロープスタート
33 kDelay.start(duration+500); //トリガー
34 }
35 gain = (int) kEnvelope.next(); //出力用変数に結果を格納
36}
37
38int updateAudio(){
39 return (gain*aSin.next())>>8; // オーディオの繰り返し出力処理 (シフト演算によるゲイン調整)
40
41}
42
43void loop(){
44 audioHook(); // 再生のために必要
45
回路は以下を参考にしてください。