midi sync

This commit is contained in:
chriskiefer 2026-03-06 10:04:30 +00:00
parent 9906cbd154
commit 1af45be168
3 changed files with 47 additions and 13 deletions

View file

@ -70,6 +70,12 @@ public:
queue_t bpmQueue; queue_t bpmQueue;
queue_t sequencerControlQueue; queue_t sequencerControlQueue;
queue_t i2cOutQueue; queue_t i2cOutQueue;
queue_t barPhaseResetQueue;
enum SequencerClockModes {
INTERNAL,
MIDI_CLOCK
} sequencerClockMode = INTERNAL;
bool sequencerPlaying = false; bool sequencerPlaying = false;
@ -99,6 +105,7 @@ public:
queue_init(&bpmQueue, sizeof(float), 1); queue_init(&bpmQueue, sizeof(float), 1);
queue_init(&sequencerControlQueue, sizeof(int), 1); queue_init(&sequencerControlQueue, sizeof(int), 1);
queue_init(&i2cOutQueue, sizeof(float) * 8, 1); queue_init(&i2cOutQueue, sizeof(float) * 8, 1);
queue_init(&barPhaseResetQueue, sizeof(int), 1);
}; };
bool __force_inline euclidean(float phase, const size_t n, const size_t k, const size_t offset, const float pulseWidth) bool __force_inline euclidean(float phase, const size_t n, const size_t k, const size_t offset, const float pulseWidth)
@ -118,18 +125,27 @@ public:
stereosample_t __force_inline Process(const stereosample_t x) override stereosample_t __force_inline Process(const stereosample_t x) override
{ {
if (sequencerPlaying) { if (sequencerPlaying) {
if (sequencerClockMode == INTERNAL){
midiClockPhasor += midiClockPhasorInc; midiClockPhasor += midiClockPhasorInc;
if (midiClockPhasor >= 1.f) { if (midiClockPhasor >= 1.f) {
midiClockPhasor -= 1.f; midiClockPhasor -= 1.f;
midiIO->queueClock(); midiIO->queueClock();
midiIO->flushQueue(); midiIO->flushQueue();
} }
}
if (sequencingSampleCounter==0) { if (sequencingSampleCounter==0) {
barPhasor += barPhasorInc; barPhasor += barPhasorInc;
if (barPhasor >= 1.f) { if (barPhasor >= 1.f) {
barPhasor -= 1.f; barPhasor -= 1.f;
} }
if (sequencerClockMode == MIDI_CLOCK) {
int phasorResetValue=0;
if (queue_try_remove(&barPhaseResetQueue, &phasorResetValue)) {
barPhasor = 0.f;
Serial.println("Bar phase reset triggered by queue");
}
}
int i2cIdx=0; int i2cIdx=0;
for(auto &seq: ratioSeqStates) { for(auto &seq: ratioSeqStates) {
//update phasor //update phasor
@ -163,11 +179,12 @@ public:
return ret; return ret;
} }
void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface) override void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface, SequencerClockModes clockMode)
{ {
AudioAppBase<NPARAMS>::Setup(sample_rate, interface); AudioAppBase<NPARAMS>::Setup(sample_rate, interface);
maxiSettings::sampleRate = sample_rate; maxiSettings::sampleRate = sample_rate;
sampleRatef = static_cast<float>(sample_rate); sampleRatef = static_cast<float>(sample_rate);
sequencerClockMode = clockMode;
updateBPM(90.f); updateBPM(90.f);
const size_t midiNotes[NSEQUENCES] = {36,37,38,39,40, 42,43,45/*,47,48*/}; const size_t midiNotes[NSEQUENCES] = {36,37,38,39,40, 42,43,45/*,47,48*/};
size_t midiNote = 0; size_t midiNote = 0;
@ -190,7 +207,7 @@ public:
// } // }
firstParamsReceived = true; firstParamsReceived = true;
if (queue_try_remove(&bpmQueue, &bpm)) { if (queue_try_remove(&bpmQueue, &bpm)) {
bpm = 30.f + (bpm * 200.f); // Scale BPM from [0,1] to [30,230] // bpm = 30.f + (bpm * 200.f); // Scale BPM from [0,1] to [30,230]
updateBPM(bpm); updateBPM(bpm);
} }
int sequencerControl; int sequencerControl;

View file

@ -25,10 +25,10 @@ public:
InterfaceRL interface; InterfaceRL interface;
std::shared_ptr<InterfaceRL> interfacePtr; std::shared_ptr<InterfaceRL> interfacePtr;
BreakOrAudioApp<>::SequencerClockModes clockMode = BreakOrAudioApp<>::MIDI_CLOCK;
bool sequencerPlaying = false; bool sequencerPlaying = false;
void setupInterface() { void setupInterface() {
interface.setup(kN_InputParams, BreakOrAudioApp<>::kN_Params); interface.setup(kN_InputParams, BreakOrAudioApp<>::kN_Params);
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true); interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK, true);
@ -55,12 +55,13 @@ public:
} }
void setupAudio(float sample_rate) { void setupAudio(float sample_rate) {
audioAppBreakOr.Setup(sample_rate, interfacePtr); audioAppBreakOr.Setup(sample_rate, interfacePtr, clockMode);
voiceSpaceList = audioAppBreakOr.getVoiceSpaceNames(); voiceSpaceList = audioAppBreakOr.getVoiceSpaceNames();
audioAppBreakOr.setupMIDI(midi_interf); audioAppBreakOr.setupMIDI(midi_interf);
MEMLNaut::Instance()->setRVGain1Callback([this](float value) { MEMLNaut::Instance()->setRVGain1Callback([this](float value) {
// Serial.printf("Volume control: %f\n", value); if (clockMode == BreakOrAudioApp<>::INTERNAL) {
queue_try_add(&audioAppBreakOr.bpmQueue, &value); queue_try_add(&audioAppBreakOr.bpmQueue, &value);
}
}, 0); // Set threshold to 0 to trigger on any change }, 0); // Set threshold to 0 to trigger on any change
} }
@ -76,6 +77,22 @@ public:
midi_interf->Setup(0); midi_interf->Setup(0);
midi_interf->SetMIDISendChannel(1); midi_interf->SetMIDISendChannel(1);
midi_interf->SetMIDINoteChannel(10); midi_interf->SetMIDINoteChannel(10);
midi_interf->SetNoteCallback([this](bool noteon, uint8_t note_number, uint8_t vel_value) {
Serial.printf("MIDI Note %d: %d %d\n", note_number, vel_value, noteon);
if (note_number==0) {
int resetTrigger=1;
queue_try_add(&audioAppBreakOr.barPhaseResetQueue, &resetTrigger); // value doesn't matter, just a trigger
Serial.println("Bar phase reset triggered by MIDI note 0");
}
});
midi_interf->SetBPMCallback([this](float bpm) {
// Serial.printf("Estimated BPM: %.2f\n", bpm);
if (clockMode == BreakOrAudioApp<>::MIDI_CLOCK) {
queue_try_add(&audioAppBreakOr.bpmQueue, &bpm);
}
});
interface.bindMIDI(midi_interf); interface.bindMIDI(midi_interf);
} }

@ -1 +1 @@
Subproject commit 1e420bf8ed869d58df75663d3dbf6870aa543de1 Subproject commit 12842a8ae7e7a9d93976fb1291f21f162381b2f4