diff --git a/TODO.md b/TODO.md index 5bd4e8925..b0fc02d37 100644 --- a/TODO.md +++ b/TODO.md @@ -1,12 +1,13 @@ # to-do for 0.6pre1 -- rewrite the system name detection function anyway -- add another FM editor layout - add ability to move selection by dragging -- find and replace - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) # to-do for 0.6pre2 (as this requires new data structures) +- rewrite the system name detection function anyway + - this involves the addition of a new "system" field in the song (which solves the problem) + - songs made in older versions will go through old system name detection for compatibility - Game Boy envelope macro/sequence - volume commands should work on Game Boy +- ability to customize `OFF`, `===` and `REL` diff --git a/demos/Funky_Bubbles_OPL3.fur b/demos/Funky_Bubbles_OPL3.fur new file mode 100644 index 000000000..5f2ffd244 Binary files /dev/null and b/demos/Funky_Bubbles_OPL3.fur differ diff --git a/demos/going_up_a_step_at_time.fur b/demos/going_up_a_step_at_time.fur new file mode 100644 index 000000000..7d52d155a Binary files /dev/null and b/demos/going_up_a_step_at_time.fur differ diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index a5c5bad02..31a3e66ae 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -21,6 +21,26 @@ #include "../ta-log.h" #include "taAudio.h" +String sanitizePortName(const String& name) { +#if defined(_WIN32) + // remove port number + size_t namePos=name.rfind(' '); + if (namePos!=String::npos) { + return name.substr(0,namePos); + } + return name; +#elif defined(__linux__) + // remove port location + size_t namePos=name.rfind(' '); + if (namePos!=String::npos) { + return name.substr(0,namePos); + } + return name; +#else + return name; +#endif +} + // --- IN --- bool TAMidiInRtMidi::gather() { @@ -56,7 +76,7 @@ std::vector TAMidiInRtMidi::listDevices() { unsigned int count=port->getPortCount(); logD("got port count."); for (unsigned int i=0; igetPortName(i); + String name=sanitizePortName(port->getPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { @@ -75,8 +95,12 @@ bool TAMidiInRtMidi::openDevice(String name) { try { bool portOpen=false; unsigned int count=port->getPortCount(); + logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)==name) { + String portName=sanitizePortName(port->getPortName(i)); + logV("- %d: %s",i,portName); + if (portName==name) { + logD("opening port %d...",i); port->openPort(i); portOpen=true; break; @@ -184,8 +208,12 @@ bool TAMidiOutRtMidi::openDevice(String name) { try { bool portOpen=false; unsigned int count=port->getPortCount(); + logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)==name) { + String portName=sanitizePortName(port->getPortName(i)); + logV("- %d: %s",i,portName); + if (portName==name) { + logD("opening port %d...",i); port->openPort(i); portOpen=true; break; @@ -222,7 +250,7 @@ std::vector TAMidiOutRtMidi::listDevices() { try { unsigned int count=port->getPortCount(); for (unsigned int i=0; igetPortName(i); + String name=sanitizePortName(port->getPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { @@ -248,4 +276,4 @@ bool TAMidiOutRtMidi::quit() { port=NULL; } return true; -} \ No newline at end of file +} diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 85d50e668..48a078803 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -306,7 +306,7 @@ void DivPlatformBubSysWSG::reset() { for (int i=0; i<2; i++) { chan[i]=DivPlatformBubSysWSG::Channel(); chan[i].std.setEngine(parent); - chan[i].ws.setEngine(parent); + chan[i].ws.setEngine(parent,8); chan[i].ws.init(NULL,32,15,false); } if (dumpWrites) { diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index fbf914484..e6f730c26 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -677,6 +677,9 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { fm.channel[outChanMap[ch]].muted=mute; } int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2; + if (ch&1 && ch<12) { + if (chan[ch-1].fourOp) return; + } chan[ch].fourOp=(ops==4); update4OpMask=true; for (int i=0; i=120) { + return -61; // out of range note + } + return seek; +} + +bool checkCondition(int mode, int arg, int argMax, int val, bool noteMode=false) { + switch (mode) { + case GUI_QUERY_IGNORE: + return true; + break; + case GUI_QUERY_MATCH: + return (val==arg); + break; + case GUI_QUERY_MATCH_NOT: + return (val!=-1 && val!=arg); + break; + case GUI_QUERY_RANGE: + return (val>=arg && val<=argMax); + break; + case GUI_QUERY_RANGE_NOT: + return (val!=-1 && (valargMax) && (!noteMode || val<120)); + break; + case GUI_QUERY_ANY: + return (val!=-1); + break; + case GUI_QUERY_NONE: + return (val==-1); + break; + } + return false; +} + +void FurnaceGUI::doFind() { + int firstOrder=0; + int lastOrder=e->curSubSong->ordersLen-1; + + if (curQueryRangeY==1 || curQueryRangeY==2) { + firstOrder=curOrder; + lastOrder=curOrder; + } + + int firstRow=0; + int lastRow=e->curSubSong->patLen-1; + + if (curQueryRangeY==1) { + firstRow=selStart.y; + lastRow=selEnd.y; + } + + int firstChan=0; + int lastChan=e->getTotalChannelCount()-1; + + if (curQueryRangeX) { + firstChan=curQueryRangeXMin; + lastChan=curQueryRangeXMax; + } + + curQueryResults.clear(); + + for (int i=firstOrder; i<=lastOrder; i++) { + for (int j=firstRow; j<=lastRow; j++) { + for (int k=firstChan; k<=lastChan; k++) { + DivPattern* p=e->curPat[k].getPattern(e->curOrders->ord[k][i],false); + bool matched=false; + for (FurnaceGUIFindQuery& l: curQuery) { + if (matched) break; + + if (!checkCondition(l.noteMode,l.note,l.noteMax,queryNote(p->data[j][0],p->data[j][1]),true)) continue; + if (!checkCondition(l.insMode,l.ins,l.insMax,p->data[j][2])) continue; + if (!checkCondition(l.volMode,l.vol,l.volMax,p->data[j][3])) continue; + + if (l.effectCount>0) { + bool notMatched=false; + switch (curQueryEffectPos) { + case 0: // no + for (int m=0; mcurPat[k].effectCols; n++) { + if (!checkCondition(l.effectMode[m],l.effect[m],l.effectMax[m],p->data[j][4+n*2])) continue; + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+n*2])) continue; + allGood=true; + break; + } + if (!allGood) { + notMatched=true; + break; + } + } + break; + case 1: { // lax + // locate first effect + int posOfFirst=-1; + for (int m=0; mcurPat[k].effectCols; m++) { + if (!checkCondition(l.effectMode[0],l.effect[0],l.effectMax[0],p->data[j][4+m*2])) continue; + if (!checkCondition(l.effectValMode[0],l.effectVal[0],l.effectValMax[0],p->data[j][5+m*2])) continue; + posOfFirst=m; + break; + } + if (posOfFirst<0) { + notMatched=true; + break; + } + // make sure we aren't too far to the right + if ((posOfFirst+l.effectCount)>e->curPat[k].effectCols) { + notMatched=true; + break; + } + // search from first effect location + for (int m=0; mdata[j][4+(m+posOfFirst)*2])) { + notMatched=true; + break; + } + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+(m+posOfFirst)*2])) { + notMatched=true; + break; + } + } + break; + } + case 2: // strict + int effectMax=l.effectCount; + if (effectMax>e->curPat[k].effectCols) { + notMatched=true; + } else { + for (int m=0; mdata[j][4+m*2])) { + notMatched=true; + break; + } + if (!checkCondition(l.effectValMode[m],l.effectVal[m],l.effectValMax[m],p->data[j][5+m*2])) { + notMatched=true; + break; + } + } + } + break; + } + if (notMatched) continue; + } + + matched=true; + } + if (matched) { + curQueryResults.push_back(FurnaceGUIQueryResult(e->getCurrentSubSong(),i,k,j)); + } + } + } + } + queryViewingResults=true; +} + +void FurnaceGUI::doReplace() { + doFind(); + queryViewingResults=false; + + bool* touched[DIV_MAX_CHANS]; + memset(touched,0,DIV_MAX_CHANS*sizeof(bool*)); + + for (FurnaceGUIQueryResult& i: curQueryResults) { + int patIndex=e->song.subsong[i.subsong]->orders.ord[i.x][i.order]; + DivPattern* p=e->song.subsong[i.subsong]->pat[i.x].getPattern(patIndex,true); + if (touched[i.x]==NULL) { + touched[i.x]=new bool[256*256]; + memset(touched[i.x],0,256*256*sizeof(bool)); + } + if (touched[i.x][(patIndex<<8)|i.y]) continue; + touched[i.x][(patIndex<<8)|i.y]=true; + if (queryReplaceNoteDo) { + switch (queryReplaceNoteMode) { + case GUI_QUERY_REPLACE_SET: + if (queryReplaceNote==130) { // macro release + p->data[i.y][0]=102; + p->data[i.y][1]=0; + } else if (queryReplaceNote==129) { // note release + p->data[i.y][0]=101; + p->data[i.y][1]=0; + } else if (queryReplaceNote==128) { // note off + p->data[i.y][0]=100; + p->data[i.y][1]=0; + } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { // note + p->data[i.y][0]=(queryReplaceNote+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((queryReplaceNote-1)/12); + } else { // invalid + p->data[i.y][0]=0; + p->data[i.y][1]=0; + } + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][0]<100) { + int note=queryNote(p->data[i.y][0],p->data[i.y][1]); + if (note>=-60 && note<120) { + note+=queryReplaceNote; + if (note<-60) note=-60; + if (note>119) note=119; + + p->data[i.y][0]=(note+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((note-1)/12); + } + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][0]<100) { + int note=queryNote(p->data[i.y][0],p->data[i.y][1]); + if (note>=-60 && note<120) { + note+=queryReplaceNote; + if (note<-60) { + while (note<-60) note+=180; + } else if (note>119) { + while (note>119) note-=180; + } + + p->data[i.y][0]=(note+60)%12; + if (p->data[i.y][0]==0) p->data[i.y][0]=12; + p->data[i.y][1]=(unsigned char)((note-1)/12); + } + } + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][0]=0; + p->data[i.y][1]=0; + break; + } + } + + if (queryReplaceInsDo) { + switch (queryReplaceInsMode) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][2]=queryReplaceIns; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][2]>=0) { + p->data[i.y][2]+=queryReplaceIns; + if (p->data[i.y][2]<0) p->data[i.y][2]=0; + if (p->data[i.y][2]>255) p->data[i.y][2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][2]>=0) p->data[i.y][2]=(p->data[i.y][2]+queryReplaceIns)&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][2]=-1; + break; + } + } + + if (queryReplaceVolDo) { + switch (queryReplaceVolMode) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][3]=queryReplaceVol; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][3]>=0) { + p->data[i.y][3]+=queryReplaceVol; + if (p->data[i.y][3]<0) p->data[i.y][3]=0; + if (p->data[i.y][3]>255) p->data[i.y][3]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][3]>=0) p->data[i.y][3]=(p->data[i.y][3]+queryReplaceVol)&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][3]=-1; + break; + } + } + + signed char effectOrder[8]; + memset(effectOrder,-1,8); + + switch (queryReplaceEffectPos) { + case 0: // clear + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + effectOrder[j]=j; + } + break; + case 1: { // replace matches + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + case 2: { // replace matches then free spaces + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]!=-1 || p->data[i.y][5+j*2]!=-1) { + effectOrder[placementIndex++]=j; + } + } + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + case 3: { // insert in free spaces + int placementIndex=0; + for (int j=0; jsong.subsong[i.subsong]->pat[i.x].effectCols; j++) { + if (p->data[i.y][4+j*2]==-1 && p->data[i.y][5+j*2]==-1) { + effectOrder[placementIndex++]=j; + } + } + break; + } + } + + for (int j=0; jdata[i.y][4+pos*2]=queryReplaceEffect[j]; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][4+pos*2]>=0) { + p->data[i.y][4+pos*2]+=queryReplaceEffect[j]; + if (p->data[i.y][4+pos*2]<0) p->data[i.y][4+pos*2]=0; + if (p->data[i.y][4+pos*2]>255) p->data[i.y][4+pos*2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][4+pos*2]>=0) p->data[i.y][4+pos*2]=(p->data[i.y][4+pos*2]+queryReplaceEffect[j])&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][4+pos*2]=-1; + break; + } + } + + if (queryReplaceEffectValDo[j]) { + switch (queryReplaceEffectValMode[j]) { + case GUI_QUERY_REPLACE_SET: + p->data[i.y][5+pos*2]=queryReplaceEffectVal[j]; + break; + case GUI_QUERY_REPLACE_ADD: + if (p->data[i.y][5+pos*2]>=0) { + p->data[i.y][5+pos*2]+=queryReplaceEffectVal[j]; + if (p->data[i.y][5+pos*2]<0) p->data[i.y][5+pos*2]=0; + if (p->data[i.y][5+pos*2]>255) p->data[i.y][5+pos*2]=255; + } + break; + case GUI_QUERY_REPLACE_ADD_OVERFLOW: + if (p->data[i.y][5+pos*2]>=0) p->data[i.y][5+pos*2]=(p->data[i.y][5+pos*2]+queryReplaceEffectVal[j])&0xff; + break; + case GUI_QUERY_REPLACE_CLEAR: + p->data[i.y][5+pos*2]=-1; + break; + } + } + } + } + + for (int i=0; i=120) { - i.note=0; - } - if (i.note==130) { - snprintf(tempID,1024,"REL"); - } else if (i.note==129) { - snprintf(tempID,1024,"==="); - } else if (i.note==128) { - snprintf(tempID,1024,"OFF"); - } else if (i.note>=-60 && i.note<120) { - snprintf(tempID,1024,"%s",noteNames[i.note+60]); + if (ImGui::BeginTabBar("FindOrReplace")) { + if (ImGui::BeginTabItem("Find")) { + if (queryViewingResults) { + if (!curQueryResults.empty()) { + ImVec2 avail=ImGui::GetContentRegionAvail(); + avail.y-=ImGui::GetFrameHeightWithSpacing(); + if (ImGui::BeginTable("FindResults",4,ImGuiTableFlags_Borders|ImGuiTableFlags_ScrollY,avail)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("order").x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("row").x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableSetupScrollFreeze(0,1); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("order"); + ImGui::TableNextColumn(); + ImGui::Text("row"); + ImGui::TableNextColumn(); + ImGui::Text("channel"); + ImGui::TableNextColumn(); + ImGui::Text("go"); + + int index=0; + for (FurnaceGUIQueryResult& i: curQueryResults) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (settings.orderRowsBase==1) { + ImGui::Text("%.2X",i.order); + } else { + ImGui::Text("%d",i.order); + } + ImGui::TableNextColumn(); + if (settings.patRowsBase==1) { + ImGui::Text("%.2X",i.y); + } else { + ImGui::Text("%d",i.y); + } + ImGui::TableNextColumn(); + ImGui::Text("%d (%s)",i.x+1,e->getChannelName(i.x)); + if (ImGui::TableNextColumn()) { + snprintf(tempID,1024,ICON_FA_CHEVRON_RIGHT "##_FR%d",index); + if (ImGui::Selectable(tempID)) { + e->changeSongP(i.subsong); + if (e->isPlaying()) { + followPattern=false; + } else { + e->setOrder(i.order); + } + curOrder=i.order; + cursor.xCoarse=i.x; + cursor.xFine=0; + cursor.y=i.y; + selStart=cursor; + selEnd=cursor; + demandScrollX=true; + updateScroll(cursor.y); + nextWindow=GUI_WINDOW_PATTERN; + } + } + index++; + } + ImGui::EndTable(); + } } else { - snprintf(tempID,1024,"???"); - i.note=0; + ImGui::Text("no matches found!"); } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##NN1",tempID)) { - for (int j=0; j<180; j++) { - snprintf(tempID,1024,"%s",noteNames[j]); - if (ImGui::Selectable(tempID,i.note==(j-60))) { - i.note=j-60; - } - } - if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { - if (ImGui::Selectable("OFF",i.note==128)) { - i.note=128; - } - if (ImGui::Selectable("===",i.note==129)) { - i.note=129; - } - if (ImGui::Selectable("REL",i.note==130)) { - i.note=130; - } - } - ImGui::EndCombo(); + if (ImGui::Button("Back")) { + queryViewingResults=false; } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.noteMode)) { - if (i.noteMax<-60 || i.noteMax>=120) { - i.noteMax=0; - } - if (i.noteMax>=-60 && i.noteMax<120) { - snprintf(tempID,1024,"%s",noteNames[i.noteMax+60]); - } else { - snprintf(tempID,1024,"???"); - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##NN2",tempID)) { - for (int j=0; j<180; j++) { - snprintf(tempID,1024,"%s",noteNames[j]); - if (ImGui::Selectable(tempID,i.noteMax==(j-60))) { - i.noteMax=j-60; + } else { + for (FurnaceGUIFindQuery& i: curQuery) { + ImGui::PushID(index+0x100); + if (ImGui::BeginTable("FindRep",4,ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.25); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Note"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NCondition",&i.noteMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.noteMode)) { + if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=120) { + i.note=0; + } + if (i.note==130) { + snprintf(tempID,1024,"REL"); + } else if (i.note==129) { + snprintf(tempID,1024,"==="); + } else if (i.note==128) { + snprintf(tempID,1024,"OFF"); + } else if (i.note>=-60 && i.note<120) { + snprintf(tempID,1024,"%s",noteNames[i.note+60]); + } else { + snprintf(tempID,1024,"???"); + i.note=0; + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##NN1",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,i.note==(j-60))) { + i.note=j-60; + } + } + if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { + if (ImGui::Selectable("OFF",i.note==128)) { + i.note=128; + } + if (ImGui::Selectable("===",i.note==129)) { + i.note=129; + } + if (ImGui::Selectable("REL",i.note==130)) { + i.note=130; + } + } + ImGui::EndCombo(); + } + } + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.noteMode)) { + if (i.noteMax<-60 || i.noteMax>=120) { + i.noteMax=0; + } + if (i.noteMax>=-60 && i.noteMax<120) { + snprintf(tempID,1024,"%s",noteNames[i.noteMax+60]); + } else { + snprintf(tempID,1024,"???"); + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##NN2",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,i.noteMax==(j-60))) { + i.noteMax=j-60; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Ins"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.ins); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.ins==j)) { - i.ins=j; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Ins"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.insMode)) { + snprintf(tempID,1024,"%.2X",i.ins); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("II1",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.ins==j)) { + i.ins=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.insMax); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.insMax==j)) { - i.insMax=j; + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.insMode)) { + snprintf(tempID,1024,"%.2X",i.insMax); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("II2",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.insMax==j)) { + i.insMax=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Volume"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.vol); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.vol==j)) { - i.vol=j; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Volume"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); + ImGui::TableNextColumn(); + if (FIRST_VISIBLE(i.volMode)) { + snprintf(tempID,1024,"%.2X",i.vol); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("VV1",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.vol==j)) { + i.vol=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.volMax); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.volMax==j)) { - i.volMax=j; + ImGui::TableNextColumn(); + if (SECOND_VISIBLE(i.volMode)) { + snprintf(tempID,1024,"%.2X",i.volMax); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("VV2",tempID)) { + for (int j=0; j<256; j++) { + snprintf(tempID,1024,"%.2X",j); + if (ImGui::Selectable(tempID,i.volMax==j)) { + i.volMax=j; + } + } + ImGui::EndCombo(); + } } - } - ImGui::EndCombo(); - } - } - for (int j=0; j0) { + if (ImGui::Button("Remove effect")) { + i.effectCount--; + } + } + ImGui::EndTable(); + } + ImGui::PopID(); + index++; + } + if (eraseIndex>=0) { + curQuery.erase(curQuery.begin()+eraseIndex); + } + if (ImGui::Button(ICON_FA_PLUS "##AddQuery")) { + curQuery.push_back(FurnaceGUIFindQuery()); + } + + if (ImGui::BeginTable("QueryLimits",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::Text("Search range:"); + + if (ImGui::RadioButton("Song",curQueryRangeY==0)) { + curQueryRangeY=0; + } + if (ImGui::RadioButton("Selection",curQueryRangeY==1)) { + curQueryRangeY=1; + } + if (ImGui::RadioButton("Pattern",curQueryRangeY==2)) { + curQueryRangeY=2; + } + + ImGui::TableNextColumn(); + ImGui::Checkbox("Confine to channels",&curQueryRangeX); + + ImGui::BeginDisabled(!curQueryRangeX); + snprintf(tempID,1024,"%d: %s",curQueryRangeXMin+1,e->getChannelName(curQueryRangeXMin)); + if (ImGui::BeginCombo("From",tempID)) { + for (int i=0; igetTotalChannelCount(); i++) { + snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); + if (ImGui::Selectable(tempID,curQueryRangeXMin==i)) { + curQueryRangeXMin=i; + } + } + ImGui::EndCombo(); + } + + snprintf(tempID,1024,"%d: %s",curQueryRangeXMax+1,e->getChannelName(curQueryRangeXMax)); + if (ImGui::BeginCombo("To",tempID)) { + for (int i=0; igetTotalChannelCount(); i++) { + snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); + if (ImGui::Selectable(tempID,curQueryRangeXMax==i)) { + curQueryRangeXMax=i; + } + } + ImGui::EndCombo(); + } + ImGui::EndDisabled(); + + ImGui::TableNextColumn(); + ImGui::Text("Match effect position:"); + + if (ImGui::RadioButton("No",curQueryEffectPos==0)) { + curQueryEffectPos=0; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects regardless of position."); + } + if (ImGui::RadioButton("Lax",curQueryEffectPos==1)) { + curQueryEffectPos=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects only if they appear in-order."); + } + if (ImGui::RadioButton("Strict",curQueryEffectPos==2)) { + curQueryEffectPos=2; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("match effects only if they appear exactly as specified."); + } + + ImGui::EndTable(); + } + + if (ImGui::Button("Find")) { + doFind(); + } + } + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Replace")) { + if (ImGui::BeginTable("QueryReplace",3,ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Effect"); + ImGui::Checkbox("Note",&queryReplaceNoteDo); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceNoteDo); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NRMode",&queryReplaceNoteMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX); - ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.effectMode[j])) { - snprintf(tempID,1024,"%.2X",i.effect[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EE1",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effect[j]==k)) { - i.effect[j]=k; + if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { + if (queryReplaceNote==130) { + snprintf(tempID,1024,"REL"); + } else if (queryReplaceNote==129) { + snprintf(tempID,1024,"==="); + } else if (queryReplaceNote==128) { + snprintf(tempID,1024,"OFF"); + } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { + snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]); + } else { + snprintf(tempID,1024,"???"); + queryReplaceNote=0; + } + if (ImGui::BeginCombo("##NRValueC",tempID)) { + for (int j=0; j<180; j++) { + snprintf(tempID,1024,"%s",noteNames[j]); + if (ImGui::Selectable(tempID,queryReplaceNote==(j-60))) { + queryReplaceNote=j-60; } } + if (ImGui::Selectable("OFF",queryReplaceNote==128)) { + queryReplaceNote=128; + } + if (ImGui::Selectable("===",queryReplaceNote==129)) { + queryReplaceNote=129; + } + if (ImGui::Selectable("REL",queryReplaceNote==130)) { + queryReplaceNote=130; + } ImGui::EndCombo(); } - } - ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.effectMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectMax[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EE2",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effectMax[j]==k)) { - i.effectMax[j]=k; - } - } - ImGui::EndCombo(); + } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) { + if (queryReplaceNote<-180) queryReplaceNote=-180; + if (queryReplaceNote>180) queryReplaceNote=180; } } - + ImGui::EndDisabled(); + ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Value"); + ImGui::Checkbox("Ins",&queryReplaceInsDo); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceInsDo); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##IRMode",&queryReplaceInsMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX); + if (queryReplaceInsMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##IRValueH",ImGuiDataType_S32,&queryReplaceIns,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceIns<0) queryReplaceIns=0; + if (queryReplaceIns>255) queryReplaceIns=255; + } + } else if (queryReplaceInsMode==GUI_QUERY_REPLACE_ADD || queryReplaceInsMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##IRValue",&queryReplaceIns,1,12)) { + if (queryReplaceIns<-255) queryReplaceIns=-255; + if (queryReplaceIns>255) queryReplaceIns=255; + } + } + ImGui::EndDisabled(); + + ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (FIRST_VISIBLE(i.effectValMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectVal[j]); + ImGui::Checkbox("Volume",&queryReplaceVolDo); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceVolDo); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##VRMode",&queryReplaceVolMode,queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceVolMode==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##VRValueH",ImGuiDataType_S32,&queryReplaceVol,&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceVol<0) queryReplaceVol=0; + if (queryReplaceVol>255) queryReplaceVol=255; + } + } else if (queryReplaceVolMode==GUI_QUERY_REPLACE_ADD || queryReplaceVolMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##VRValue",&queryReplaceVol,1,12)) { + if (queryReplaceVol<-255) queryReplaceVol=-255; + if (queryReplaceVol>255) queryReplaceVol=255; + } + } + ImGui::EndDisabled(); + + for (int i=0; i255) queryReplaceEffect[i]=255; } - ImGui::EndCombo(); + } else if (queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffect[i],1,12)) { + if (queryReplaceEffect[i]<-255) queryReplaceEffect[i]=-255; + if (queryReplaceEffect[i]>255) queryReplaceEffect[i]=255; + } + } + ImGui::EndDisabled(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("Value",&queryReplaceEffectValDo[i]); + ImGui::TableNextColumn(); + ImGui::BeginDisabled(!queryReplaceEffectValDo[i]); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) { + if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) { + if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) { + if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) { + if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255; + if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255; + } + } + ImGui::EndDisabled(); + + + ImGui::PopID(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + if (queryReplaceEffectCount<8) { + if (ImGui::Button("Add effect")) { + queryReplaceEffectCount++; } } ImGui::TableNextColumn(); - if (SECOND_VISIBLE(i.effectValMode[j])) { - snprintf(tempID,1024,"%.2X",i.effectValMax[j]); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("EV2",tempID)) { - for (int k=0; k<256; k++) { - snprintf(tempID,1024,"%.2X",k); - if (ImGui::Selectable(tempID,i.effectValMax[j]==k)) { - i.effectValMax[j]=k; - } - } - ImGui::EndCombo(); + if (queryReplaceEffectCount>0) { + if (ImGui::Button("Remove effect")) { + queryReplaceEffectCount--; } } - ImGui::PopID(); + ImGui::EndTable(); } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - if (ImGui::Button(ICON_FA_MINUS "##DelQuery")) { - eraseIndex=index; + ImGui::Text("Effect replace mode:"); + if (ImGui::RadioButton("Clear effects",queryReplaceEffectPos==0)) { + queryReplaceEffectPos=0; } - ImGui::TableNextColumn(); - if (i.effectCount<8) { - if (ImGui::Button("Add effect")) { - i.effectCount++; - } + if (ImGui::RadioButton("Replace matches only",queryReplaceEffectPos==1)) { + queryReplaceEffectPos=1; } - ImGui::TableNextColumn(); - if (i.effectCount>0) { - if (ImGui::Button("Remove effect")) { - i.effectCount--; - } + if (ImGui::RadioButton("Replace matches, then free spaces",queryReplaceEffectPos==2)) { + queryReplaceEffectPos=2; } - ImGui::PopID(); - ImGui::EndTable(); - } - index++; - } - if (ImGui::Button("Find")) { - - } - ImGui::SameLine(); - if (eraseIndex>=0) { - curQuery.erase(curQuery.begin()+eraseIndex); - } - if (ImGui::Button(ICON_FA_PLUS "##AddQuery")) { - curQuery.push_back(FurnaceGUIFindQuery()); - } - - if (ImGui::BeginTable("QueryLimits",2)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::Text("Search range:"); - - if (ImGui::RadioButton("Song",curQueryRangeY==0)) { - curQueryRangeY=0; - } - if (ImGui::RadioButton("Selection",curQueryRangeY==1)) { - curQueryRangeY=1; - } - if (ImGui::RadioButton("Pattern",curQueryRangeY==2)) { - curQueryRangeY=2; - } - - ImGui::TableNextColumn(); - ImGui::Checkbox("Confine to channels",&curQueryRangeX); - - ImGui::BeginDisabled(!curQueryRangeX); - snprintf(tempID,1024,"%d: %s",curQueryRangeXMin+1,e->getChannelName(curQueryRangeXMin)); - if (ImGui::BeginCombo("From",tempID)) { - for (int i=0; igetTotalChannelCount(); i++) { - snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); - if (ImGui::Selectable(tempID,curQueryRangeXMin==i)) { - curQueryRangeXMin=i; - } + if (ImGui::RadioButton("Insert in free spaces",queryReplaceEffectPos==3)) { + queryReplaceEffectPos=3; } - ImGui::EndCombo(); - } - - snprintf(tempID,1024,"%d: %s",curQueryRangeXMax+1,e->getChannelName(curQueryRangeXMax)); - if (ImGui::BeginCombo("To",tempID)) { - for (int i=0; igetTotalChannelCount(); i++) { - snprintf(tempID,1024,"%d: %s",i+1,e->getChannelName(i)); - if (ImGui::Selectable(tempID,curQueryRangeXMax==i)) { - curQueryRangeXMax=i; - } + if (ImGui::Button("Replace##QueryReplace")) { + doReplace(); } - ImGui::EndCombo(); + ImGui::EndTabItem(); } - ImGui::EndDisabled(); - - ImGui::Text("Match effect position:"); - - if (ImGui::RadioButton("No",curQueryEffectPos==0)) { - curQueryEffectPos=0; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects regardless of position."); - } - if (ImGui::RadioButton("Lax",curQueryEffectPos==1)) { - curQueryEffectPos=1; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects only if they appear in-order."); - } - if (ImGui::RadioButton("Strict",curQueryEffectPos==2)) { - curQueryEffectPos=2; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("match effects only if they appear exactly as specified."); - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Checkbox("From start",&curQueryFromStart); - ImGui::TableNextColumn(); - ImGui::Checkbox("Backwards",&curQueryBackwards); - - ImGui::EndTable(); - } - - if (ImGui::TreeNode("Replace")) { - if (ImGui::BeginTable("QueryReplace",3)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Note"); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Ins"); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Volume"); - - /*ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Effect"); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Value");*/ - - ImGui::EndTable(); - } - if (ImGui::Button("Replace##QueryReplace")) { - // TODO - } - ImGui::TreePop(); + ImGui::EndTabBar(); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_FIND; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index ed1805f7d..b982987c3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4431,6 +4431,26 @@ FurnaceGUI::FurnaceGUI(): wavePreviewLen(32), wavePreviewHeight(255), wavePreviewInit(true), + pgSys(0), + pgAddr(0), + pgVal(0), + curQueryRangeX(false), + curQueryBackwards(false), + curQueryRangeXMin(0), curQueryRangeXMax(0), + curQueryRangeY(0), + curQueryEffectPos(0), + queryReplaceEffectCount(0), + queryReplaceEffectPos(0), + queryReplaceNoteMode(0), + queryReplaceInsMode(0), + queryReplaceVolMode(0), + queryReplaceNote(0), + queryReplaceIns(0), + queryReplaceVol(0), + queryReplaceNoteDo(false), + queryReplaceInsDo(false), + queryReplaceVolDo(false), + queryViewingResults(false), wavePreviewOn(false), wavePreviewKey((SDL_Scancode)0), wavePreviewNote(0), @@ -4624,4 +4644,11 @@ FurnaceGUI::FurnaceGUI(): memset(pianoKeyHit,0,sizeof(float)*180); memset(pianoKeyPressed,0,sizeof(bool)*180); + + memset(queryReplaceEffectMode,0,sizeof(int)*8); + memset(queryReplaceEffectValMode,0,sizeof(int)*8); + memset(queryReplaceEffect,0,sizeof(int)*8); + memset(queryReplaceEffectVal,0,sizeof(int)*8); + memset(queryReplaceEffectDo,0,sizeof(bool)*8); + memset(queryReplaceEffectValDo,0,sizeof(bool)*8); } diff --git a/src/gui/gui.h b/src/gui/gui.h index 2ee6170aa..55ea989c8 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -818,6 +818,7 @@ enum FurnaceGUIFindQueryModes { enum FurnaceGUIFindQueryReplaceModes { GUI_QUERY_REPLACE_SET=0, GUI_QUERY_REPLACE_ADD, + GUI_QUERY_REPLACE_ADD_OVERFLOW, GUI_QUERY_REPLACE_CLEAR, GUI_QUERY_REPLACE_MAX @@ -855,6 +856,20 @@ struct FurnaceGUIFindQuery { } }; +struct FurnaceGUIQueryResult { + int subsong, order, x, y; + FurnaceGUIQueryResult(): + subsong(0), + order(0), + x(0), + y(0) {} + FurnaceGUIQueryResult(int ss, int o, int xPos, int yPos): + subsong(ss), + order(o), + x(xPos), + y(yPos) {} +}; + class FurnaceGUI { DivEngine* e; @@ -1170,11 +1185,31 @@ class FurnaceGUI { int pgSys, pgAddr, pgVal; std::vector curQuery; - bool curQueryRangeX, curQueryFromStart, curQueryBackwards; + std::vector curQueryResults; + bool curQueryRangeX, curQueryBackwards; int curQueryRangeXMin, curQueryRangeXMax; int curQueryRangeY; int curQueryEffectPos; + int queryReplaceEffectCount; + int queryReplaceEffectPos; + int queryReplaceNoteMode; + int queryReplaceInsMode; + int queryReplaceVolMode; + int queryReplaceEffectMode[8]; + int queryReplaceEffectValMode[8]; + int queryReplaceNote; + int queryReplaceIns; + int queryReplaceVol; + int queryReplaceEffect[8]; + int queryReplaceEffectVal[8]; + bool queryReplaceNoteDo; + bool queryReplaceInsDo; + bool queryReplaceVolDo; + bool queryReplaceEffectDo[8]; + bool queryReplaceEffectValDo[8]; + bool queryViewingResults; + struct ActiveNote { int chan; int note; @@ -1456,6 +1491,8 @@ class FurnaceGUI { void doExpand(int multiplier); void doUndo(); void doRedo(); + void doFind(); + void doReplace(); void editOptions(bool topMenu); void noteInput(int num, int key, int vol=-1); void valueInput(int num, bool direct=false, int target=-1); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 7d7fa050b..be09eb6d6 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1345,6 +1345,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { #define CENTER_VSLIDER \ ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5f*ImGui::GetContentRegionAvail().x-10.0f*dpiScale); +#define CENTER_TEXT_20(text) \ + ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(20.0f*dpiScale-ImGui::CalcTextSize(text).x)); + void FurnaceGUI::drawInsEdit() { if (nextWindow==GUI_WINDOW_INS_EDIT) { insEditOpen=true; @@ -2016,7 +2019,452 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } - } else { + } else if (settings.fmLayout>=4 && settings.fmLayout<=6) { // alternate + int columns=2; + switch (settings.fmLayout) { + case 4: // 2x2 + columns=2; + break; + case 5: // 1x4 + columns=1; + break; + case 6: // 4x1 + columns=opCount; + break; + } + char tempID[1024]; + ImVec2 oldPadding=ImGui::GetStyle().CellPadding; + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale)); + if (ImGui::BeginTable("KGE93BSIEO3NOWBDJZBA",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) { + for (int i=0; ifm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; + if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::PushID(fmt::sprintf("op%d",i).c_str()); + + // push colors + if (settings.separateFMColors) { + bool mod=true; + if (ins->type==DIV_INS_OPL_DRUMS) { + mod=false; + } else if (opCount==4) { + if (ins->type==DIV_INS_OPL) { + if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false; + } else { + if (opIsOutput[ins->fm.alg&7][i]) mod=false; + } + } else { + if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false; + } + if (mod) { + pushAccentColors( + uiColors[GUI_COLOR_FM_PRIMARY_MOD], + uiColors[GUI_COLOR_FM_SECONDARY_MOD], + uiColors[GUI_COLOR_FM_BORDER_MOD], + uiColors[GUI_COLOR_FM_BORDER_SHADOW_MOD] + ); + } else { + pushAccentColors( + uiColors[GUI_COLOR_FM_PRIMARY_CAR], + uiColors[GUI_COLOR_FM_SECONDARY_CAR], + uiColors[GUI_COLOR_FM_BORDER_CAR], + uiColors[GUI_COLOR_FM_BORDER_SHADOW_CAR] + ); + } + } + + ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + if (ins->type==DIV_INS_OPL_DRUMS) { + snprintf(tempID,1024,"%s",oplDrumNames[i]); + } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { + if (i==1) { + snprintf(tempID,1024,"Envelope 2 (kick only)"); + } else { + snprintf(tempID,1024,"Envelope"); + } + } else { + snprintf(tempID,1024,"Operator %d",i+1); + } + CENTER_TEXT(tempID); + ImGui::TextUnformatted(tempID); + + float sliderHeight=200.0f*dpiScale; + float waveWidth=140.0*dpiScale; + float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*(ins->type==DIV_INS_OPLL?4.5f:5.5f); + + int maxTl=127; + if (ins->type==DIV_INS_OPLL) { + if (i==1) { + maxTl=15; + } else { + maxTl=63; + } + } + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { + maxTl=63; + } + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + + bool ssgOn=op.ssgEnv&8; + bool ksrOn=op.ksr; + bool vibOn=op.vib; + bool egtOn=op.egt; + bool susOn=op.sus; // yawn + unsigned char ssgEnv=op.ssgEnv&7; + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,oldPadding); + if (ImGui::BeginTable("opParams",4,ImGuiTableFlags_BordersInnerV)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,waveWidth); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + float textY=ImGui::GetCursorPosY(); + CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); + ImGui::TableNextColumn(); + if (ins->type==DIV_INS_FM) { + ImGui::Text("SSG-EG"); + } else { + ImGui::Text("Waveform"); + } + ImGui::TableNextColumn(); + ImGui::Text("Envelope"); + ImGui::TableNextColumn(); + CENTER_TEXT(FM_SHORT_NAME(FM_TL)); + ImGui::Text("TL"); + + // A/D/S/R + ImGui::TableNextColumn(); + + op.ar&=maxArDr; + P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); + + ImGui::SameLine(); + op.dr&=maxArDr; + float textX_DR=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); + + float textX_SL=0.0f; + if (settings.susPosition==0) { + ImGui::SameLine(); + op.sl&=15; + textX_SL=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + } + + float textX_D2R=0.0f; + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + ImGui::SameLine(); + op.d2r&=31; + textX_D2R=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); + } + + ImGui::SameLine(); + op.rr&=15; + float textX_RR=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); + + if (settings.susPosition==1) { + ImGui::SameLine(); + op.sl&=15; + textX_SL=ImGui::GetCursorPosX(); + P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); + } + + ImVec2 prevCurPos=ImGui::GetCursorPos(); + + // labels + ImGui::SetCursorPos(ImVec2(textX_DR,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_DR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_DR)); + + ImGui::SetCursorPos(ImVec2(textX_SL,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_SL)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); + + ImGui::SetCursorPos(ImVec2(textX_RR,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_RR)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + ImGui::SetCursorPos(ImVec2(textX_D2R,textY)); + CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); + } + + ImGui::SetCursorPos(prevCurPos); + + ImGui::TableNextColumn(); + switch (ins->type) { + case DIV_INS_FM: { + // SSG + ImGui::BeginDisabled(!ssgOn); + drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); + ImGui::EndDisabled(); + if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER + op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only for OPN family chips"); + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER + op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + } + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+3; + } rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + + break; + } + case DIV_INS_OPLL: + // waveform + drawWaveform(i==0?(ins->fm.ams&1):(ins->fm.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + + // params + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInner",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_EGS),&ssgOn)) { PARAMETER + op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); + } + + ImGui::EndTable(); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + break; + case DIV_INS_OPL: + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInner",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER + op.ksr=ksrOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER + op.vib=vibOn; + } + ImGui::TableNextColumn(); + if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER + op.sus=susOn; + } + + ImGui::EndTable(); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_KSL)); + P(CWSliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + break; + case DIV_INS_OPZ: { + // waveform + drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { + ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); + } + + // params + ImGui::Separator(); + if (egtOn) { + int block=op.dt; + int freqNum=(op.mult<<4)|(op.dvb&15); + ImGui::Text("Block"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImVec2 cursorAlign=ImGui::GetCursorPos(); + if (ImGui::InputInt("##Block",&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + op.dt=block; + } + + ImGui::Text("Freq"); + ImGui::SameLine(); + ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY())); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) { + if (freqNum<0) freqNum=0; + if (freqNum>255) freqNum=255; + op.mult=freqNum>>4; + op.dvb=freqNum&15; + } + } else { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-3; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+3; + } rightClickable + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Only on YM2151 (OPM)"); + } + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + break; + } + default: + break; + } + + ImGui::TableNextColumn(); + float envHeight=sliderHeight;//-ImGui::GetStyle().ItemSpacing.y*2.0f; + if (ins->type==DIV_INS_OPZ) { + envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f; + } + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type); + + if (ins->type==DIV_INS_OPZ) { + ImGui::Separator(); + if (ImGui::BeginTable("FMParamsInnerOPZ",2)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (!egtOn) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_FINE)); + P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable + } + + ImGui::TableNextColumn(); + bool amOn=op.am; + if (ImGui::Checkbox(FM_NAME(FM_AM),&amOn)) { PARAMETER + op.am=amOn; + } + ImGui::SameLine(); + if (ImGui::Checkbox("Fixed",&egtOn)) { PARAMETER + op.egt=egtOn; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_EGSHIFT)); + P(CWSliderScalar("##EGShift",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE,tempID)); rightClickable + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_REV)); + P(CWSliderScalar("##REV",ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN,tempID)); rightClickable + + ImGui::TableNextColumn(); + + + ImGui::EndTable(); + } + } + + ImGui::TableNextColumn(); + op.tl&=maxTl; + P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + + if (ins->type==DIV_INS_FM) { + CENTER_TEXT(FM_SHORT_NAME(FM_AM)); + ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); + bool amOn=op.am; + if (ImGui::Checkbox("##AM",&amOn)) { PARAMETER + op.am=amOn; + } + } + + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + if (settings.separateFMColors) { + popAccentColors(); + } + + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + } else { // classic int columns=2; switch (settings.fmLayout) { case 1: // 2x2 diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 9c7f53b94..8bee0f88c 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -25,6 +25,7 @@ const int _THREE=3; const int _SEVEN=7; const int _TEN=10; const int _FIFTEEN=15; +const int _SIXTEEN=16; const int _THIRTY_ONE=31; const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index c6b13b9af..98c6c34ff 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -27,6 +27,7 @@ extern const int _THREE; extern const int _SEVEN; extern const int _TEN; extern const int _FIFTEEN; +extern const int _SIXTEEN; extern const int _THIRTY_ONE; extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index ea1d92748..da3b0f277 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1117,6 +1117,15 @@ void FurnaceGUI::drawSettings() { if (ImGui::RadioButton("Compact (4x1)##fml3",settings.fmLayout==3)) { settings.fmLayout=3; } + if (ImGui::RadioButton("Alternate (2x2)##fml4",settings.fmLayout==4)) { + settings.fmLayout=4; + } + if (ImGui::RadioButton("Alternate (1x4)##fml5",settings.fmLayout==5)) { + settings.fmLayout=5; + } + if (ImGui::RadioButton("Alternate (4x1)##fml5",settings.fmLayout==6)) { + settings.fmLayout=6; + } ImGui::Text("Position of Sustain in FM editor:"); if (ImGui::RadioButton("Between Decay and Sustain Rate##susp0",settings.susPosition==0)) { @@ -2077,7 +2086,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.roundedMenus,0,1); clampSetting(settings.loadJapanese,0,1); clampSetting(settings.loadChinese,0,1); - clampSetting(settings.fmLayout,0,3); + clampSetting(settings.fmLayout,0,6); clampSetting(settings.susPosition,0,1); clampSetting(settings.effectCursorDir,0,2); clampSetting(settings.cursorPastePos,0,1); diff --git a/src/main.cpp b/src/main.cpp index 079058528..8c90c7c8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,7 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include +#include #include #else #include @@ -243,6 +244,12 @@ void initParams() { // TODO: add crash log int main(int argc, char** argv) { initLog(); +#ifdef _WIN32 + HRESULT coResult=CoInitializeEx(NULL,COINIT_MULTITHREADED); + if (coResult!=S_OK) { + logE("CoInitializeEx failed!"); + } +#endif #if !(defined(__APPLE__) || defined(_WIN32) || defined(ANDROID)) // workaround for Wayland HiDPI issue if (getenv("SDL_VIDEODRIVER")==NULL) { @@ -446,6 +453,12 @@ int main(int argc, char** argv) { logI("stopping engine."); e.quit(); + +#ifdef _WIN32 + if (coResult==S_OK || coResult==S_FALSE) { + CoUninitialize(); + } +#endif return 0; }