MIDI output improvements

This commit is contained in:
tildearrow 2022-09-26 01:27:36 -05:00
parent c27c650c11
commit 122694d7c9
5 changed files with 117 additions and 47 deletions

View file

@ -3683,6 +3683,8 @@ bool DivEngine::initAudioBackend() {
clampSamples=getConfInt("clampSamples",0);
lowLatency=getConfInt("lowLatency",0);
metroVol=(float)(getConfInt("metroVol",100))/100.0f;
midiOutClock=getConfInt("midiOutClock",0);
midiOutMode=getConfInt("midiOutMode",DIV_MIDI_MODE_NOTE);
if (metroVol<0.0f) metroVol=0.0f;
if (metroVol>2.0f) metroVol=2.0f;

View file

@ -83,6 +83,12 @@ enum DivHaltPositions {
DIV_HALT_BREAKPOINT
};
enum DivMIDIModes {
DIV_MIDI_MODE_OFF=0,
DIV_MIDI_MODE_NOTE,
DIV_MIDI_MODE_LIGHT_SHOW
};
struct DivChannelState {
std::vector<DivDelayedCommand> delayed;
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
@ -340,6 +346,8 @@ class DivEngine {
bool lowLatency;
bool systemsRegistered;
bool hasLoadedSomething;
bool midiOutClock;
int midiOutMode;
int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
size_t curSubSongIndex;
@ -1008,6 +1016,8 @@ class DivEngine {
lowLatency(false),
systemsRegistered(false),
hasLoadedSomething(false),
midiOutClock(false),
midiOutMode(DIV_MIDI_MODE_NOTE),
softLockCount(0),
subticks(0),
ticks(0),

View file

@ -257,52 +257,79 @@ int DivEngine::dispatchCmd(DivCommand c) {
if (output) if (!skipping && output->midiOut!=NULL) {
if (output->midiOut->isDeviceOpen()) {
int scaledVol=(chan[c.chan].volume*127)/MAX(1,chan[c.chan].volMax);
if (scaledVol<0) scaledVol=0;
if (scaledVol>127) scaledVol=127;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
case DIV_CMD_LEGATO:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
if (midiOutMode==DIV_MIDI_MODE_NOTE) {
int scaledVol=(chan[c.chan].volume*127)/MAX(1,chan[c.chan].volMax);
if (scaledVol<0) scaledVol=0;
if (scaledVol>127) scaledVol=127;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
case DIV_CMD_LEGATO:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].curMidiNote=c.value+12;
if (chan[c.chan].curMidiNote<0) chan[c.chan].curMidiNote=0;
if (chan[c.chan].curMidiNote>127) chan[c.chan].curMidiNote=127;
}
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
break;
case DIV_CMD_NOTE_OFF:
case DIV_CMD_NOTE_OFF_ENV:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
chan[c.chan].curMidiNote=-1;
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) {
chan[c.chan].midiAftertouch=false;
output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
break;
case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383;
if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break;
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].curMidiNote=c.value+12;
if (chan[c.chan].curMidiNote<0) chan[c.chan].curMidiNote=0;
if (chan[c.chan].curMidiNote>127) chan[c.chan].curMidiNote=127;
case DIV_CMD_PANNING: {
int pan=convertPanSplitToLinearLR(c.value,c.value2,127);
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x0a,pan));
break;
}
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
break;
case DIV_CMD_NOTE_OFF:
case DIV_CMD_NOTE_OFF_ENV:
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
case DIV_CMD_HINT_PORTA: {
if (c.value2>0) {
if (c.value<=0 || c.value>=255) break;
//output->midiOut->send(TAMidiMessage(0x80|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
int target=c.value+12;
if (target<0) target=0;
if (target>127) target=127;
if (chan[c.chan].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x54,chan[c.chan].curMidiNote));
}
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x05,1/*MIN(0x7f,c.value2/4)*/));
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x41,0x7f));
output->midiOut->send(TAMidiMessage(0x90|(c.chan&15),target,scaledVol));
} else {
output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x41,0));
}
break;
}
chan[c.chan].curMidiNote=-1;
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) {
chan[c.chan].midiAftertouch=false;
output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol));
}
break;
case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383;
if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break;
default:
break;
}
default:
break;
}
}
}
@ -1055,11 +1082,6 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
cycles++;
}
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL) {
//output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
if (!pendingNotes.empty()) {
bool isOn[DIV_MAX_CHANS];
memset(isOn,0,DIV_MAX_CHANS*sizeof(bool));
@ -1106,6 +1128,12 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
if (!freelance) {
if (--subticks<=0) {
subticks=tickMult;
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL && midiOutClock) {
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
if (stepPlay!=1) {
tempoAccum+=curSubSong->virtualTempoN;
while (tempoAccum>=curSubSong->virtualTempoD) {

View file

@ -1195,6 +1195,8 @@ class FurnaceGUI {
int channelFeedbackStyle;
int channelFont;
int channelTextCenter;
int midiOutClock;
int midiOutMode;
int maxRecentFile;
unsigned int maxUndoSteps;
String mainFontPath;
@ -1318,6 +1320,8 @@ class FurnaceGUI {
channelFeedbackStyle(1),
channelFont(1),
channelTextCenter(1),
midiOutClock(0),
midiOutMode(1),
maxRecentFile(10),
maxUndoSteps(100),
mainFontPath(""),

View file

@ -955,6 +955,26 @@ void FurnaceGUI::drawSettings() {
ImGui::EndTable();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("MIDI output settings")) {
ImGui::Text("Output mode:");
if (ImGui::RadioButton("Off (use for TX81Z)",settings.midiOutMode==0)) {
settings.midiOutMode=0;
}
if (ImGui::RadioButton("Melodic",settings.midiOutMode==1)) {
settings.midiOutMode=1;
}
/*
if (ImGui::RadioButton("Light Show (use for Launchpad)",settings.midiOutMode==2)) {
settings.midiOutMode=2;
}*/
bool midiOutClockB=settings.midiOutClock;
if (ImGui::Checkbox("Send MIDI clock",&midiOutClockB)) {
settings.midiOutClock=midiOutClockB;
}
ImGui::TreePop();
}
}
@ -2314,6 +2334,8 @@ void FurnaceGUI::syncSettings() {
settings.channelFont=e->getConfInt("channelFont",1);
settings.channelTextCenter=e->getConfInt("channelTextCenter",1);
settings.maxRecentFile=e->getConfInt("maxRecentFile",10);
settings.midiOutClock=e->getConfInt("midiOutClock",0);
settings.midiOutMode=e->getConfInt("midiOutMode",1);
clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96);
@ -2415,6 +2437,8 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.channelFont,0,1);
clampSetting(settings.channelTextCenter,0,1);
clampSetting(settings.maxRecentFile,0,30);
clampSetting(settings.midiOutClock,0,1);
clampSetting(settings.midiOutMode,0,2);
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
if (settings.initialSys.size()<4) {
@ -2572,6 +2596,8 @@ void FurnaceGUI::commitSettings() {
e->setConf("channelFont",settings.channelFont);
e->setConf("channelTextCenter",settings.channelTextCenter);
e->setConf("maxRecentFile",settings.maxRecentFile);
e->setConf("midiOutClock",settings.midiOutClock);
e->setConf("midiOutMode",settings.midiOutMode);
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {