#include #include #define GRAIN_FREQ_CONTROL (0) // #define GRAIN_DECAY_CONTROL (2) // #define GRAIN2_FREQ_CONTROL (3) // #define GRAIN2_DECAY_CONTROL (1) // #define PWM_PIN 3 #define PWM_VALUE OCR2B #define PWM_INTERRUPT TIMER2_OVF_vect #define keyCPin 12 #define keyDPin 11 #define keyEPin 10 #define keyFPin 9 #define keyGPin 8 #define keyAPin 7 #define keyBPin 6 #define keyOctaveUpPin 5 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; int octup = 0; int keyName = 0; uint16_t mapkeyTable[] = { // Caution: 1st actual data is 17, but 0 for note off data here. // C C# D D# E F F# G G# A A# B 0, 18, 19, 20, 22, 23, 24, 26, 27, 29, 31, 32, //0 34, 36, 38, 41, 43, 46, 48, 51, 54, 58, 61, 65, //12 69, 73, 77, 82, 86, 92, 97, 103, 109, 115, 122, 129, //24 137, 145, 154, 163, 173, 183, 194, 206, 218, 231, 244, 259, //36 274, 291, 308, 326, 346, 366, 388, 411, 435, 461, 489, 518, //48 549, 581, 616, 652, 691, 732, 776, 822, 871, 923, 978, 1036, //60 1097, 1163, 1232, 1305, 1383, 1465, 1552, 1644, 1742, 1845, 1955, 2071, //72 2195, 2325, 2463, 2610, 2765, 2930, 3104, 3288, 3484, 3691, 3910, 4143, //84 4389, 4650, 4927, 5220, 5530, 5859, 6207, 6577, 6968, 7382, 7821, 8286, //96 8779, 9301, 9854,10440,11060,11718,12415,13153,13935,14764,15642,16572, //108 17557,18601,19708,20879,22121,23436,24830,26306 }; // 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() { TCCR2A = _BV(COM2B1) | _BV(WGM20); TCCR2B = _BV(CS20); TIMSK2 = _BV(TOIE2); } void setup() { pinMode(PWM_PIN,OUTPUT); audioOn(); pinMode(keyCPin,INPUT); pinMode(keyDPin,INPUT); pinMode(keyEPin,INPUT); pinMode(keyFPin,INPUT); pinMode(keyGPin,INPUT); pinMode(keyAPin,INPUT); pinMode(keyBPin,INPUT); pinMode(keyOctaveUpPin,INPUT); } void loop() { if (digitalRead(keyOctaveUpPin) == HIGH) { octup = 12; }else { octup = 0; } if (digitalRead(keyCPin) == HIGH) { syncPhaseInc = mapkeyTable[60 + (octup)]; keyName = 1; }else if (digitalRead(keyDPin) == HIGH) { syncPhaseInc = mapkeyTable[62 + (octup)]; keyName = 2; }else if (digitalRead(keyEPin) == HIGH) { syncPhaseInc = mapkeyTable[64 + (octup)]; keyName = 3; }else if (digitalRead(keyFPin) == HIGH) { syncPhaseInc = mapkeyTable[65 + (octup)]; keyName = 4; }else if (digitalRead(keyGPin) == HIGH) { syncPhaseInc = mapkeyTable[67 + (octup)]; keyName = 5; }else if (digitalRead(keyAPin) == HIGH) { syncPhaseInc = mapkeyTable[69 + (octup)]; keyName = 6; }else if (digitalRead(keyBPin) == HIGH) { syncPhaseInc = mapkeyTable[71 + (octup)]; keyName = 7; } else { keyName = 0; } 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) { if (keyName == 0) return ; uint8_t value; uint16_t output; syncPhaseAcc += syncPhaseInc; if (syncPhaseAcc < syncPhaseInc) { // 次のグレインがスタートする時間 grainPhaseAcc = 0; grainAmp = 0x7fff; grain2PhaseAcc = 0; grain2Amp = 0x7fff; } // グレインオシレータの位相を進める 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; }