Skip to content

Instantly share code, notes, and snippets.

@vilaca
Created March 30, 2015 10:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vilaca/6681e618e9e8f3e3efdf to your computer and use it in GitHub Desktop.
Save vilaca/6681e618e9e8f3e3efdf to your computer and use it in GitHub Desktop.
Arduino 'Synth' using 8 bit Sigma-Delta DAC v0.0.0
/*
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