次は和音出力(加算合成)に挑戦です。 少し込み入ってきましたが、記入してあるコメント文を読むと何となくわかってきます。 単純に今まで使ってきたオシレーターを複数用意して(この場合7つ)、今までと同じようにピッチを設定しています。
今回初めて使っているのは、updateAudio()
内のゲイン調整です。
複数のオシレーターを重ねると出力が大きくなってしまいます。
そのため、シフト演算で>>3
をかけてあげることで、1/2^3
、すなわち8で割って出力オーバーを防ぎます。
(サンプルのSynthesis/”Detuned_Beats_Wash.ino”(Tim Barrass 2012.)
を参考にしています。)
1#include <MozziGuts.h>
2#include <Oscil.h> // オシレーターのテンプレート
3#include <tables/cos8192_int8.h> // オシレーター用のコサインテーブル
4#include <mozzi_midi.h> //Pdの[mtof]オブジェクトの代わり
5
6#define CONTROL_RATE 64 // コントロールレートの設定
7
8// harmonics 加算するオシレーターの配列変数COS2048_DATA2048の8bitデータを格納
9Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos1(COS8192_DATA);
10Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos2(COS8192_DATA);
11Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos3(COS8192_DATA);
12Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos4(COS8192_DATA);
13Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos5(COS8192_DATA);
14Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos6(COS8192_DATA);
15Oscil<COS8192_NUM_CELLS, AUDIO_RATE> aCos7(COS8192_DATA);
16
17// ベースとなるピッチの変数を用意
18Q16n16 f1,f2,f3,f4,f5,f6,f7;
19
20float val = 0.f;
21float pitch = 0.f; // 音の高さ (pitch) の変数
22int sensorValue;
23int pin = 0;
24
25void setup(){
26 startMozzi(CONTROL_RATE); // Mozziの初期化と処理開始
27}
28
29void loop(){
30 audioHook(); // 再生のために必要
31}
32
33void updateControl(){ // Mozziの音出力設定はこの領域に書き込む
34
35 sensorValue = mozziAnalogRead(pin); //Mozzi処理のバックグラウンドでセンサ値を読み込む
36 val = map(sensorValue, 0, 1024, 0, 127); //センサの値を0~127にマッピング
37
38 if(val < 128 && val > 0){ // 1~127の値であれば...
39 pitch = val; //pitchに値を格納する
40
41 // センサ値からピッチを決定 (MIDIノートナンバー)
42 f1 = Q16n16_mtof(Q16n0_to_Q16n16(pitch));
43 f2 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+3));
44 f3 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+7));
45 f4 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+10));
46 f5 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+14));
47 f6 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+21));
48 f7 = Q16n16_mtof(Q16n0_to_Q16n16(pitch+24));
49
50 // setFreqに格納
51 aCos1.setFreq_Q16n16(f1);
52 aCos2.setFreq_Q16n16(f2);
53 aCos3.setFreq_Q16n16(f3);
54 aCos4.setFreq_Q16n16(f4);
55 aCos5.setFreq_Q16n16(f5);
56 aCos6.setFreq_Q16n16(f6);
57 aCos7.setFreq_Q16n16(f7);
58 }
59
60 else{ // 1~127以外の値がきた場合は...
61 pitch = 0.f; //pitchを0にしてオシレーターを止める
62 f1 = Q16n16_mtof(Q16n0_to_Q16n16(0));
63 f2 = Q16n16_mtof(Q16n0_to_Q16n16(0));
64 f3 = Q16n16_mtof(Q16n0_to_Q16n16(0));
65 f4 = Q16n16_mtof(Q16n0_to_Q16n16(0));
66 f5 = Q16n16_mtof(Q16n0_to_Q16n16(0));
67 f6 = Q16n16_mtof(Q16n0_to_Q16n16(0));
68 f7 = Q16n16_mtof(Q16n0_to_Q16n16(0));
69
70 aCos1.setFreq_Q16n16(0);
71 aCos2.setFreq_Q16n16(0);
72 aCos3.setFreq_Q16n16(0);
73 aCos4.setFreq_Q16n16(0);
74 aCos5.setFreq_Q16n16(0);
75 aCos6.setFreq_Q16n16(0);
76 aCos7.setFreq_Q16n16(0);
77 }
78}
79
80int updateAudio(){
81 // オーディオの繰り返し出力処理
82 int asig =
83 aCos1.next() + aCos2.next() +
84 aCos3.next() + aCos4.next() +
85 aCos5.next() + aCos6.next() +
86 aCos7.next() ;
87
88 return asig >> 3; ///それぞれの出力オーバーを防ぐために>>3
89}
回路は第4回の可変抵抗のものを流用してください。