MIDI input: program change pass-through option
This commit is contained in:
parent
39481ab571
commit
478f7bb3bd
|
@ -3392,6 +3392,10 @@ void DivEngine::setMidiDirect(bool value) {
|
||||||
midiIsDirect=value;
|
midiIsDirect=value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::setMidiDirectProgram(bool value) {
|
||||||
|
midiIsDirectProgram=value;
|
||||||
|
}
|
||||||
|
|
||||||
void DivEngine::setMidiVolExp(float value) {
|
void DivEngine::setMidiVolExp(float value) {
|
||||||
midiVolExp=value;
|
midiVolExp=value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,16 +176,16 @@ struct DivNoteEvent {
|
||||||
signed char channel;
|
signed char channel;
|
||||||
unsigned char ins;
|
unsigned char ins;
|
||||||
signed char note, volume;
|
signed char note, volume;
|
||||||
bool on, nop, pad1, pad2;
|
bool on, nop, insChange, fromMIDI;
|
||||||
DivNoteEvent(int c, int i, int n, int v, bool o):
|
DivNoteEvent(int c, int i, int n, int v, bool o, bool ic=false, bool fm=false):
|
||||||
channel(c),
|
channel(c),
|
||||||
ins(i),
|
ins(i),
|
||||||
note(n),
|
note(n),
|
||||||
volume(v),
|
volume(v),
|
||||||
on(o),
|
on(o),
|
||||||
nop(false),
|
nop(false),
|
||||||
pad1(false),
|
insChange(ic),
|
||||||
pad2(false) {}
|
fromMIDI(fm) {}
|
||||||
DivNoteEvent():
|
DivNoteEvent():
|
||||||
channel(-1),
|
channel(-1),
|
||||||
ins(0),
|
ins(0),
|
||||||
|
@ -193,8 +193,8 @@ struct DivNoteEvent {
|
||||||
volume(-1),
|
volume(-1),
|
||||||
on(false),
|
on(false),
|
||||||
nop(true),
|
nop(true),
|
||||||
pad1(false),
|
insChange(false),
|
||||||
pad2(false) {}
|
fromMIDI(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivDispatchContainer {
|
struct DivDispatchContainer {
|
||||||
|
@ -415,6 +415,7 @@ class DivEngine {
|
||||||
bool firstTick;
|
bool firstTick;
|
||||||
bool skipping;
|
bool skipping;
|
||||||
bool midiIsDirect;
|
bool midiIsDirect;
|
||||||
|
bool midiIsDirectProgram;
|
||||||
bool lowLatency;
|
bool lowLatency;
|
||||||
bool systemsRegistered;
|
bool systemsRegistered;
|
||||||
bool hasLoadedSomething;
|
bool hasLoadedSomething;
|
||||||
|
@ -1188,6 +1189,9 @@ class DivEngine {
|
||||||
// set MIDI direct channel map
|
// set MIDI direct channel map
|
||||||
void setMidiDirect(bool value);
|
void setMidiDirect(bool value);
|
||||||
|
|
||||||
|
// set MIDI direct program change
|
||||||
|
void setMidiDirectProgram(bool value);
|
||||||
|
|
||||||
// set MIDI volume curve exponent
|
// set MIDI volume curve exponent
|
||||||
void setMidiVolExp(float value);
|
void setMidiVolExp(float value);
|
||||||
|
|
||||||
|
@ -1260,6 +1264,7 @@ class DivEngine {
|
||||||
firstTick(false),
|
firstTick(false),
|
||||||
skipping(false),
|
skipping(false),
|
||||||
midiIsDirect(false),
|
midiIsDirect(false),
|
||||||
|
midiIsDirectProgram(false),
|
||||||
lowLatency(false),
|
lowLatency(false),
|
||||||
systemsRegistered(false),
|
systemsRegistered(false),
|
||||||
hasLoadedSomething(false),
|
hasLoadedSomething(false),
|
||||||
|
|
|
@ -1370,8 +1370,15 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
pendingNotes.pop_front();
|
pendingNotes.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (note.insChange) {
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,0));
|
||||||
|
pendingNotes.pop_front();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (note.on) {
|
if (note.on) {
|
||||||
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1));
|
if (!(midiIsDirect && midiIsDirectProgram && note.fromMIDI)) {
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1));
|
||||||
|
}
|
||||||
if (note.volume>=0 && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
if (note.volume>=0 && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
|
||||||
float curvedVol=pow((float)note.volume/127.0f,midiVolExp);
|
float curvedVol=pow((float)note.volume/127.0f,midiVolExp);
|
||||||
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],curvedVol);
|
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],curvedVol);
|
||||||
|
@ -1832,7 +1839,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
case TA_MIDI_NOTE_OFF: {
|
case TA_MIDI_NOTE_OFF: {
|
||||||
if (chan<0 || chan>=chans) break;
|
if (chan<0 || chan>=chans) break;
|
||||||
if (midiIsDirect) {
|
if (midiIsDirect) {
|
||||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
|
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
|
||||||
} else {
|
} else {
|
||||||
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
||||||
}
|
}
|
||||||
|
@ -1847,13 +1854,13 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
if (chan<0 || chan>=chans) break;
|
if (chan<0 || chan>=chans) break;
|
||||||
if (msg.data[1]==0) {
|
if (msg.data[1]==0) {
|
||||||
if (midiIsDirect) {
|
if (midiIsDirect) {
|
||||||
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
|
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
|
||||||
} else {
|
} else {
|
||||||
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
autoNoteOff(msg.type&15,msg.data[0]-12,msg.data[1]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (midiIsDirect) {
|
if (midiIsDirect) {
|
||||||
pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true));
|
pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true,false,true));
|
||||||
} else {
|
} else {
|
||||||
autoNoteOn(msg.type&15,ins,msg.data[0]-12,msg.data[1]);
|
autoNoteOn(msg.type&15,ins,msg.data[0]-12,msg.data[1]);
|
||||||
}
|
}
|
||||||
|
@ -1861,7 +1868,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TA_MIDI_PROGRAM: {
|
case TA_MIDI_PROGRAM: {
|
||||||
// TODO: change instrument event thingy
|
if (midiIsDirect && midiIsDirectProgram) {
|
||||||
|
pendingNotes.push_back(DivNoteEvent(chan,msg.data[0],0,0,false,true,true));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3803,7 +3803,7 @@ bool FurnaceGUI::loop() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TA_MIDI_PROGRAM:
|
case TA_MIDI_PROGRAM:
|
||||||
if (midiMap.programChange) {
|
if (midiMap.programChange && !(midiMap.directChannel && midiMap.directProgram)) {
|
||||||
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;
|
||||||
wavePreviewInit=true;
|
wavePreviewInit=true;
|
||||||
|
@ -7018,6 +7018,7 @@ bool FurnaceGUI::init() {
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (midiMap.directChannel && midiMap.directProgram) return -1;
|
||||||
return curIns;
|
return curIns;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -936,7 +936,7 @@ struct MIDIMap {
|
||||||
int**** map;
|
int**** map;
|
||||||
std::vector<MIDIBind> binds;
|
std::vector<MIDIBind> binds;
|
||||||
|
|
||||||
bool noteInput, volInput, rawVolume, polyInput, directChannel, programChange, midiClock, midiTimeCode, yamahaFMResponse;
|
bool noteInput, volInput, rawVolume, polyInput, directChannel, programChange, midiClock, midiTimeCode, yamahaFMResponse, directProgram;
|
||||||
// 0: disabled
|
// 0: disabled
|
||||||
//
|
//
|
||||||
// 1: C- C# D- D# E- F- F# G- G# A- A# B-
|
// 1: C- C# D- D# E- F- F# G- G# A- A# B-
|
||||||
|
@ -999,6 +999,7 @@ struct MIDIMap {
|
||||||
midiClock(false),
|
midiClock(false),
|
||||||
midiTimeCode(false),
|
midiTimeCode(false),
|
||||||
yamahaFMResponse(false),
|
yamahaFMResponse(false),
|
||||||
|
directProgram(false),
|
||||||
valueInputStyle(1),
|
valueInputStyle(1),
|
||||||
valueInputControlMSB(0),
|
valueInputControlMSB(0),
|
||||||
valueInputControlLSB(0),
|
valueInputControlLSB(0),
|
||||||
|
|
|
@ -139,6 +139,7 @@ bool MIDIMap::read(String path) {
|
||||||
UNDERSTAND_OPTION(midiClock) else
|
UNDERSTAND_OPTION(midiClock) else
|
||||||
UNDERSTAND_OPTION(midiTimeCode) else
|
UNDERSTAND_OPTION(midiTimeCode) else
|
||||||
UNDERSTAND_OPTION(yamahaFMResponse) else
|
UNDERSTAND_OPTION(yamahaFMResponse) else
|
||||||
|
UNDERSTAND_OPTION(directProgram) else
|
||||||
UNDERSTAND_OPTION(valueInputStyle) else
|
UNDERSTAND_OPTION(valueInputStyle) else
|
||||||
UNDERSTAND_OPTION(valueInputControlMSB) else
|
UNDERSTAND_OPTION(valueInputControlMSB) else
|
||||||
UNDERSTAND_OPTION(valueInputControlLSB) else
|
UNDERSTAND_OPTION(valueInputControlLSB) else
|
||||||
|
@ -205,6 +206,7 @@ bool MIDIMap::write(String path) {
|
||||||
WRITE_OPTION(midiClock);
|
WRITE_OPTION(midiClock);
|
||||||
WRITE_OPTION(midiTimeCode);
|
WRITE_OPTION(midiTimeCode);
|
||||||
WRITE_OPTION(yamahaFMResponse);
|
WRITE_OPTION(yamahaFMResponse);
|
||||||
|
WRITE_OPTION(directProgram);
|
||||||
WRITE_OPTION(valueInputStyle);
|
WRITE_OPTION(valueInputStyle);
|
||||||
WRITE_OPTION(valueInputControlMSB);
|
WRITE_OPTION(valueInputControlMSB);
|
||||||
WRITE_OPTION(valueInputControlLSB);
|
WRITE_OPTION(valueInputControlLSB);
|
||||||
|
|
|
@ -1141,10 +1141,19 @@ void FurnaceGUI::drawSettings() {
|
||||||
//ImGui::Checkbox("Polyphonic/chord input",&midiMap.polyInput);
|
//ImGui::Checkbox("Polyphonic/chord input",&midiMap.polyInput);
|
||||||
if (ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel)) {
|
if (ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel)) {
|
||||||
e->setMidiDirect(midiMap.directChannel);
|
e->setMidiDirect(midiMap.directChannel);
|
||||||
|
e->setMidiDirectProgram(midiMap.directChannel && midiMap.directProgram);
|
||||||
settingsChanged=true;
|
settingsChanged=true;
|
||||||
}
|
}
|
||||||
|
if (midiMap.directChannel) {
|
||||||
|
if (ImGui::Checkbox("Program change pass-through",&midiMap.directProgram)) {
|
||||||
|
e->setMidiDirectProgram(midiMap.directChannel && midiMap.directProgram);
|
||||||
|
settingsChanged=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ImGui::Checkbox("Map Yamaha FM voice data to instruments",&midiMap.yamahaFMResponse)) settingsChanged=true;
|
if (ImGui::Checkbox("Map Yamaha FM voice data to instruments",&midiMap.yamahaFMResponse)) settingsChanged=true;
|
||||||
if (ImGui::Checkbox("Program change is instrument selection",&midiMap.programChange)) settingsChanged=true;
|
if (!(midiMap.directChannel && midiMap.directProgram)) {
|
||||||
|
if (ImGui::Checkbox("Program change is instrument selection",&midiMap.programChange)) settingsChanged=true;
|
||||||
|
}
|
||||||
//ImGui::Checkbox("Listen to MIDI clock",&midiMap.midiClock);
|
//ImGui::Checkbox("Listen to MIDI clock",&midiMap.midiClock);
|
||||||
//ImGui::Checkbox("Listen to MIDI time code",&midiMap.midiTimeCode);
|
//ImGui::Checkbox("Listen to MIDI time code",&midiMap.midiTimeCode);
|
||||||
if (ImGui::Combo("Value input style",&midiMap.valueInputStyle,valueInputStyles,7)) settingsChanged=true;
|
if (ImGui::Combo("Value input style",&midiMap.valueInputStyle,valueInputStyles,7)) settingsChanged=true;
|
||||||
|
@ -4029,6 +4038,7 @@ void FurnaceGUI::syncSettings() {
|
||||||
midiMap.compile();
|
midiMap.compile();
|
||||||
|
|
||||||
e->setMidiDirect(midiMap.directChannel);
|
e->setMidiDirect(midiMap.directChannel);
|
||||||
|
e->setMidiDirectProgram(midiMap.directChannel && midiMap.directProgram);
|
||||||
e->setMidiVolExp(midiMap.volExp);
|
e->setMidiVolExp(midiMap.volExp);
|
||||||
e->setMetronomeVol(((float)settings.metroVol)/100.0f);
|
e->setMetronomeVol(((float)settings.metroVol)/100.0f);
|
||||||
e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f);
|
e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f);
|
||||||
|
|
Loading…
Reference in a new issue