multiple instrument playback, part 1

not implemented for MIDI yet
This commit is contained in:
tildearrow 2025-10-31 19:36:13 -05:00
parent 08a27be76f
commit 5b145b7121
15 changed files with 276 additions and 34 deletions

View file

@ -868,6 +868,38 @@ void FurnaceGUI::autoDetectSystem() {
}
}
void FurnaceGUI::setCurIns(int newIns) { curIns=newIns;
memset(multiIns,-1,7*sizeof(int));
}
bool FurnaceGUI::setMultiIns(int newIns) {
// set primary instrument if not set
if (curIns<0) {
setCurIns(newIns);
return true;
}
// don't allow using the primary instrument twice
if (curIns==newIns) return false;
for (int i=0; i<7; i++) {
// don't allow using an instrument more than once
if (multiIns[i]==newIns) return false;
// if slot is empty, assign instrument to it
if (multiIns[i]==-1) {
multiIns[i]=newIns;
return true;
}
}
// no more slots available
return false;
}
bool FurnaceGUI::isMultiInsActive() {
for (int i=0; i<7; i++) {
if (multiIns[i]>=0) return true;
}
return false;
}
void FurnaceGUI::updateROMExportAvail() {
memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX);
romExportExists=false;
@ -1333,6 +1365,11 @@ void FurnaceGUI::previewNote(int refChan, int note, bool autoNote) {
e->setMidiBaseChan(refChan);
e->synchronized([this,note]() {
if (!e->autoNoteOn(-1,curIns,note)) failedNoteOn=true;
for (int mi=0; mi<7; mi++) {
if (multiIns[mi]!=-1) {
e->autoNoteOn(-1,multiIns[mi],note,-1,multiInsTranspose[mi]);
}
}
});
}
@ -1469,7 +1506,7 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
}
}
if (settings.absorbInsInput) {
curIns=pat->newData[y][target];
setCurIns(pat->newData[y][target]);
wavePreviewInit=true;
updateFMPreview=true;
}
@ -1977,7 +2014,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
if (curIns!=-2) {
prevIns=curIns;
}
curIns=-2;
setCurIns(-2);
}
}
for (DivInstrument* i: instruments) delete i;
@ -3858,6 +3895,7 @@ bool FurnaceGUI::loop() {
DECLARE_METRIC(effectList)
DECLARE_METRIC(userPresets)
DECLARE_METRIC(refPlayer)
DECLARE_METRIC(multiInsSetup)
DECLARE_METRIC(popup)
#ifdef IS_MOBILE
@ -4045,7 +4083,7 @@ bool FurnaceGUI::loop() {
instrumentCount=e->addInstrumentPtr(i);
}
if (instrumentCount>=0 && settings.selectAssetOnLoad) {
curIns=instrumentCount-1;
setCurIns(instrumentCount-1);
}
nextWindow=GUI_WINDOW_INS_LIST;
MARK_MODIFIED;
@ -4239,8 +4277,8 @@ bool FurnaceGUI::loop() {
break;
case TA_MIDI_PROGRAM:
if (midiMap.programChange && !(midiMap.directChannel && midiMap.directProgram)) {
curIns=msg.data[0];
if (curIns>=(int)e->song.ins.size()) curIns=e->song.ins.size()-1;
setCurIns(msg.data[0]);
if (curIns>=(int)e->song.ins.size()) setCurIns(e->song.ins.size()-1);
wavePreviewInit=true;
updateFMPreview=true;
}
@ -4480,6 +4518,7 @@ bool FurnaceGUI::loop() {
IMPORT_CLOSE(csPlayerOpen);
IMPORT_CLOSE(userPresetsOpen);
IMPORT_CLOSE(refPlayerOpen);
IMPORT_CLOSE(multiInsSetupOpen);
} else if (pendingLayoutImportStep==1) {
// let the UI settle
} else if (pendingLayoutImportStep==2) {
@ -4852,6 +4891,7 @@ bool FurnaceGUI::loop() {
if (ImGui::MenuItem(_("play/edit controls"),BIND_FOR(GUI_ACTION_WINDOW_EDIT_CONTROLS),editControlsOpen)) editControlsOpen=!editControlsOpen;
if (ImGui::MenuItem(_("piano/input pad"),BIND_FOR(GUI_ACTION_WINDOW_PIANO),pianoOpen)) pianoOpen=!pianoOpen;
if (ImGui::MenuItem(_("reference music player"),BIND_FOR(GUI_ACTION_WINDOW_REF_PLAYER),refPlayerOpen)) refPlayerOpen=!refPlayerOpen;
if (ImGui::MenuItem(_("multi-ins setup"),BIND_FOR(GUI_ACTION_WINDOW_MULTI_INS_SETUP),multiInsSetupOpen)) multiInsSetupOpen=!multiInsSetupOpen;
if (spoilerOpen) if (ImGui::MenuItem(_("spoiler"),NULL,spoilerOpen)) spoilerOpen=!spoilerOpen;
ImGui::EndMenu();
@ -5052,6 +5092,7 @@ bool FurnaceGUI::loop() {
MEASURE(effectList,drawEffectList());
MEASURE(userPresets,drawUserPresets());
MEASURE(refPlayer,drawRefPlayer());
MEASURE(multiInsSetup,drawMultiInsSetup());
MEASURE(patManager,drawPatManager());
} else {
@ -5098,6 +5139,7 @@ bool FurnaceGUI::loop() {
MEASURE(effectList,drawEffectList());
MEASURE(userPresets,drawUserPresets());
MEASURE(refPlayer,drawRefPlayer());
MEASURE(multiInsSetup,drawMultiInsSetup());
}
@ -5167,7 +5209,7 @@ bool FurnaceGUI::loop() {
}
}
} else {
curIns=prevIns;
setCurIns(prevIns);
wavePreviewInit=true;
updateFMPreview=true;
}
@ -5673,7 +5715,7 @@ bool FurnaceGUI::loop() {
MARK_MODIFIED;
}
if (instrumentCount>=0 && settings.selectAssetOnLoad) {
curIns=instrumentCount-1;
setCurIns(instrumentCount-1);
}
}
}
@ -6550,7 +6592,7 @@ bool FurnaceGUI::loop() {
e->lockEngine([this]() {
e->song.clearInstruments();
});
curIns=-1;
setCurIns(-1);
MARK_MODIFIED;
ImGui::CloseCurrentPopup();
}
@ -6755,7 +6797,7 @@ bool FurnaceGUI::loop() {
strncpy(temp,insTypes[i][0],1023);
if (ImGui::MenuItem(temp)) {
// create ins
curIns=e->addInstrument(-1,i);
setCurIns(e->addInstrument(-1,i));
if (curIns==-1) {
showError(_("too many instruments!"));
} else {
@ -8249,6 +8291,7 @@ void FurnaceGUI::syncState() {
spoilerOpen=e->getConfBool("spoilerOpen",false);
userPresetsOpen=e->getConfBool("userPresetsOpen",false);
refPlayerOpen=e->getConfBool("refPlayerOpen",false);
multiInsSetupOpen=e->getConfBool("multiInsSetupOpen",false);
insListDir=e->getConfBool("insListDir",false);
waveListDir=e->getConfBool("waveListDir",false);
@ -8414,6 +8457,7 @@ void FurnaceGUI::commitState(DivConfig& conf) {
conf.set("spoilerOpen",spoilerOpen);
conf.set("userPresetsOpen",userPresetsOpen);
conf.set("refPlayerOpen",refPlayerOpen);
conf.set("multiInsSetupOpen",multiInsSetupOpen);
// commit dir state
conf.set("insListDir",insListDir);
@ -8769,6 +8813,7 @@ FurnaceGUI::FurnaceGUI():
curPaletteChoice(0),
curPaletteType(0),
soloTimeout(0.0f),
mobileMultiInsToggle(false),
purgeYear(2021),
purgeMonth(4),
purgeDay(4),
@ -8818,6 +8863,7 @@ FurnaceGUI::FurnaceGUI():
cvOpen(false),
userPresetsOpen(false),
refPlayerOpen(false),
multiInsSetupOpen(false),
cvNotSerious(false),
shortIntro(false),
insListDir(false),
@ -9285,6 +9331,9 @@ FurnaceGUI::FurnaceGUI():
memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX);
memset(multiIns,-1,7*sizeof(int));
memset(multiInsTranspose,0,7*sizeof(int));
strncpy(noteOffLabel,"OFF",32);
strncpy(noteRelLabel,"===",32);
strncpy(macroRelLabel,"REL",32);