Kaoru Shoji
/
granularsynth
Auduino port
auduino.cpp@1:a553c5d93bb8, 2010-09-15 (annotated)
- Committer:
- kshoji
- Date:
- Wed Sep 15 00:20:19 2010 +0000
- Revision:
- 1:a553c5d93bb8
- Parent:
- 0:831ef5c249ef
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kshoji | 0:831ef5c249ef | 1 | #include <math.h> |
kshoji | 0:831ef5c249ef | 2 | #include "mbed.h" |
kshoji | 0:831ef5c249ef | 3 | |
kshoji | 1:a553c5d93bb8 | 4 | #define FEATURE_ORIGINAL_AUDUINO |
kshoji | 1:a553c5d93bb8 | 5 | |
kshoji | 0:831ef5c249ef | 6 | // Auduino for mbed |
kshoji | 0:831ef5c249ef | 7 | // Ported and arranged by Kaoru Shoji |
kshoji | 0:831ef5c249ef | 8 | |
kshoji | 0:831ef5c249ef | 9 | // Original source code: |
kshoji | 0:831ef5c249ef | 10 | // Auduino, the Lo-Fi granular synthesiser |
kshoji | 0:831ef5c249ef | 11 | // |
kshoji | 0:831ef5c249ef | 12 | // by Peter Knight, Tinker.it http://tinker.it |
kshoji | 0:831ef5c249ef | 13 | // |
kshoji | 0:831ef5c249ef | 14 | // Help: http://code.google.com/p/tinkerit/wiki/Auduino |
kshoji | 0:831ef5c249ef | 15 | // More help: http://groups.google.com/group/auduino |
kshoji | 0:831ef5c249ef | 16 | // |
kshoji | 0:831ef5c249ef | 17 | // Changelog: |
kshoji | 0:831ef5c249ef | 18 | // 19 Nov 2008: Added support for ATmega8 boards |
kshoji | 0:831ef5c249ef | 19 | // 21 Mar 2009: Added support for ATmega328 boards |
kshoji | 0:831ef5c249ef | 20 | // 7 Apr 2009: Fixed interrupt vector for ATmega328 boards |
kshoji | 0:831ef5c249ef | 21 | // 8 Apr 2009: Added support for ATmega1280 boards (Arduino Mega) |
kshoji | 0:831ef5c249ef | 22 | |
kshoji | 0:831ef5c249ef | 23 | // Analog in p16: Grain 1 pitch |
kshoji | 0:831ef5c249ef | 24 | // Analog in p17: Grain 1 decay |
kshoji | 0:831ef5c249ef | 25 | // Analog in p19: Grain 2 pitch |
kshoji | 0:831ef5c249ef | 26 | // Analog in p20: Grain 2 decay |
kshoji | 0:831ef5c249ef | 27 | // Analog in p15: Grain repetition frequency |
kshoji | 0:831ef5c249ef | 28 | // Analog out p18: Audio out |
kshoji | 0:831ef5c249ef | 29 | |
kshoji | 0:831ef5c249ef | 30 | Ticker interrupt; |
kshoji | 0:831ef5c249ef | 31 | AnalogIn SYNC_CONTROL(p15); |
kshoji | 0:831ef5c249ef | 32 | AnalogIn GRAIN_FREQ_CONTROL(p16); |
kshoji | 0:831ef5c249ef | 33 | AnalogIn GRAIN_DECAY_CONTROL(p17); |
kshoji | 0:831ef5c249ef | 34 | AnalogIn GRAIN2_FREQ_CONTROL(p19); |
kshoji | 0:831ef5c249ef | 35 | AnalogIn GRAIN2_DECAY_CONTROL(p20); |
kshoji | 0:831ef5c249ef | 36 | AnalogOut OUTPUT(p18); |
kshoji | 0:831ef5c249ef | 37 | DigitalOut LED_PIN(LED1); |
kshoji | 0:831ef5c249ef | 38 | |
kshoji | 0:831ef5c249ef | 39 | float syncPhaseAcc; |
kshoji | 0:831ef5c249ef | 40 | float syncPhaseInc; |
kshoji | 0:831ef5c249ef | 41 | |
kshoji | 0:831ef5c249ef | 42 | float grainPhaseAcc; |
kshoji | 0:831ef5c249ef | 43 | float grainPhaseInc; |
kshoji | 0:831ef5c249ef | 44 | float grainAmp; |
kshoji | 0:831ef5c249ef | 45 | float grainDecay; |
kshoji | 0:831ef5c249ef | 46 | |
kshoji | 0:831ef5c249ef | 47 | float grain2PhaseAcc; |
kshoji | 0:831ef5c249ef | 48 | float grain2PhaseInc; |
kshoji | 0:831ef5c249ef | 49 | float grain2Amp; |
kshoji | 0:831ef5c249ef | 50 | float grain2Decay; |
kshoji | 0:831ef5c249ef | 51 | |
kshoji | 0:831ef5c249ef | 52 | // Smooth logarithmic mapping |
kshoji | 0:831ef5c249ef | 53 | // |
kshoji | 0:831ef5c249ef | 54 | float mapPhaseInc(double input) { |
kshoji | 0:831ef5c249ef | 55 | return pow(65536.0, 1.0 - input); |
kshoji | 0:831ef5c249ef | 56 | } |
kshoji | 0:831ef5c249ef | 57 | |
kshoji | 0:831ef5c249ef | 58 | // Stepped chromatic mapping |
kshoji | 0:831ef5c249ef | 59 | // |
kshoji | 0:831ef5c249ef | 60 | uint16_t midiTable[] = { |
kshoji | 0:831ef5c249ef | 61 | 17,18,19,20,22,23,24,26,27,29,31,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73, |
kshoji | 0:831ef5c249ef | 62 | 77,82,86,92,97,103,109,115,122,129,137,145,154,163,173,183,194,206,218,231, |
kshoji | 0:831ef5c249ef | 63 | 244,259,274,291,308,326,346,366,388,411,435,461,489,518,549,581,616,652,691, |
kshoji | 0:831ef5c249ef | 64 | 732,776,822,871,923,978,1036,1097,1163,1232,1305,1383,1465,1552,1644,1742, |
kshoji | 0:831ef5c249ef | 65 | 1845,1955,2071,2195,2325,2463,2610,2765,2930,3104,3288,3484,3691,3910,4143, |
kshoji | 0:831ef5c249ef | 66 | 4389,4650,4927,5220,5530,5859,6207,6577,6968,7382,7821,8286,8779,9301,9854, |
kshoji | 0:831ef5c249ef | 67 | 10440,11060,11718,12415,13153,13935,14764,15642,16572,17557,18601,19708,20879, |
kshoji | 0:831ef5c249ef | 68 | 22121,23436,24830,26306 |
kshoji | 0:831ef5c249ef | 69 | }; |
kshoji | 0:831ef5c249ef | 70 | uint16_t mapMidi(float input) { |
kshoji | 0:831ef5c249ef | 71 | return midiTable[(int)(127.9 - input * 127.9)]; |
kshoji | 0:831ef5c249ef | 72 | } |
kshoji | 0:831ef5c249ef | 73 | |
kshoji | 0:831ef5c249ef | 74 | // Stepped Pentatonic mapping |
kshoji | 0:831ef5c249ef | 75 | // |
kshoji | 0:831ef5c249ef | 76 | uint16_t pentatonicTable[54] = { |
kshoji | 0:831ef5c249ef | 77 | 0,19,22,26,29,32,38,43,51,58,65,77,86,103,115,129,154,173,206,231,259,308,346, |
kshoji | 0:831ef5c249ef | 78 | 411,461,518,616,691,822,923,1036,1232,1383,1644,1845,2071,2463,2765,3288, |
kshoji | 0:831ef5c249ef | 79 | 3691,4143,4927,5530,6577,7382,8286,9854,11060,13153,14764,16572,19708,22121,26306 |
kshoji | 0:831ef5c249ef | 80 | }; |
kshoji | 0:831ef5c249ef | 81 | |
kshoji | 0:831ef5c249ef | 82 | uint16_t mapPentatonic(float input) { |
kshoji | 0:831ef5c249ef | 83 | uint8_t value = ((int)(1023.9 - input * 1023.9)) / (1024/53); |
kshoji | 0:831ef5c249ef | 84 | return pentatonicTable[value]; |
kshoji | 0:831ef5c249ef | 85 | } |
kshoji | 0:831ef5c249ef | 86 | |
kshoji | 0:831ef5c249ef | 87 | void updateLatestInputValue() { |
kshoji | 0:831ef5c249ef | 88 | // The loop is pretty simple - it just updates the parameters for the oscillators. |
kshoji | 0:831ef5c249ef | 89 | // |
kshoji | 0:831ef5c249ef | 90 | // Avoid using any functions that make extensive use of interrupts, or turn interrupts off. |
kshoji | 0:831ef5c249ef | 91 | // They will cause clicks and poops in the audio. |
kshoji | 0:831ef5c249ef | 92 | |
kshoji | 1:a553c5d93bb8 | 93 | #ifndef FEATURE_ORIGINAL_AUDUINO |
kshoji | 0:831ef5c249ef | 94 | // Smooth frequency mapping |
kshoji | 0:831ef5c249ef | 95 | syncPhaseInc = mapPhaseInc(SYNC_CONTROL) * 4.0; |
kshoji | 1:a553c5d93bb8 | 96 | #endif |
kshoji | 0:831ef5c249ef | 97 | |
kshoji | 0:831ef5c249ef | 98 | // Stepped mapping to MIDI notes: C, Db, D, Eb, E, F... |
kshoji | 0:831ef5c249ef | 99 | //syncPhaseInc = mapMidi(SYNC_CONTROL); |
kshoji | 0:831ef5c249ef | 100 | |
kshoji | 1:a553c5d93bb8 | 101 | #ifdef FEATURE_ORIGINAL_AUDUINO |
kshoji | 0:831ef5c249ef | 102 | // Stepped pentatonic mapping: D, E, G, A, B |
kshoji | 1:a553c5d93bb8 | 103 | syncPhaseInc = mapPentatonic(SYNC_CONTROL); |
kshoji | 0:831ef5c249ef | 104 | |
kshoji | 1:a553c5d93bb8 | 105 | grainPhaseInc = mapPhaseInc(GRAIN_FREQ_CONTROL) * 2.0; |
kshoji | 1:a553c5d93bb8 | 106 | grainDecay = GRAIN_DECAY_CONTROL * 128.0; |
kshoji | 1:a553c5d93bb8 | 107 | grain2PhaseInc = mapPhaseInc(GRAIN2_FREQ_CONTROL) * 2.0; |
kshoji | 1:a553c5d93bb8 | 108 | grain2Decay = GRAIN2_DECAY_CONTROL * 256.0; |
kshoji | 1:a553c5d93bb8 | 109 | #else |
kshoji | 0:831ef5c249ef | 110 | grainPhaseInc = mapPhaseInc(GRAIN_FREQ_CONTROL) * 4.0; |
kshoji | 0:831ef5c249ef | 111 | grainDecay = GRAIN_DECAY_CONTROL * 16.0; |
kshoji | 0:831ef5c249ef | 112 | grain2PhaseInc = mapPhaseInc(GRAIN2_FREQ_CONTROL) * 4.0; |
kshoji | 0:831ef5c249ef | 113 | grain2Decay = GRAIN2_DECAY_CONTROL * 32.0; |
kshoji | 1:a553c5d93bb8 | 114 | #endif |
kshoji | 0:831ef5c249ef | 115 | } |
kshoji | 0:831ef5c249ef | 116 | |
kshoji | 0:831ef5c249ef | 117 | float adjustPhaseValue(float phaseAcc) { |
kshoji | 0:831ef5c249ef | 118 | float value = phaseAcc / 128.0; |
kshoji | 0:831ef5c249ef | 119 | value = ((value / 256.0) - (int)(value / 256.0)) * 256.0; |
kshoji | 0:831ef5c249ef | 120 | if (value > 256) value = 256; |
kshoji | 0:831ef5c249ef | 121 | if (phaseAcc > 32768) value = 256 - value; |
kshoji | 0:831ef5c249ef | 122 | return value; |
kshoji | 0:831ef5c249ef | 123 | } |
kshoji | 0:831ef5c249ef | 124 | |
kshoji | 0:831ef5c249ef | 125 | void interruptHandler() { |
kshoji | 0:831ef5c249ef | 126 | float value; |
kshoji | 0:831ef5c249ef | 127 | float output; |
kshoji | 0:831ef5c249ef | 128 | |
kshoji | 0:831ef5c249ef | 129 | updateLatestInputValue(); |
kshoji | 0:831ef5c249ef | 130 | |
kshoji | 0:831ef5c249ef | 131 | syncPhaseAcc += syncPhaseInc; |
kshoji | 0:831ef5c249ef | 132 | if (syncPhaseAcc > 65536.0) { |
kshoji | 0:831ef5c249ef | 133 | syncPhaseAcc -= 65536.0; |
kshoji | 0:831ef5c249ef | 134 | } |
kshoji | 0:831ef5c249ef | 135 | if (syncPhaseAcc < syncPhaseInc) { |
kshoji | 0:831ef5c249ef | 136 | // Time to start the next grain |
kshoji | 0:831ef5c249ef | 137 | grainPhaseAcc = 0; |
kshoji | 0:831ef5c249ef | 138 | grainAmp = 32768.0; |
kshoji | 0:831ef5c249ef | 139 | grain2PhaseAcc = 0; |
kshoji | 0:831ef5c249ef | 140 | grain2Amp = 32768.0; |
kshoji | 0:831ef5c249ef | 141 | LED_PIN = !LED_PIN; |
kshoji | 0:831ef5c249ef | 142 | } |
kshoji | 0:831ef5c249ef | 143 | |
kshoji | 0:831ef5c249ef | 144 | // Increment the phase of the grain oscillators |
kshoji | 0:831ef5c249ef | 145 | grainPhaseAcc += grainPhaseInc; |
kshoji | 0:831ef5c249ef | 146 | grain2PhaseAcc += grain2PhaseInc; |
kshoji | 0:831ef5c249ef | 147 | if (grainPhaseAcc > 65536) grainPhaseAcc -= 65536; |
kshoji | 0:831ef5c249ef | 148 | if (grain2PhaseAcc > 65536) grain2PhaseAcc -= 65536; |
kshoji | 0:831ef5c249ef | 149 | |
kshoji | 0:831ef5c249ef | 150 | // Convert phase into a triangle wave |
kshoji | 0:831ef5c249ef | 151 | value = adjustPhaseValue(grainPhaseAcc); |
kshoji | 0:831ef5c249ef | 152 | // Multiply by current grain amplitude to get sample |
kshoji | 0:831ef5c249ef | 153 | output = value * (grainAmp / 512.0); |
kshoji | 0:831ef5c249ef | 154 | |
kshoji | 0:831ef5c249ef | 155 | // Repeat for second grain |
kshoji | 0:831ef5c249ef | 156 | value = adjustPhaseValue(grain2PhaseAcc); |
kshoji | 0:831ef5c249ef | 157 | output += value * (grain2Amp / 512.0); |
kshoji | 0:831ef5c249ef | 158 | |
kshoji | 0:831ef5c249ef | 159 | // Make the grain amplitudes decay by a factor every sample (exponential decay) |
kshoji | 0:831ef5c249ef | 160 | grainAmp -= (grainAmp / 256.0) * grainDecay; |
kshoji | 0:831ef5c249ef | 161 | grain2Amp -= (grain2Amp / 256.0) * grain2Decay; |
kshoji | 0:831ef5c249ef | 162 | |
kshoji | 0:831ef5c249ef | 163 | OUTPUT.write_u16(output); |
kshoji | 0:831ef5c249ef | 164 | } |
kshoji | 0:831ef5c249ef | 165 | |
kshoji | 0:831ef5c249ef | 166 | int main() { |
kshoji | 0:831ef5c249ef | 167 | interrupt.attach_us(&interruptHandler, 32); |
kshoji | 0:831ef5c249ef | 168 | } |