// Auduino, the Lo-Fi granular synthesiser // by Peter Knight, Tinker.it http://tinker.it // http://code.google.com/p/tinkerit/ // Code license: GNU LGPL // Content license: CC3.0 BY-SA // 日本語コメント: 武蔵野電波 #include #include // アナログ入力ピン #define SYNC_CONTROL (4) // ピン4: グレイン繰り返し周波数 #define GRAIN_FREQ_CONTROL (0) // ピン0: グレイン1 ピッチ #define GRAIN_DECAY_CONTROL (2) // ピン2: グレイン1 ディケイ #define GRAIN2_FREQ_CONTROL (3) // ピン3: グレイン2 ピッチ #define GRAIN2_DECAY_CONTROL (1) // ピン1: グレイン2 ディケイ // オーディオ出力=デジタルピン3 #define PWM_PIN 3 #define PWM_VALUE OCR2B #define LED_PIN 13 #define LED_PORT PORTB #define LED_BIT 5 #define PWM_INTERRUPT TIMER2_OVF_vect uint16_t syncPhaseAcc; uint16_t syncPhaseInc; uint16_t grainPhaseAcc; uint16_t grainPhaseInc; uint16_t grainAmp; uint8_t grainDecay; uint16_t grain2PhaseAcc; uint16_t grain2PhaseInc; uint16_t grain2Amp; uint8_t grain2Decay; // マッピング(ペンタトニック) uint16_t pentatonicTable[54] = { 0,19,22,26,29,32,38,43,51,58,65,77,86,103,115,129,154,173,206,231,259,308,346, 411,461,518,616,691,822,923,1036,1232,1383,1644,1845,2071,2463,2765,3288, 3691,4143,4927,5530,6577,7382,8286,9854,11060,13153,14764,16572,19708,22121,26306 }; uint16_t mapPentatonic(uint16_t input) { uint8_t value = (1023-input) / (1024/53); return (pentatonicTable[value]); } // 対数マッピング uint16_t antilogTable[] = { 64830,64132,63441,62757,62081,61413,60751,60097,59449,58809,58176,57549,56929,56316,55709,55109, 54515,53928,53347,52773,52204,51642,51085,50535,49991,49452,48920,48393,47871,47356,46846,46341, 45842,45348,44859,44376,43898,43425,42958,42495,42037,41584,41136,40693,40255,39821,39392,38968, 38548,38133,37722,37316,36914,36516,36123,35734,35349,34968,34591,34219,33850,33486,33125,32768 }; uint16_t mapPhaseInc(uint16_t input) { return (antilogTable[input & 0x3f]) >> (input >> 6); } void audioOn() { // PWMを31.25kHzに設定(正確な位相) TCCR2A = _BV(COM2B1) | _BV(WGM20); TCCR2B = _BV(CS20); TIMSK2 = _BV(TOIE2); } void setup() { pinMode(PWM_PIN,OUTPUT); audioOn(); pinMode(LED_PIN,OUTPUT); } void loop() { // loopはとてもシンプルです - オシレータの変数を更新しているだけです // ペンタトニック・マッピングを使用: D, E, G, A, B syncPhaseInc = mapPentatonic(analogRead(SYNC_CONTROL)); grainPhaseInc = mapPhaseInc(analogRead(GRAIN_FREQ_CONTROL)) / 2; grainDecay = analogRead(GRAIN_DECAY_CONTROL) / 8; grain2PhaseInc = mapPhaseInc(analogRead(GRAIN2_FREQ_CONTROL)) / 2; grain2Decay = analogRead(GRAIN2_DECAY_CONTROL) / 4; } SIGNAL(PWM_INTERRUPT) { uint8_t value; uint16_t output; syncPhaseAcc += syncPhaseInc; if (syncPhaseAcc < syncPhaseInc) { // 次のグレインがスタートする時間 grainPhaseAcc = 0; grainAmp = 0x7fff; grain2PhaseAcc = 0; grain2Amp = 0x7fff; LED_PORT ^= 1 << LED_BIT; // digitalWriteより高速 } // グレインオシレータの位相を進める grainPhaseAcc += grainPhaseInc; grain2PhaseAcc += grain2PhaseInc; // 位相を三角波に変換 value = (grainPhaseAcc >> 7) & 0xff; if (grainPhaseAcc & 0x8000) value = ~value; // 現在のグレイン振幅を掛けてサンプルを取得 output = value * (grainAmp >> 8); // 2つ目のグレイン value = (grain2PhaseAcc >> 7) & 0xff; if (grain2PhaseAcc & 0x8000) value = ~value; output += value * (grain2Amp >> 8); // グレイン振幅にディケイを反映させる(指数関数的ディケイ) grainAmp -= (grainAmp >> 8) * grainDecay; grain2Amp -= (grain2Amp >> 8) * grain2Decay; // 出力をスケーリング(必要ならクリッピング) output >>= 9; if (output > 255) output = 255; // PWMに出力 (analogWriteよりも高速) PWM_VALUE = output; }