Skip to content

Instantly share code, notes, and snippets.

@matthewSorensen
Created October 15, 2011 00:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewSorensen/1288734 to your computer and use it in GitHub Desktop.
Save matthewSorensen/1288734 to your computer and use it in GitHub Desktop.
/**************************************************************
* Hacked down to size, simplified, and tone quality improved.
* Also very heavily adapted for an Arduino-based Ondes Martenot.
* Matthew Sorensen, NOV-DEC 2009
*
* (original copyright 2009. Adrian Freed)
**************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
//Physical aspect of the device:
#define POT_PIN 1 //Potentiometer pin, analog 1
#define VOL_PIN 0 //FSR volume pin, analog 0
#define PWM_PIN 3 //The pin used to output sound (connected to the low-pass and audio-out, digital 3)
#define SWITCH_PIN 4 //Pin for switching between onboard-synth and pd, digital 4
#define TONE_PIN 5 //Pin for switching waveforms, digital 5
//For the interface to pure-data:
#define BAUD 115200 //Must be the same as the baud-rate for the PD comport
#define POT_CHAN 1 //[parser 1] returns the potentiometer data
#define VOL_CHAN 0 //[parser 0] returns the IR data
//Various things for the onboard synth:
#define PWM_DEST OCR2B //Place to output the new wave value
#define PWM_INTERRUPT TIMER2_OVF_vect //The interrupt triggered by PWM counter-overflow
#define INT_MAX 65535 //256*256
#define SIGMAX 1023 //2^10-1, largest signal value
//Parameters controlling aspects of the synth:
#define BASEFREQ 100 //Lowest frequency possible
#define SCALE 1.7 //SIGMAX*SCALE + BASEFREQ = highest frequency possible
#define DELTA_AMP 100 //Responsiveness
#define THRES 100 //Lowest volume we can hear
#define SIG_THRES 10 //Input value that corresponds to THRES
const unsigned int LUTsize = 1<<8;
const unsigned int LUTmask = 0xFF;
int8_t* wavetable;
// A wave-form table designed to replicate the Ondes Martenot - from Lennart's Fourier analysis.
int8_t ondestable[LUTsize] PROGMEM =
{
127,134,141,148,155,162,169,176,183,189,195,201,207,212,
217,222,227,231,234,238,241,244,246,248,250,251,252,253,
253,254,253,253,252,251,250,248,246,244,242,240,238,235,
233,230,227,225,222,219,216,214,211,208,206,203,201,199,
196,194,192,190,189,187,185,184,183,181,180,179,178,178,
177,176,176,175,175,174,174,174,173,173,173,173,172,172,
172,171,171,171,170,170,169,169,168,168,167,166,166,165,
164,163,162,161,160,159,158,157,156,155,153,152,151,150,
148,147,146,144,143,142,140,139,137,136,135,133,132,131,
129,128,127,125,124,122,121,120,118,117,116,114,113,111,
110,109,107,106,105,103,102,101,100,98,97,96,95,94,93,92,
91,90,89,88,87,87,86,85,85,84,84,83,83,82,82,82,81,81,81,
80,80,80,80,79,79,79,78,78,77,77,76,75,75,74,73,72,70,69,
68,66,64,63,61,59,57,54,52,50,47,45,42,39,37,34,31,28,26,
23,20,18,15,13,11,9,7,5,3,2,1,0,0,0,0,0,1,2,3,5,7,9,12,15,
19,22,26,31,36,41,46,52,58,64,70,77,84,91,98,105,112,119
};
int8_t sintable[LUTsize] PROGMEM = { // already biased with +127
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,
176,179,182,184,187,190,193,195,198,200,203,205,208,210,213,215,
217,219,221,224,226,228,229,231,233,235,236,238,239,241,242,244,
245,246,247,248,249,250,251,251,252,253,253,254,254,254,254,254,
255,254,254,254,254,254,253,253,252,251,251,250,249,248,247,246,
245,244,242,241,239,238,236,235,233,231,229,228,226,224,221,219,
217,215,213,210,208,205,203,200,198,195,193,190,187,184,182,179,
176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,
127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,
78,75,72,70,67,64,61,59,56,54,51,49,46,44,41,39,
37,35,33,30,28,26,25,23,21,19,18,16,15,13,12,10,
9,8,7,6,5,4,3,3,2,1,1,0,0,0,0,0,
0,0,0,0,0,0,1,1,2,3,3,4,5,6,7,8,
9,10,12,13,15,16,18,19,21,23,25,26,28,30,33,35,
37,39,41,44,46,49,51,54,56,59,61,64,67,70,72,75,
78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};
const int timerPrescale=1<<9;
//The oscillator variables
uint32_t phase;//Current position in phase
int32_t phase_increment;//Controls pitch
uint16_t amp;//Current amplitude
uint16_t idealAmp;//Amplitude we want
const int fractionalbits = 16; // 16 bits fractional phase
// compute a phase increment from a frequency
unsigned long phaseinc(float frequency_in_Hz){
return LUTsize *(1l<<fractionalbits)* frequency_in_Hz/(F_CPU/timerPrescale);
}
void initializeTimer() {
// Set up PWM with Clock/256 (i.e. 31.25kHz on Arduino 16MHz;
// and phase accurate
//Timer 2, 8 bit
/* _BV(WGM20) (bit 0) toggles phase correct PWM,
* _BV(COM2B1)(bit 5) clears OC2B on match, sets 0C2B to bottom*/
TCCR2A = _BV(COM2B1) | _BV(WGM20);
/* Bits 2:0 of TCCR2B select the clock source, in this case
* no prescaler */
TCCR2B = _BV(CS20);
/*Enables the interrupt on counter overflow */
TIMSK2 = _BV(TOIE2);
pinMode(PWM_PIN,OUTPUT);
}
void setup(){
Serial.begin(BAUD);
pinMode(SWITCH_PIN,INPUT);
phase = 0; //Start out oscillator
phase_increment = 0 ;//0 hertz
amp = 0; //No sound
initializeTimer();
wavetable = ondestable;
}
void loop() {
idealAmp =255*256;//Max
phase_increment = phaseinc(440.0);
while(1){
if(digitalRead(SWITCH_PIN)){
doXSerial(200);
}else{
doXSynth(200);
}
}
}
void doXSynth(int x){
while(x-->0){
if(analogRead(TONE_PIN)){
wavetable = sintable;
}else{
wavetable = ondestable;
}
phase_increment = phaseinc((float)analogRead(POT_PIN)*SCALE+BASEFREQ);//Set freq
int sig = analogRead(VOL_PIN);
if(sig>SIG_THRES){//Any reading smaller than 10 means off
if(THRES>amp){//If off, turn on to lowest volume
amp=THRES;
}
idealAmp = THRES+(sig-1)*((INT_MAX-THRES)/(SIGMAX-SIG_THRES));//Set volume, scaling to 0-255
}else{//Else turn off
amp =0;
idealAmp=0;
}
}
}
void doXSerial(int x){
while(x-->0){
send(POT_CHAN,analogRead(POT_PIN));
send(VOL_CHAN,analogRead(VOL_PIN));
}
}
//Look up wave in sine table, scale by amp, increment phase...
//Rinse and repeat.
int8_t outputvalue =0;
SIGNAL(PWM_INTERRUPT){
PWM_DEST = outputvalue; //output first for better tone, then calc new
outputvalue = (((uint8_t)(amp>>8)) * pgm_read_byte(wavetable+((phase>>16)&LUTmask)))>>8;
phase += (uint32_t)phase_increment;//Overflow is good
if(amp!=idealAmp){//If the volume isn't where we want, change it slowly
amp += (amp>idealAmp)? -DELTA_AMP:DELTA_AMP;
}
}
//Will fail if chan>31, and data is truncated to 10 bits
//0000001111100000 0x3E0
//0000000000011111 0x1F
//0000000011100000 0xE0
void send(unsigned char chan,int data){
if(chan<32){
Serial.print(chan,BYTE);//Channel
Serial.print(((data&0x3E0)>>5)|0xE0,BYTE);//High
Serial.print((data&0x1F)|0xE0,BYTE); //Low
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment