/* freqout(freq, t) // freq in hz, t in ms
* Paul Badger 2007
* a simple tone generation function
* generates square waves of arbitrary frequency and duration
* program also includes a top-octave lookup table & transposition function
*/
#include <math.h> // requires an Atmega168 chip
#define outpin 4 // audio out to speaker or amp
int ptime;
int k, x, dur, freq, t;
int i, j;
float ps; // variable for pow pitchShift routine
float noteval;
// note values for two octave scale
// divide them by powers of two to generate other octaves
float A = 14080;
float AS = 14917.2;
float B = 15804.3;
float C = 16744;
float CS = 17739.7;
float D = 18794.5;
float DS = 19912.1;
float E = 21096.2;
float F = 22350.6;
float FS = 23679.6;
float G = 25087.7;
float GS = 26579.5;
float A2 = 28160;
float A2S = 29834.5;
float B2 = 31608.5;
float C2 = 33488.1;
float C2S = 35479.4;
float D2 = 37589.1;
float D2S = 39824.3;
float E2 = 42192.3;
float F2 = 44701.2;
float F2S = 47359.3;
float G2 = 50175.4;
float G2S = 53159;
float A3 = 56320;
//octaves - corresponds to piano octaves
float oct8 = 4;
float oct7 = 8;
float oct6 = 16;
float oct5 = 32;
float oct4 = 64;
float oct3 = 128;
float oct2 = 256;
float oct1 = 512;
float oct0 = 1024;
//rhythm values
int wh = 1024;
int h = 512;
int dq = 448;
int q = 256;
int qt = 170;
int de = 192;
int e = 128;
int et = 85;
int dsx = 96;
int sx = 64;
int thx = 32;
// major scale just for demo, hack this
float majScale[] = {
A, B, CS, D, E, FS, GS, A2, B2, C2S, D2, E2, F2S, G2S, A3};
void setup() {
Serial.begin(9600);
}
void loop(){
for(i= 0; i<=11; i++){
ps = (float)i / 12; // choose new transpose interval every loop
for(x= 0; x<=15; x++){
noteval = (majScale[x] / oct4) * pow(2,ps); // transpose scale up 12 tones
// pow function generates transposition
// eliminate " * pow(2,ps) " to cut out transpose routine
dur = 100;
freqout((int)noteval, dur);
delay(10);
}
}
}
void freqout(int freq, int t) // freq in hz, t in ms
{
int hperiod; //calculate 1/2 period in us
long cycles, i;
pinMode(outpin, OUTPUT); // turn on output pin
hperiod = (500000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead
cycles = ((long)freq * (long)t) / 1000; // calculate cycles
// Serial.print(freq);
// Serial.print((char)9); // ascii 9 is tab - you have to coerce it to a char to work
// Serial.print(hperiod);
// Serial.print((char)9);
// Serial.println(cycles);
for (i=0; i<= cycles; i++){ // play note for t ms
digitalWrite(outpin, HIGH);
delayMicroseconds(hperiod);
digitalWrite(outpin, LOW);
delayMicroseconds(hperiod - 1); // - 1 to make up for digitaWrite overhead
}
pinMode(outpin, INPUT); // shut off pin to avoid noise from other operations
}
--- Duration extension
Here's some minor tweaks to the above to extend it just a bit. I left the above untouched cause it's simplicity is great. Basically, I changed the array to have durations and added a sentinel to mark the end.
float EIGHTH = 1; float QUARTER = 2; float DOTTED_QUARTER =3; float HALF = 4; float ETERNITY =-1;
float TEMPO = 150;
float majScale[] = { A,QUARTER, B,QUARTER, CS,QUARTER, D,QUARTER, E,QUARTER, FS,QUARTER, GS,QUARTER, A2,QUARTER, B2,QUARTER, C2S,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER, G2S,QUARTER, A3,QUARTER, REST,ETERNITY};
float odeToJoy[] = {F2S,QUARTER, F2S,QUARTER, G2,QUARTER, A3,QUARTER, A3,QUARTER, G2,QUARTER, F2S,QUARTER, E2,QUARTER, D2,QUARTER, D2,QUARTER,
E2,QUARTER, F2S,QUARTER, F2S,DOTTED_QUARTER, E2,EIGHTH, E2,HALF, F2S,QUARTER, F2S,QUARTER, G2,QUARTER, A3,QUARTER, A3,QUARTER,
G2,QUARTER, F2S,QUARTER, E2,QUARTER, D2,QUARTER, D2,QUARTER, E2,QUARTER, F2S,QUARTER, E2,DOTTED_QUARTER, D2,EIGHTH, D2,HALF,
E2,QUARTER, E2,QUARTER, F2S,QUARTER, D2,QUARTER, E2,QUARTER, F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER, D2,QUARTER, E2,QUARTER,
F2S,EIGHTH, G2,EIGHTH, F2S,QUARTER, E2,QUARTER, D2,QUARTER, E2,QUARTER, A,QUARTER, REST,ETERNITY};
void play(float song[])
{
for(x= 0; x<10000; x=x+2)
{
noteval = (song[x] / 64);
dur = TEMPO * song[x+1];
if(dur < 0)
break;
freqout((int)noteval, dur);
delay(10);
}
}
--- Examples