better MIDI and note input handling

closes #147
This commit is contained in:
tildearrow 2022-03-31 01:51:57 -05:00
parent 6f3b9f2e5d
commit 45ce940d66
7 changed files with 92 additions and 18 deletions

View file

@ -2537,6 +2537,45 @@ void DivEngine::noteOff(int chan) {
BUSY_END; BUSY_END;
} }
void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
//if (ch<0 || ch>=chans) return;
if (midiBaseChan<0) midiBaseChan=0;
if (midiBaseChan>=chans) midiBaseChan=chans-1;
int finalChan=midiBaseChan;
if (!playing) {
reset();
freelance=true;
playing=true;
}
do {
if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type) && chan[finalChan].midiNote==-1) {
chan[finalChan].midiNote=note;
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
break;
}
if (++finalChan>=chans) {
finalChan=0;
}
} while (finalChan!=midiBaseChan);
}
void DivEngine::autoNoteOff(int ch, int note, int vol) {
if (!playing) {
reset();
freelance=true;
playing=true;
}
//if (ch<0 || ch>=chans) return;
for (int i=0; i<chans; i++) {
if (chan[i].midiNote==note) {
pendingNotes.push(DivNoteEvent(i,-1,-1,-1,false));
chan[i].midiNote=-1;
}
}
}
void DivEngine::setOrder(unsigned char order) { void DivEngine::setOrder(unsigned char order) {
BUSY_BEGIN_SOFT; BUSY_BEGIN_SOFT;
curOrder=order; curOrder=order;
@ -2621,6 +2660,11 @@ bool DivEngine::switchMaster() {
return true; return true;
} }
void DivEngine::setMidiBaseChan(int chan) {
if (chan<0 || chan>=chans) chan=0;
midiBaseChan=chan;
}
void DivEngine::setMidiCallback(std::function<int(const TAMidiMessage&)> what) { void DivEngine::setMidiCallback(std::function<int(const TAMidiMessage&)> what) {
midiCallback=what; midiCallback=what;
} }

View file

@ -86,6 +86,8 @@ struct DivChannelState {
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
int midiNote;
DivChannelState(): DivChannelState():
note(-1), note(-1),
oldNote(-1), oldNote(-1),
@ -126,7 +128,8 @@ struct DivChannelState {
scheduledSlideReset(false), scheduledSlideReset(false),
shorthandPorta(false), shorthandPorta(false),
noteOnInhibit(false), noteOnInhibit(false),
resetArp(false) {} resetArp(false),
midiNote(-1) {}
}; };
struct DivNoteEvent { struct DivNoteEvent {
@ -231,6 +234,7 @@ class DivEngine {
short vibTable[64]; short vibTable[64];
int reversePitchTable[4096]; int reversePitchTable[4096];
int pitchTable[4096]; int pitchTable[4096];
int midiBaseChan;
blip_buffer_t* samp_bb; blip_buffer_t* samp_bb;
size_t samp_bbInLen; size_t samp_bbInLen;
@ -539,6 +543,9 @@ class DivEngine {
// stop note // stop note
void noteOff(int chan); void noteOff(int chan);
void autoNoteOn(int chan, int ins, int note, int vol=-1);
void autoNoteOff(int chan, int note, int vol=-1);
// go to order // go to order
void setOrder(unsigned char order); void setOrder(unsigned char order);
@ -638,6 +645,9 @@ class DivEngine {
// switch master // switch master
bool switchMaster(); bool switchMaster();
// set MIDI base channel
void setMidiBaseChan(int chan);
// set MIDI input callback // set MIDI input callback
// if the specified function returns -2, note feedback will be inhibited. // if the specified function returns -2, note feedback will be inhibited.
void setMidiCallback(std::function<int(const TAMidiMessage&)> what); void setMidiCallback(std::function<int(const TAMidiMessage&)> what);
@ -726,6 +736,7 @@ class DivEngine {
view(DIV_STATUS_NOTHING), view(DIV_STATUS_NOTHING),
haltOn(DIV_HALT_NONE), haltOn(DIV_HALT_NONE),
audioEngine(DIV_AUDIO_NULL), audioEngine(DIV_AUDIO_NULL),
midiBaseChan(0),
samp_bbInLen(0), samp_bbInLen(0),
samp_temp(0), samp_temp(0),
samp_prevSample(0), samp_prevSample(0),

View file

@ -430,7 +430,7 @@ struct DivInstrument {
DivInstrument(): DivInstrument():
name(""), name(""),
mode(false), mode(false),
type(DIV_INS_STD) { type(DIV_INS_FM) {
} }
}; };
#endif #endif

View file

@ -1552,7 +1552,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
switch (msg.type&0xf0) { switch (msg.type&0xf0) {
case TA_MIDI_NOTE_OFF: { case TA_MIDI_NOTE_OFF: {
if (chan<0 || chan>=chans) break; if (chan<0 || chan>=chans) break;
pendingNotes.push(DivNoteEvent(msg.type&15,-1,-1,-1,false)); autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
if (!playing) { if (!playing) {
reset(); reset();
freelance=true; freelance=true;
@ -1563,14 +1563,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
case TA_MIDI_NOTE_ON: { case TA_MIDI_NOTE_ON: {
if (chan<0 || chan>=chans) break; if (chan<0 || chan>=chans) break;
if (msg.data[1]==0) { if (msg.data[1]==0) {
pendingNotes.push(DivNoteEvent(msg.type&15,-1,-1,-1,false)); autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
} else { } else {
pendingNotes.push(DivNoteEvent(msg.type&15,ins,(int)msg.data[0]-12,msg.data[1],true)); autoNoteOn(msg.type&15,ins,msg.data[0]-12,msg.data[1]);
}
if (!playing) {
reset();
freelance=true;
playing=true;
} }
break; break;
} }

View file

@ -35,6 +35,7 @@ void FurnaceGUI::startSelection(int xCoarse, int xFine, int y) {
selEnd.xFine=xFine; selEnd.xFine=xFine;
selEnd.y=y; selEnd.y=y;
selecting=true; selecting=true;
e->setMidiBaseChan(cursor.xCoarse);
} }
void FurnaceGUI::updateSelection(int xCoarse, int xFine, int y) { void FurnaceGUI::updateSelection(int xCoarse, int xFine, int y) {
@ -88,6 +89,8 @@ void FurnaceGUI::finishSelection() {
if (e->song.chanCollapse[selEnd.xCoarse]) { if (e->song.chanCollapse[selEnd.xCoarse]) {
selEnd.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2; selEnd.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2;
} }
e->setMidiBaseChan(cursor.xCoarse);
} }
void FurnaceGUI::moveCursor(int x, int y, bool select) { void FurnaceGUI::moveCursor(int x, int y, bool select) {
@ -191,6 +194,7 @@ void FurnaceGUI::moveCursor(int x, int y, bool select) {
} }
selEnd=cursor; selEnd=cursor;
updateScroll(cursor.y); updateScroll(cursor.y);
e->setMidiBaseChan(cursor.xCoarse);
} }
void FurnaceGUI::moveCursorPrevChannel(bool overflow) { void FurnaceGUI::moveCursorPrevChannel(bool overflow) {
@ -210,6 +214,7 @@ void FurnaceGUI::moveCursorPrevChannel(bool overflow) {
cursor.xCoarse=firstChannel; cursor.xCoarse=firstChannel;
} }
} }
e->setMidiBaseChan(cursor.xCoarse);
selStart=cursor; selStart=cursor;
selEnd=cursor; selEnd=cursor;
@ -233,6 +238,7 @@ void FurnaceGUI::moveCursorNextChannel(bool overflow) {
cursor.xCoarse=lastChannel-1; cursor.xCoarse=lastChannel-1;
} }
} }
e->setMidiBaseChan(cursor.xCoarse);
selStart=cursor; selStart=cursor;
selEnd=cursor; selEnd=cursor;
@ -254,6 +260,7 @@ void FurnaceGUI::moveCursorTop(bool select) {
if (!select) { if (!select) {
selEnd=cursor; selEnd=cursor;
} }
e->setMidiBaseChan(cursor.xCoarse);
updateScroll(cursor.y); updateScroll(cursor.y);
} }
@ -273,6 +280,7 @@ void FurnaceGUI::moveCursorBottom(bool select) {
selStart=cursor; selStart=cursor;
} }
selEnd=cursor; selEnd=cursor;
e->setMidiBaseChan(cursor.xCoarse);
updateScroll(cursor.y); updateScroll(cursor.y);
} }

View file

@ -703,7 +703,15 @@ void FurnaceGUI::stop() {
activeNotes.clear(); activeNotes.clear();
} }
void FurnaceGUI::previewNote(int refChan, int note) { void FurnaceGUI::previewNote(int refChan, int note, bool autoNote) {
if (autoNote) {
e->setMidiBaseChan(refChan);
e->synchronized([this,note]() {
e->autoNoteOn(-1,curIns,note);
});
return;
}
bool chanBusy[DIV_MAX_CHANS]; bool chanBusy[DIV_MAX_CHANS];
memset(chanBusy,0,DIV_MAX_CHANS*sizeof(bool)); memset(chanBusy,0,DIV_MAX_CHANS*sizeof(bool));
for (ActiveNote& i: activeNotes) { for (ActiveNote& i: activeNotes) {
@ -725,8 +733,8 @@ void FurnaceGUI::previewNote(int refChan, int note) {
//printf("FAILED TO FIND CHANNEL!\n"); //printf("FAILED TO FIND CHANNEL!\n");
} }
void FurnaceGUI::stopPreviewNote(SDL_Scancode scancode) { void FurnaceGUI::stopPreviewNote(SDL_Scancode scancode, bool autoNote) {
if (activeNotes.empty()) return; if (activeNotes.empty() && !autoNote) return;
try { try {
int key=noteKeys.at(scancode); int key=noteKeys.at(scancode);
int num=12*curOctave+key; int num=12*curOctave+key;
@ -737,6 +745,13 @@ void FurnaceGUI::stopPreviewNote(SDL_Scancode scancode) {
if (key==101) return; if (key==101) return;
if (key==102) return; if (key==102) return;
if (autoNote) {
e->synchronized([this,num]() {
e->autoNoteOff(-1,num);
});
return;
}
for (size_t i=0; i<activeNotes.size(); i++) { for (size_t i=0; i<activeNotes.size(); i++) {
if (activeNotes[i].note==num) { if (activeNotes[i].note==num) {
e->noteOff(activeNotes[i].chan); e->noteOff(activeNotes[i].chan);
@ -1008,7 +1023,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
int key=noteKeys.at(ev.key.keysym.scancode); int key=noteKeys.at(ev.key.keysym.scancode);
int num=12*curOctave+key; int num=12*curOctave+key;
if (key!=100 && key!=101 && key!=102) { if (key!=100 && key!=101 && key!=102) {
previewNote(cursor.xCoarse,num); previewNote(cursor.xCoarse,num,true);
} }
} catch (std::out_of_range& e) { } catch (std::out_of_range& e) {
} }
@ -1052,7 +1067,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
} }
void FurnaceGUI::keyUp(SDL_Event& ev) { void FurnaceGUI::keyUp(SDL_Event& ev) {
stopPreviewNote(ev.key.keysym.scancode); stopPreviewNote(ev.key.keysym.scancode,curWindow!=GUI_WINDOW_PATTERN);
if (wavePreviewOn) { if (wavePreviewOn) {
if (ev.key.keysym.scancode==wavePreviewKey) { if (ev.key.keysym.scancode==wavePreviewKey) {
wavePreviewOn=false; wavePreviewOn=false;
@ -1923,7 +1938,7 @@ bool FurnaceGUI::loop() {
case TA_MIDI_PROGRAM: case TA_MIDI_PROGRAM:
if (midiMap.programChange) { if (midiMap.programChange) {
curIns=msg.data[0]; curIns=msg.data[0];
if (curIns>(int)e->song.ins.size()) curIns=e->song.ins.size()-1; if (curIns>=(int)e->song.ins.size()) curIns=e->song.ins.size()-1;
} }
break; break;
} }
@ -2693,6 +2708,7 @@ bool FurnaceGUI::init() {
midiLock.lock(); midiLock.lock();
midiQueue.push(msg); midiQueue.push(msg);
midiLock.unlock(); midiLock.unlock();
e->setMidiBaseChan(cursor.xCoarse);
if (midiMap.at(msg)) return -2; if (midiMap.at(msg)) return -2;
return curIns; return curIns;
}); });

View file

@ -988,8 +988,8 @@ class FurnaceGUI {
void play(int row=0); void play(int row=0);
void stop(); void stop();
void previewNote(int refChan, int note); void previewNote(int refChan, int note, bool autoNote=false);
void stopPreviewNote(SDL_Scancode scancode); void stopPreviewNote(SDL_Scancode scancode, bool autoNote=false);
void keyDown(SDL_Event& ev); void keyDown(SDL_Event& ev);
void keyUp(SDL_Event& ev); void keyUp(SDL_Event& ev);