#include /* Convert series of trigger pulses to MIDI sync */ #include #define triggerPin 2 #define STOP_TIMEOUT 2000 /* for 16th note triggers (4ppqn, like a DR-110 hitting accent on every step), this should be 6. adjust accordingly. PPQN*DIVIDE_SLICE=24 */ #define DIVIDE_SLICE 6 /* attempting to account for code execution, MIDI clock slowness on the receiver end, Arduino clock and/or cosmic rays. This setting lost about 10ms over 5 minutes using trigger from a DR-110 MIDI Clock in on a Yamaha RY-10, with an RBBB using an ATMega168 and resonator clock. YM_W_V. */ #define CODE_OVERHEAD_TIME 10 volatile int trigger=0; volatile unsigned long triggertime=0; unsigned long lasttrig=0; unsigned long nextsync=0; unsigned long timediff=0; unsigned long now=0; int timeslice=0; int started=0; //1= in the playing state. 0= in the stopped state, //int debug=0; //interrupt service routine - if we get a trigger - note it and the time. ISR(INT0_vect){ trigger=1; triggertime=millis(); } void setup(){ pinMode(triggerPin, INPUT); // if(debug){ //Serial.begin(9600); //} else { Serial.begin(31250); // } //interrupt setup stuff. EIMSK |= (1 << INT0); EICRA |= (1 << ISC00); //this line and the next one set interrupt on a rising slope EICRA |= (1 << ISC01); timediff=millis(); lasttrig=millis(); } void loop(){ if(trigger==1){ if (started==0){ //if we're stopped, start! syncSignal(0xFA); started=1; } timediff=triggertime-lasttrig; lasttrig=triggertime; timeslice=timediff/DIVIDE_SLICE; nextsync=millis()+timeslice-CODE_OVERHEAD_TIME; trigger=0; } if (started==1){ //in the world of STOP_TIMEOUT, is the next line needed? // if(timeslice > 1000) {timeslice=1000;} now=millis(); //I'm not convinved millis is an atomic-ish operation... if (now >= nextsync){ syncSignal(0xF8); nextsync=now+timeslice; if ((now-lasttrig) > STOP_TIMEOUT){ //if it's been too long since we've seen a trigger, stop! syncSignal(0xFC); started=0; } } } } void syncSignal(char cmd){ // if(debug){ // Serial.print("sync:"); // Serial.println(millis()); //} else { Serial.print(cmd, BYTE); // } }