Created
March 30, 2015 10:01
-
-
Save vilaca/6681e618e9e8f3e3efdf to your computer and use it in GitHub Desktop.
Arduino 'Synth' using 8 bit Sigma-Delta DAC v0.0.0
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
/* | |
Arduino 'Synth' using 8 bit Sigma-Delta DAC v0.0.0 | |
Can be played over serial. Connect speaker to pin9 and GND. | |
Piano keys: z s x d c v g b h n j m ; ( + shift = transpose up) | |
Mute: space | |
Transpose up: + | |
Transpose down: - | |
Change OSC FX: * | |
*/ | |
// speaker at rest | |
#define DC_OFFSET 127 | |
// connect speaker to this pin | |
#define DAC_OUTPUT_PIN 9 | |
// inital keyb octave | |
#define OCTAVE 3 | |
#define MIN_OCTAVE 0 | |
#define MAX_OCTAVE 7 | |
// fx bounds | |
#define FX 0 | |
#define MAX_FX 7 | |
// piano keys | |
enum Notes { NOTE_C, NOTE_C_SHARP, NOTE_D, NOTE_D_SHARP, NOTE_E, NOTE_F, NOTE_F_SHARP, NOTE_G, NOTE_G_SHARP, NOTE_A, NOTE_A_SHARP, NOTE_B }; | |
float pitch[] = { | |
0.05232512, | |
0.05543664, | |
0.05873296, | |
0.06222544, | |
0.0659256, | |
0.06984576, | |
0.07399888, | |
0.0783992, | |
0.0830608, | |
0.088, | |
0.09323296, | |
0.09877664, | |
0.10465024, | |
0.11087328, | |
0.11746592, | |
0.12445088, | |
0.1318512, | |
0.13969152, | |
0.14799776, | |
0.1567984, | |
0.1661216, | |
0.176, | |
0.1864656, | |
0.19755328, | |
0.20930048, | |
0.22174624, | |
0.23493184, | |
0.24890144, | |
0.26370208, | |
0.27938272, | |
0.29599552, | |
0.31359648, | |
0.3322432, | |
0.352, | |
0.3729312, | |
0.3951072, | |
0.4186016, | |
0.4434912, | |
0.4698624, | |
0.4978016, | |
0.5274048, | |
0.5587648, | |
0.5919904, | |
0.6271936, | |
0.6644864, | |
0.704, | |
0.7458624, | |
0.7902144, | |
0.8372032, | |
0.8869856, | |
0.939728, | |
0.9956064, | |
1.0548096, | |
1.1175296, | |
1.1839808, | |
1.254384, | |
1.328976, | |
1.408, | |
1.4917248, | |
1.5804256, | |
1.6744032, | |
1.773968, | |
1.879456, | |
1.9912128, | |
2.109616, | |
2.2350592, | |
2.3679648, | |
2.5087712, | |
2.6579488, | |
2.816, | |
2.9834496, | |
3.1608544, | |
3.3488, | |
3.547936, | |
3.758912, | |
3.982432, | |
4.219232, | |
4.470112, | |
4.735936, | |
5.017536, | |
5.315904, | |
5.632, | |
5.966912, | |
6.321696, | |
6.6976, | |
7.095872, | |
7.517824, | |
7.964864, | |
8.438464, | |
8.940256, | |
9.471872, | |
10.035072, | |
10.631808, | |
11.264, | |
11.933792, | |
12.643424, | |
13.395232 | |
}; | |
// setup timer interrupts | |
void setup() { | |
Serial.begin(9600); | |
cli(); | |
// 8 bit fast PWM | |
pinMode(DAC_OUTPUT_PIN, OUTPUT); | |
// no prescaller = 16MHz | |
TCCR1B = (1 << CS10); | |
// Pin low when TCNT1=OCR1A | |
// Use 8-bit fast PWM mode | |
TCCR1A |= (1 << COM1A1) | (1 << WGM10); | |
TCCR1B |= (1 << WGM12); | |
// speaker at rest | |
OCR1AL = DC_OFFSET; | |
// disable timer2 channel b | |
TCCR2B = 0; | |
// Clear Timer on Compare Match (CTC) mode | |
TCCR2A = _BV( WGM21 ); | |
// reset int flag register | |
TIFR2 = 0; | |
// set OCIE2A as match register | |
TIMSK2 = _BV( OCIE2A ); | |
// count to n | |
OCR2A = 99; | |
// x8 prescale | |
TCCR2B = _BV( CS21 ); | |
sei(); | |
} | |
void loop() { | |
// nothing happens here ;) | |
} | |
// this method most likely eats a lot of cpu | |
int roundff(float d) | |
{ | |
return (int)(d + 0.5); | |
} | |
// octave ( note being played ) | |
static int oct = OCTAVE; | |
// bit fx | |
static int fx = FX; | |
// used to generate waveform | |
static float accum = 0; | |
// used to increment accum | |
static float ratio = 0; | |
// interrupt method | |
ISR (TIMER2_COMPA_vect) | |
{ | |
accum += ratio; | |
// output waveform | |
// OCR1AL is the DAC register | |
switch (fx) | |
{ | |
case 0: | |
OCR1AL = ~(roundff(accum) & 255); | |
break; | |
case 1: | |
OCR1AL = (roundff(accum) & 255) > DC_OFFSET ? 0 : 255; | |
break; | |
case 2: | |
OCR1AL = ~(roundff(accum) & millis() & 255); | |
break; | |
case 3: | |
OCR1AL = (~roundff(accum) & 255) > DC_OFFSET ? millis() & 255 : 255; | |
break; | |
case 4: | |
OCR1AL = (~roundff(accum) & 255) > DC_OFFSET ? millis() & 255 : roundff(accum) & 255; | |
break; | |
case 5: | |
OCR1AL = (~roundff(accum) & 255) < DC_OFFSET ? millis() & 255 : roundff(accum) & 255; | |
break; | |
case 6: | |
OCR1AL = ~(roundff(accum) | millis() & 255); | |
break; | |
case 7: | |
OCR1AL = (~roundff(accum) & millis() & 255) > DC_OFFSET ? 0 : 255; | |
break; | |
} | |
} | |
// set note to play | |
// trans(pose) not used for now | |
void playNote(int n, int trans) | |
{ | |
ratio = pitch[12 * (oct + trans) + n] * 4; | |
accum = 0; | |
} | |
// set quiet | |
void mute() | |
{ | |
ratio = 0; | |
OCR1AL = DC_OFFSET; | |
} | |
// read terminal | |
void serialEvent() { | |
while (Serial.available()) { | |
char in = (char)Serial.read(); | |
int transpose = 0; | |
if ( in >= 'A' && in <= 'Z' && oct < MAX_OCTAVE) | |
{ | |
in = in + 'a' - 'A'; | |
transpose = 1; | |
} | |
switch ( in ) | |
{ | |
case 'z': | |
playNote ( NOTE_C, transpose); | |
break; | |
case 's': | |
playNote ( NOTE_C_SHARP, transpose); | |
break; | |
case 'x': | |
playNote ( NOTE_D, transpose); | |
break; | |
case 'd': | |
playNote ( NOTE_D_SHARP, transpose); | |
break; | |
case 'c': | |
playNote ( NOTE_E, transpose); | |
break; | |
case 'v': | |
playNote ( NOTE_F, transpose); | |
break; | |
case 'g': | |
playNote ( NOTE_F_SHARP, transpose); | |
break; | |
case 'b': | |
playNote ( NOTE_G, transpose); | |
break; | |
case 'h': | |
playNote ( NOTE_G_SHARP, transpose); | |
break; | |
case 'n': | |
playNote ( NOTE_A, transpose); | |
break; | |
case 'j': | |
playNote ( NOTE_A_SHARP, transpose); | |
break; | |
case 'm': | |
playNote ( NOTE_B, transpose); | |
break; | |
case ',': | |
if ( oct < MAX_OCTAVE ) playNote ( NOTE_C, 1 + transpose); | |
break; | |
case ' ': | |
mute(); | |
break; | |
case '+': | |
if ( oct < MAX_OCTAVE ) oct++; | |
break; | |
case '-': | |
if ( oct > MIN_OCTAVE ) oct--; | |
break; | |
case '*': | |
if ( fx < MAX_FX ) fx++; else fx = 0; | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment