EG波形の出力にはArduinoのanalogOutを使おう思ったが、PWMの周波数が500Hz~1kHz程度みたいなのでEGとして使うにもムリそう。
自力でAVRのPWMを制御するのもめんどくさいので、SPI DACのMCP4922を使った。
ブレッドボード図
↑他のSPIデバイスも使う予定なので、図ではMCP4922のLDAC(8pin)はArduinoのD2に接続していますが、今回の実験ではD9に接続しています。
入力デバイスには久しぶりにPOT3個とタクトスイッチ2個のぴゅんぴゅんコントローラー1号を使ってみた。
POTは左から
Duration: 音符の長さに割り当てている。
Decay: 減衰時間
Sustain: 減衰後の出力レベル
タクトスイッチは今回は未使用。
普通のシンセだとEGはADSRにするところだが、ベースマシンを想定しているのでAtackとReleaseは端折った。
出力波形
Arduinoのスケッチ
#include <SPI.h> #include <MsTimer2.h> #define MOD_RATE 1 // ms #define PIN_LDAC 9 // MCP4922のラッチ動作出力ピン #define PIN_DURATION A0 #define PIN_DECAY A1 #define PIN_SUSTAIN A2 int16_t beatLen = 500; int16_t level = 4095; int16_t duration = 400; int16_t decay = 100; int16_t sustain = 2000; int16_t decay_delta; int16_t mod_value; int16_t tick; // DACに出力 // parameter: v: 出力値(0 .. 4095) void outDAC(int16_t v) { digitalWrite(PIN_LDAC, HIGH) ; digitalWrite(SS, LOW) ; SPI.transfer((v >> 8)| 0x30) ; SPI.transfer(v & 0xff) ; digitalWrite(SS, HIGH) ; digitalWrite(PIN_LDAC, LOW) ; } void outADSR() { tick++; if (tick > beatLen) { tick = 0; // モジュレーション波形を初期化する mod_value = level; decay_delta = (level - sustain) / decay; } // 出力値補正 if (mod_value < 0) { mod_value = 0; } outDAC(mod_value); if (tick < decay) { mod_value -= decay_delta; } if (tick == duration) { mod_value = 0; } } void setup() { Serial.begin(9600); // DAC出力の初期化 pinMode(PIN_LDAC, OUTPUT); SPI.begin(); SPI.setBitOrder(MSBFIRST); // ビットオーダー SPI.setClockDivider(SPI_CLOCK_DIV8); // クロック(CLK)をシステムクロックの1/8で使用(16MHz/8) SPI.setDataMode(SPI_MODE0) ; // クロック極性0(LOW) クロック位相0 // Timerの初期化 MsTimer2::set(MOD_RATE, outADSR); MsTimer2::start(); } void loop() { duration = map(analogRead(PIN_DURATION), 0, 1023, 0, beatLen); decay = map(analogRead(PIN_DECAY), 0, 1023, 0, beatLen); sustain = analogRead(PIN_SUSTAIN) << 2; Serial.print(duration); Serial.print("\t"); Serial.print(decay); Serial.print("\t"); Serial.print(sustain); Serial.print("\n"); }
0 件のコメント:
コメントを投稿