HI guys,
I've made a few changes and thought I'd post here.
I have decided to go the route of Bresenham accumulators and use the timer directly. Here is what I have to go on:
#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>
#include <TimerOne.h>
#include <avr/pgmspace.h>
#define TIMER_OVF_PERIOD 51 //period in uS before Timer1 triggers the interrupt
#define MAX_ON_TIME 1 //10 to give ~510uS per pulse, 1 for 51uS
#define MODE_NUM 3 //number of modes
/* Output Tone Pins */
int tone1pin = 3;
int tone2pin = 5;
int tone3pin = 6;
volatile int mode;
/* Note Status (On/Off) */
boolean note1on = false;
boolean note2on = false;
boolean note3on = false;
/* 32-bit Bresenham Accumulators */
unsigned long bres1 = 0;
unsigned long bres2 = 0;
unsigned long bres3 = 0;
/* 32-bit Note Frequencies */
unsigned long note1freq;
unsigned long note2freq;
unsigned long note3freq;
/* Note On-Time Counters */
int note1_on_time = MAX_ON_TIME;
int note2_on_time = MAX_ON_TIME;
int note3_on_time = MAX_ON_TIME;
/* MIDI Data Information */
volatile double note;
volatile int type, velocity, channel, d1, d2;
void setup() {
pinMode(tone1pin, OUTPUT); // tone output pins
pinMode(tone2pin, OUTPUT);
pinMode(tone3pin, OUTPUT);
MIDI.begin(MIDI_CHANNEL_OMNI);
Timer1.initialize(TIMER_OVF_PERIOD); //trigger the interrupt at specified number of uS
Timer1.attachInterrupt(noteISR); //attach interrupt service routine to Timer1
Serial.begin(57600);
}
void loop() {
if (MIDI.read()) {
byte type = MIDI.getType();
switch (type) {
case NoteOn:
note = 440.0 * pow(2.0, ((double)(MIDI.getData1()-69.0)/12.0)); //get note frequency
velocity = MIDI.getData2();
channel = MIDI.getChannel();
if (velocity > 0) {
if (!note1on) {
note1freq = note;
note1on = true;
} else if (!note2on) {
note2freq = note;
note2on = true;
} else if (!note3on) {
note3freq = note;
note3on = true;
}
} else {
if (note1freq == note) note1on = false;
else if (note2freq == note) note2on = false;
else if (note3freq == note) note3on = false;
}
break;
case NoteOff:
note = 440.0 * pow(2.0, ((double)(MIDI.getData1()-69.0)/12.0)); //get note frequency
//determine which pin is playing the note and turn it off
if (note1freq == note) note1on = false;
else if (note2freq == note) note2on = false;
else if (note3freq == note) note3on = false;
break;
default:
break;
}
}
}
}
/*****************************
* Interrupt Service Routine *
*****************************/
void noteISR() {
/* Note 1 */
if (note1on) {
bres1 += note1freq * 64;
if (bres1 >= (19531.25 * 64)) {
bres1 -= (19531.25 * 64);
note1_on_time = MAX_ON_TIME;
}
}
if (note1_on_time > 0) {
note1_on_time--;
//Serial.println(note_on_time);
digitalWrite(tone1pin, HIGH);
} else {
digitalWrite(tone1pin, LOW);
}
/* Note 2 */
if (note2on) {
bres2 += note2freq * 64;
if (bres2 >= (19531.25 * 64)) {
bres2 -= (19531.25 * 64);
note2_on_time = MAX_ON_TIME;
}
}
if (note2_on_time > 0) {
note2_on_time--;
//Serial.println(note_on_time);
digitalWrite(tone2pin, HIGH);
} else {
digitalWrite(tone2pin, LOW);
}
/* Note 3 */
if (note3on) {
bres3 += note3freq * 64;
if (bres3 >= (19531.25 * 64)) {
bres3 -= (19531.25 * 64);
note3_on_time = MAX_ON_TIME;
}
}
if (note3_on_time > 0) {
note3_on_time--;
//Serial.println(note_on_time);
digitalWrite(tone3pin, HIGH);
} else {
digitalWrite(tone3pin, LOW);
}
}
Unfortunately, I constantly get stuck notes and can't seem to figure out why. I was hoping someone could look over the code for me.
The specifications have changed a bit. I need each note frequency to have a duty cycle with an on-time that stays at around 50uS. That's what TIMER_OVF_PERIOD and MAX_ON_TIME do. I am using the MIDI library found here: MIDI Library, For Communication With Musical Instruments
I'm afraid there's not much more info I can give you right now. I'm stumped.
Thanks for any insight you can offer.
Regards,
Matt