Hey fellow forum members!
A good long time ago I built a box for controlling a strobe light with the help of some people on here.
I've just started an update to the project to get the strobe light to synchronise with Virtual DJ using the Midi Clock.
The controller is an UNO R3 running dual MocoLufa firmware on the ATMega16U2.
I have 3 arcade buttons with pullup resistors on the input pins that will give me 1, 2 or 4 flashes per beat. I also have 1 button that will just flash once when pushed.
The strobe is wired up to the LED Pin13.
I've run into several problems getting the light to synchronise with the downbeat because VDJ doesn't send Song Position Pointer messages as far as I'm aware, so whilst it can count the midi clock messages it can't align them to the music. So I've parked that for now and am focusing on using the midi clock to calculate the BPM to set the intervals between flashes.
So far I've used a combination of google searching and ChatGPT to build some code that is almost there.
The problem I'm having with the code now is that If I push and hold a button it doesn't always flash immediately, sometimes there's a delay, it's a pain if I'm trying to manually synchronise by timing the button push.
Also if I hold the button the flashes begin to drift, I have a feeling it's because of the code that's counting the midi messages.
Can anyone help with these two problems?
Thanks for your time.
byte midi_clock = 0xf8;
unsigned long int startTime;
int beatCount;
bool counting = false;
long int bpm;
long int noteTime;
const int StrobePin = 13;
const int buttonPins[] = {2, 3, 4};
long int intervals[3]; // Interval values for 1, 2, and 4 flashes per beat
#define buttonPin11 11
const int numButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);
boolean isButtonPressed = false;
long previousMillis = 0;
long interval = 1000;
boolean isStrobeOn = LOW;
void setup() {
Serial.begin(31250); // Set baud rate to 31250 for MIDI communication
pinMode(StrobePin, OUTPUT);
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT);
}
pinMode(buttonPin11, INPUT);
// Set default intervals
intervals[0] = 200; // 1 flash per beat
intervals[1] = 100; // 2 flashes per beat
intervals[2] = 50; // 4 flashes per beat
}
void loop() {
while (Serial.available()) {
byte midiByte = Serial.read();
if (midiByte == midi_clock) {
if (!counting) { // First time you have seen a clock message in this batch
startTime = millis();
counting = true;
beatCount = 1;
} else {
beatCount += 1;
if (beatCount >= 96) {
noteTime = millis() - startTime;
counting = false;
// You now have the time for one note, so calculate the BPM
bpm = 240000 / noteTime;
// Calculate the interval values for 1, 2, and 4 flashes per beat
intervals[0] = 30000 / bpm; // 1 flash per beat
intervals[1] = 15000 / bpm; // 2 flashes per beat
intervals[2] = 7500 / bpm; // 4 flashes per beat
}
}
}
}
unsigned long currentTime = millis();
for (int i = 0; i < numButtons; i++) {
if (digitalRead(buttonPins[i]) == HIGH) {
isButtonPressed = true;
interval = getInterval(i);
break;
}
isButtonPressed = false;
}
if (isButtonPressed) {
if (currentTime - previousMillis > interval || previousMillis == 0) {
previousMillis = currentTime;
isStrobeOn = !isStrobeOn;
digitalWrite(StrobePin, isStrobeOn);
}
} else {
digitalWrite(StrobePin, LOW);
}
// Check if Button 5 is pressed
if (digitalRead(buttonPin11) == HIGH) {
digitalWrite(StrobePin, HIGH);
} else {
digitalWrite(StrobePin, LOW);
delay(10); // Delay to prevent extra flashes after button release
}
}
long int getInterval(int buttonIndex) {
if (buttonIndex >= 0 && buttonIndex < numButtons) {
return intervals[buttonIndex];
}
return 0; // Return a default value if the buttonIndex is out of range
}