Kaoru Shoji
/
granularsynth
Auduino port
Diff: auduino.cpp
- Revision:
- 0:831ef5c249ef
- Child:
- 1:a553c5d93bb8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auduino.cpp Mon Sep 13 12:25:27 2010 +0000 @@ -0,0 +1,157 @@ +#include <math.h> +#include "mbed.h" + +// Auduino for mbed +// Ported and arranged by Kaoru Shoji + +// Original source code: +// Auduino, the Lo-Fi granular synthesiser +// +// by Peter Knight, Tinker.it http://tinker.it +// +// Help: http://code.google.com/p/tinkerit/wiki/Auduino +// More help: http://groups.google.com/group/auduino +// +// Changelog: +// 19 Nov 2008: Added support for ATmega8 boards +// 21 Mar 2009: Added support for ATmega328 boards +// 7 Apr 2009: Fixed interrupt vector for ATmega328 boards +// 8 Apr 2009: Added support for ATmega1280 boards (Arduino Mega) + +// Analog in p16: Grain 1 pitch +// Analog in p17: Grain 1 decay +// Analog in p19: Grain 2 pitch +// Analog in p20: Grain 2 decay +// Analog in p15: Grain repetition frequency +// Analog out p18: Audio out + +Ticker interrupt; +AnalogIn SYNC_CONTROL(p15); +AnalogIn GRAIN_FREQ_CONTROL(p16); +AnalogIn GRAIN_DECAY_CONTROL(p17); +AnalogIn GRAIN2_FREQ_CONTROL(p19); +AnalogIn GRAIN2_DECAY_CONTROL(p20); +AnalogOut OUTPUT(p18); +DigitalOut LED_PIN(LED1); + +float syncPhaseAcc; +float syncPhaseInc; + +float grainPhaseAcc; +float grainPhaseInc; +float grainAmp; +float grainDecay; + +float grain2PhaseAcc; +float grain2PhaseInc; +float grain2Amp; +float grain2Decay; + +// Smooth logarithmic mapping +// +float mapPhaseInc(double input) { + return pow(65536.0, 1.0 - input); +} + +// Stepped chromatic mapping +// +uint16_t midiTable[] = { + 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, + 77,82,86,92,97,103,109,115,122,129,137,145,154,163,173,183,194,206,218,231, + 244,259,274,291,308,326,346,366,388,411,435,461,489,518,549,581,616,652,691, + 732,776,822,871,923,978,1036,1097,1163,1232,1305,1383,1465,1552,1644,1742, + 1845,1955,2071,2195,2325,2463,2610,2765,2930,3104,3288,3484,3691,3910,4143, + 4389,4650,4927,5220,5530,5859,6207,6577,6968,7382,7821,8286,8779,9301,9854, + 10440,11060,11718,12415,13153,13935,14764,15642,16572,17557,18601,19708,20879, + 22121,23436,24830,26306 +}; +uint16_t mapMidi(float input) { + return midiTable[(int)(127.9 - input * 127.9)]; +} + +// Stepped Pentatonic mapping +// +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(float input) { + uint8_t value = ((int)(1023.9 - input * 1023.9)) / (1024/53); + return pentatonicTable[value]; +} + +void updateLatestInputValue() { + // The loop is pretty simple - it just updates the parameters for the oscillators. + // + // Avoid using any functions that make extensive use of interrupts, or turn interrupts off. + // They will cause clicks and poops in the audio. + + // Smooth frequency mapping + syncPhaseInc = mapPhaseInc(SYNC_CONTROL) * 4.0; + + // Stepped mapping to MIDI notes: C, Db, D, Eb, E, F... + //syncPhaseInc = mapMidi(SYNC_CONTROL); + + // Stepped pentatonic mapping: D, E, G, A, B + //syncPhaseInc = mapPentatonic(SYNC_CONTROL); + + grainPhaseInc = mapPhaseInc(GRAIN_FREQ_CONTROL) * 4.0; + grainDecay = GRAIN_DECAY_CONTROL * 16.0; + grain2PhaseInc = mapPhaseInc(GRAIN2_FREQ_CONTROL) * 4.0; + grain2Decay = GRAIN2_DECAY_CONTROL * 32.0; +} + +float adjustPhaseValue(float phaseAcc) { + float value = phaseAcc / 128.0; + value = ((value / 256.0) - (int)(value / 256.0)) * 256.0; + if (value > 256) value = 256; + if (phaseAcc > 32768) value = 256 - value; + return value; +} + +void interruptHandler() { + float value; + float output; + + updateLatestInputValue(); + + syncPhaseAcc += syncPhaseInc; + if (syncPhaseAcc > 65536.0) { + syncPhaseAcc -= 65536.0; + } + if (syncPhaseAcc < syncPhaseInc) { + // Time to start the next grain + grainPhaseAcc = 0; + grainAmp = 32768.0; + grain2PhaseAcc = 0; + grain2Amp = 32768.0; + LED_PIN = !LED_PIN; + } + + // Increment the phase of the grain oscillators + grainPhaseAcc += grainPhaseInc; + grain2PhaseAcc += grain2PhaseInc; + if (grainPhaseAcc > 65536) grainPhaseAcc -= 65536; + if (grain2PhaseAcc > 65536) grain2PhaseAcc -= 65536; + + // Convert phase into a triangle wave + value = adjustPhaseValue(grainPhaseAcc); + // Multiply by current grain amplitude to get sample + output = value * (grainAmp / 512.0); + + // Repeat for second grain + value = adjustPhaseValue(grain2PhaseAcc); + output += value * (grain2Amp / 512.0); + + // Make the grain amplitudes decay by a factor every sample (exponential decay) + grainAmp -= (grainAmp / 256.0) * grainDecay; + grain2Amp -= (grain2Amp / 256.0) * grain2Decay; + + OUTPUT.write_u16(output); +} + +int main() { + interrupt.attach_us(&interruptHandler, 32); +}