Created
April 17, 2016 17:45
-
-
Save dyln/bcd41f01d35315bf7a99661e7a251059 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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 | |
| // | |
| // Analog in 0: Grain 1 pitch | |
| // Analog in 1: Grain 2 decay | |
| // Analog in 2: Grain 1 decay | |
| // Analog in 3: Grain 2 pitch | |
| // Analog in 4: Grain repetition frequency | |
| // | |
| // Digital 3: Audio out (Digital 11 on ATmega8) | |
| // | |
| // 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) | |
| #include <avr/io.h> | |
| #include <avr/interrupt.h> | |
| 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; | |
| // Map Analogue channels | |
| #define SYNC_CONTROL (4) | |
| #define GRAIN_FREQ_CONTROL (0) | |
| #define GRAIN_DECAY_CONTROL (2) | |
| #define GRAIN2_FREQ_CONTROL (3) | |
| #define GRAIN2_DECAY_CONTROL (1) | |
| // Changing these will also requires rewriting audioOn() | |
| #if defined(__AVR_ATmega8__) | |
| // | |
| // On old ATmega8 boards. | |
| // Output is on pin 11 | |
| // | |
| #define LED_PIN 13 | |
| #define LED_PORT PORTB | |
| #define LED_BIT 5 | |
| #define PWM_PIN 11 | |
| #define PWM_VALUE OCR2 | |
| #define PWM_INTERRUPT TIMER2_OVF_vect | |
| #elif defined(__AVR_ATmega1280__) | |
| // | |
| // On the Arduino Mega | |
| // Output is on pin 3 | |
| // | |
| #define LED_PIN 13 | |
| #define LED_PORT PORTB | |
| #define LED_BIT 7 | |
| #define PWM_PIN 3 | |
| #define PWM_VALUE OCR3C | |
| #define PWM_INTERRUPT TIMER3_OVF_vect | |
| #else | |
| // | |
| // For modern ATmega168 and ATmega328 boards | |
| // Output is on pin 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 | |
| #endif | |
| // Smooth logarithmic mapping | |
| // | |
| 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); | |
| } | |
| // 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(uint16_t input) { | |
| return (midiTable[(1023-input) >> 3]); | |
| } | |
| // 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(uint16_t input) { | |
| uint8_t value = (1023-input) / (1024/53); | |
| return (pentatonicTable[value]); | |
| } | |
| void audioOn() { | |
| #if defined(__AVR_ATmega8__) | |
| // ATmega8 has different registers | |
| TCCR2 = _BV(WGM20) | _BV(COM21) | _BV(CS20); | |
| TIMSK = _BV(TOIE2); | |
| #elif defined(__AVR_ATmega1280__) | |
| TCCR3A = _BV(COM3C1) | _BV(WGM30); | |
| TCCR3B = _BV(CS30); | |
| TIMSK3 = _BV(TOIE3); | |
| #else | |
| // Set up PWM to 31.25kHz, phase accurate | |
| TCCR2A = _BV(COM2B1) | _BV(WGM20); | |
| TCCR2B = _BV(CS20); | |
| TIMSK2 = _BV(TOIE2); | |
| #endif | |
| } | |
| void setup() { | |
| pinMode(PWM_PIN,OUTPUT); | |
| audioOn(); | |
| pinMode(LED_PIN,OUTPUT); | |
| } | |
| void loop() { | |
| // 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(analogRead(SYNC_CONTROL)) / 4; | |
| // Stepped mapping to MIDI notes: C, Db, D, Eb, E, F... | |
| //syncPhaseInc = mapMidi(analogRead(SYNC_CONTROL)); | |
| // Stepped pentatonic mapping: 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) { | |
| // Time to start the next grain | |
| grainPhaseAcc = 0; | |
| grainAmp = 0x7fff; | |
| grain2PhaseAcc = 0; | |
| grain2Amp = 0x7fff; | |
| LED_PORT ^= 1 << LED_BIT; // Faster than using digitalWrite | |
| } | |
| // Increment the phase of the grain oscillators | |
| grainPhaseAcc += grainPhaseInc; | |
| grain2PhaseAcc += grain2PhaseInc; | |
| // Convert phase into a triangle wave | |
| value = (grainPhaseAcc >> 7) & 0xff; | |
| if (grainPhaseAcc & 0x8000) value = ~value; | |
| // Multiply by current grain amplitude to get sample | |
| output = value * (grainAmp >> 8); | |
| // Repeat for second grain | |
| value = (grain2PhaseAcc >> 7) & 0xff; | |
| if (grain2PhaseAcc & 0x8000) value = ~value; | |
| output += value * (grain2Amp >> 8); | |
| // Make the grain amplitudes decay by a factor every sample (exponential decay) | |
| grainAmp -= (grainAmp >> 8) * grainDecay; | |
| grain2Amp -= (grain2Amp >> 8) * grain2Decay; | |
| // Scale output to the available range, clipping if necessary | |
| output >>= 9; | |
| if (output > 255) output = 255; | |
| // Output to PWM (this is faster than using analogWrite) | |
| PWM_VALUE = output; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment