diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 2493d620d..f6252cbe7 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2621,7 +2621,7 @@ bool DivEngine::switchMaster() { return true; } -void DivEngine::setMidiCallback(std::function what) { +void DivEngine::setMidiCallback(std::function what) { midiCallback=what; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 1fe93f345..52a01291b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -244,7 +244,8 @@ class DivEngine { size_t totalProcessed; - std::function midiCallback=[](const TAMidiMessage&) -> bool {return false;}; + // MIDI stuff + std::function midiCallback=[](const TAMidiMessage&) -> int {return -1;}; DivSystem systemFromFile(unsigned char val); unsigned char systemToFile(DivSystem val); @@ -638,8 +639,8 @@ class DivEngine { bool switchMaster(); // set MIDI input callback - // if the specified function returns true, note feedback will be inhibited. - void setMidiCallback(std::function what); + // if the specified function returns -2, note feedback will be inhibited. + void setMidiCallback(std::function what); // perform secure/sync operation void synchronized(const std::function& what); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 259209e4a..2f9d6f5c1 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1541,17 +1541,32 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi // process MIDI events (TODO: everything) if (output->midiIn) while (!output->midiIn->queue.empty()) { TAMidiMessage& msg=output->midiIn->queue.front(); - if (!midiCallback(msg)) { + int ins=-1; + if ((ins=midiCallback(msg))!=-2) { int chan=msg.type&15; switch (msg.type&0xf0) { case TA_MIDI_NOTE_OFF: { if (chan<0 || chan>=chans) break; pendingNotes.push(DivNoteEvent(msg.type&15,-1,-1,-1,false)); + if (!playing) { + reset(); + freelance=true; + playing=true; + } break; } case TA_MIDI_NOTE_ON: { if (chan<0 || chan>=chans) break; - pendingNotes.push(DivNoteEvent(msg.type&15,-1,(int)msg.data[0]-12,msg.data[1],true)); + if (msg.data[1]==0) { + pendingNotes.push(DivNoteEvent(msg.type&15,-1,-1,-1,false)); + } else { + pendingNotes.push(DivNoteEvent(msg.type&15,ins,(int)msg.data[0]-12,msg.data[1],true)); + } + if (!playing) { + reset(); + freelance=true; + playing=true; + } break; } case TA_MIDI_PROGRAM: { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 911bef9f2..89bd1a019 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1874,6 +1874,24 @@ bool FurnaceGUI::loop() { } } + while (true) { + midiLock.lock(); + if (midiQueue.empty()) { + midiLock.unlock(); + break; + } + TAMidiMessage msg=midiQueue.front(); + midiLock.unlock(); + + // parse message here + logD("message is %.2x\n",msg.type); + if (msg.type==0xb0) doAction(GUI_ACTION_PLAY_TOGGLE); + + midiLock.lock(); + midiQueue.pop(); + midiLock.unlock(); + } + ImGui_ImplSDLRenderer_NewFrame(); ImGui_ImplSDL2_NewFrame(sdlWin); ImGui::NewFrame(); @@ -2628,10 +2646,12 @@ bool FurnaceGUI::init() { firstFrame=true; - // TODO - e->setMidiCallback([this](const TAMidiMessage& msg) -> bool { - logD("I hate macOS: %p\n",this); - return true; + // TODO: MIDI mapping time! + e->setMidiCallback([this](const TAMidiMessage& msg) -> int { + midiLock.lock(); + midiQueue.push(msg); + midiLock.unlock(); + return curIns; }); return true; diff --git a/src/gui/gui.h b/src/gui/gui.h index 1b06d1526..933455def 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -492,6 +492,14 @@ struct UndoStep { std::vector pat; }; +struct MIDIBind { + int type, channel, data1, data2; +}; + +struct MIDIMap { + std::vector binds; +}; + struct Particle { ImU32* colors; const char* type; @@ -562,6 +570,9 @@ class FurnaceGUI { std::mutex backupLock; String backupPath; + std::mutex midiLock; + std::queue midiQueue; + ImFont* mainFont; ImFont* iconFont; ImFont* patFont;