Merge branch 'master' into SID3

This commit is contained in:
tildearrow 2024-09-13 23:46:03 -05:00
commit 47f36f99d9
188 changed files with 5790 additions and 546 deletions

View file

@ -300,6 +300,7 @@ const char* aboutLine[]={
_N("PowerNoise emulator by scratchminer"),
_N("ep128emu by Istvan Varga"),
_N("NDS sound emulator by cam900"),
_N("openMSX YMF278 emulator (modified version) by the openMSX developers"),
_N("SID2 emulator by LTVA (modification of reSID emulator)"),
_N("SID3 emulator by LTVA"),
"",

View file

@ -69,6 +69,9 @@ void FurnaceGUI::startSelection(int xCoarse, int xFine, int y, bool fullRow) {
selStart.y=y;
selEnd.y=y;
} else {
if (xCoarse!=cursor.xCoarse || y!=cursor.y) {
makeCursorUndo();
}
cursor.xCoarse=xCoarse;
cursor.xFine=xFine;
cursor.y=y;
@ -208,6 +211,9 @@ void FurnaceGUI::finishSelection() {
}
void FurnaceGUI::moveCursor(int x, int y, bool select) {
if (y>=editStepCoarse || y<=-editStepCoarse || x<=-5 || x>=5 ) {
makeCursorUndo();
}
if (!select) {
finishSelection();
}
@ -326,6 +332,7 @@ void FurnaceGUI::moveCursor(int x, int y, bool select) {
}
void FurnaceGUI::moveCursorPrevChannel(bool overflow) {
makeCursorUndo();
finishSelection();
curNibble=false;
@ -354,6 +361,7 @@ void FurnaceGUI::moveCursorPrevChannel(bool overflow) {
}
void FurnaceGUI::moveCursorNextChannel(bool overflow) {
makeCursorUndo();
finishSelection();
curNibble=false;
@ -382,6 +390,7 @@ void FurnaceGUI::moveCursorNextChannel(bool overflow) {
}
void FurnaceGUI::moveCursorTop(bool select) {
makeCursorUndo();
if (!select) {
finishSelection();
}
@ -403,6 +412,7 @@ void FurnaceGUI::moveCursorTop(bool select) {
}
void FurnaceGUI::moveCursorBottom(bool select) {
makeCursorUndo();
if (!select) {
finishSelection();
}

View file

@ -51,6 +51,7 @@
#include "../engine/platform/pcmdac.h"
#include "../engine/platform/k007232.h"
#include "../engine/platform/ga20.h"
#include "../engine/platform/supervision.h"
#include "../engine/platform/sm8521.h"
#include "../engine/platform/pv1000.h"
#include "../engine/platform/k053260.h"

View file

@ -731,6 +731,25 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("result: %.0f%%",realVol*100.0f);
ImGui::TreePop();
}
if (ImGui::TreeNode("Cursor Undo Debug")) {
auto DrawSpot=[&](const CursorJumpPoint& spot) {
ImGui::Text("[%d:%d] <%d:%d, %d>", spot.subSong, spot.order, spot.point.xCoarse, spot.point.xFine, spot.point.y);
};
if (ImGui::BeginChild("##CursorUndoDebugChild", ImVec2(0, 300), true)) {
if (ImGui::BeginTable("##CursorUndoDebug", 2, ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) {
for (size_t row=0; row<MAX(cursorUndoHist.size(),cursorRedoHist.size()); ++row) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (row<cursorUndoHist.size()) DrawSpot(cursorUndoHist[cursorUndoHist.size()-row-1]);
ImGui::TableNextColumn();
if (row<cursorRedoHist.size()) DrawSpot(cursorRedoHist[cursorRedoHist.size()-row-1]);
}
ImGui::EndTable();
}
}
ImGui::EndChild();
ImGui::TreePop();
}
if (ImGui::TreeNode("User Interface")) {
if (ImGui::Button("Inspect")) {
inspectorOpen=!inspectorOpen;

View file

@ -680,10 +680,15 @@ void FurnaceGUI::doAction(int what) {
latchTarget=0;
latchNibble=false;
break;
case GUI_ACTION_PAT_ABSORB_INSTRUMENT: {
case GUI_ACTION_PAT_ABSORB_INSTRUMENT:
doAbsorbInstrument();
break;
}
case GUI_ACTION_PAT_CURSOR_UNDO:
doCursorUndo();
break;
case GUI_ACTION_PAT_CURSOR_REDO:
doCursorRedo();
break;
case GUI_ACTION_INS_LIST_ADD:
if (settings.insTypeMenu) {

View file

@ -678,6 +678,7 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
if (readClipboard) {
if (settings.cursorPastePos) {
makeCursorUndo();
cursor.y=j;
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
selStart=cursor;
@ -1220,6 +1221,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
if (readClipboard) {
if (settings.cursorPastePos) {
makeCursorUndo();
cursor.y=j;
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
selStart=cursor;
@ -1846,8 +1848,11 @@ void FurnaceGUI::doAbsorbInstrument() {
}
// absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of
// notes will result in an octave number equal to the previous note).
if (!foundOctave && pat->data[i][0] != 0) {
// notes will result in an octave number equal to the previous note). make sure to
// skip "special note values" like OFF/REL/=== and "none", since there won't be valid
// octave values
unsigned char note=pat->data[i][0];
if (!foundOctave && note!=0 && note!=100 && note!=101 && note!=102) {
foundOctave=true;
// decode octave data (was signed cast to unsigned char)
@ -2058,3 +2063,52 @@ void FurnaceGUI::doRedo() {
redoHist.pop_back();
}
CursorJumpPoint FurnaceGUI::getCurrentCursorJumpPoint() {
return CursorJumpPoint(cursor, curOrder, e->getCurrentSubSong());
}
void FurnaceGUI::applyCursorJumpPoint(const CursorJumpPoint& spot) {
cursor=spot.point;
curOrder=MIN(e->curSubSong->ordersLen-1, spot.order);
e->setOrder(curOrder);
e->changeSongP(spot.subSong);
if (!settings.cursorMoveNoScroll) {
updateScroll(cursor.y);
}
}
void FurnaceGUI::makeCursorUndo() {
CursorJumpPoint spot = getCurrentCursorJumpPoint();
if (!cursorUndoHist.empty() && spot == cursorUndoHist.back()) return;
if (cursorUndoHist.size()>=settings.maxUndoSteps) cursorUndoHist.pop_front();
cursorUndoHist.push_back(spot);
// redo history no longer relevant, we've changed timeline
cursorRedoHist.clear();
}
void FurnaceGUI::doCursorUndo() {
if (cursorUndoHist.empty()) return;
// allow returning to current spot
if (cursorRedoHist.size()>=settings.maxUndoSteps) cursorRedoHist.pop_front();
cursorRedoHist.push_back(getCurrentCursorJumpPoint());
// apply spot
applyCursorJumpPoint(cursorUndoHist.back());
cursorUndoHist.pop_back();
}
void FurnaceGUI::doCursorRedo() {
if (cursorRedoHist.empty()) return;
// allow returning to current spot
if (cursorUndoHist.size()>=settings.maxUndoSteps) cursorUndoHist.pop_front();
cursorUndoHist.push_back(getCurrentCursorJumpPoint());
// apply spot
applyCursorJumpPoint(cursorRedoHist.back());
cursorRedoHist.pop_back();
}

View file

@ -560,6 +560,7 @@ void FurnaceGUI::drawFindReplace() {
if (ImGui::TableNextColumn()) {
snprintf(tempID,1024,ICON_FA_CHEVRON_RIGHT "##_FR%d",index);
if (ImGui::Selectable(tempID)) {
makeCursorUndo();
e->changeSongP(i.subsong);
if (e->isPlaying()) {
followPattern=false;

View file

@ -388,6 +388,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
setBit30=false;
macroLen++;
buf=0;
MARK_MODIFIED;
}
}
@ -424,6 +425,21 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
} \
}
bool FurnaceGUI::isCtrlWheelModifierHeld() const {
switch (settings.ctrlWheelModifier) {
case 0:
return ImGui::IsKeyDown(ImGuiMod_Ctrl) || ImGui::IsKeyDown(ImGuiMod_Super);
case 1:
return ImGui::IsKeyDown(ImGuiMod_Ctrl);
case 2:
return ImGui::IsKeyDown(ImGuiMod_Super);
case 3:
return ImGui::IsKeyDown(ImGuiMod_Alt);
default:
return false;
}
}
bool FurnaceGUI::CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) {
flags^=ImGuiSliderFlags_AlwaysClamp;
if (ImGui::SliderScalar(label,data_type,p_data,p_min,p_max,format,flags)) {
@ -993,11 +1009,6 @@ Pos=339,177\n\
Size=601,400\n\
Collapsed=0\n\
\n\
[Window][Rendering...]\n\
Pos=585,342\n\
Size=600,100\n\
Collapsed=0\n\
\n\
[Window][Export VGM##FileDialog]\n\
Pos=340,177\n\
Size=600,400\n\
@ -1216,6 +1227,7 @@ void FurnaceGUI::play(int row) {
memset(chanOscBright,0,DIV_MAX_CHANS*sizeof(float));
e->walkSong(loopOrder,loopRow,loopEnd);
memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS);
if (followPattern) makeCursorUndo();
if (!followPattern) e->setOrder(curOrder);
if (row>0) {
if (!e->playToRow(row)) {
@ -5859,7 +5871,8 @@ bool FurnaceGUI::loop() {
MEASURE_BEGIN(popup);
centerNextWindow(_("Rendering..."),canvasW,canvasH);
if (ImGui::BeginPopupModal(_("Rendering..."),NULL,ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove)) {
// ImGui::SetNextWindowSize(ImVec2(0.0f,0.0f));
if (ImGui::BeginPopupModal(_("Rendering..."),NULL,ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) {
// WHAT the HELL?!
WAKE_UP;
if (audioExportOptions.mode!=DIV_EXPORT_MODE_MANY_CHAN) {
@ -5875,35 +5888,32 @@ bool FurnaceGUI::loop() {
int curFile=0;
int* curFileLambda=&curFile;
if (e->isExporting()) {
e->lockEngine([this, progressLambda, curPosInRowsLambda, curFileLambda,
loopsLeftLambda, totalLoopsLambda] () {
int curRow=0; int curOrder=0;
e->getCurSongPos(curRow, curOrder); *curFileLambda=0;
e->getCurFileIndex(*curFileLambda);
*curPosInRowsLambda=curRow; for (int i=0; i<curOrder;
i++) {
*curPosInRowsLambda+=songOrdersLengths[i];}
if (!songHasSongEndCommand) {
e->getLoopsLeft(*loopsLeftLambda); e->getTotalLoops(*totalLoopsLambda); if ((*totalLoopsLambda)!=(*loopsLeftLambda)) //we are going 2nd, 3rd, etc. time through the song
{
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); //a hack so progress bar does not jump?
}
if (e->getIsFadingOut()) //we are in fadeout??? why it works like that bruh
{
// LIVE WITH IT damn it
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); //a hack so progress bar does not jump?
}
}
// this horrible indentation courtesy of `indent`
*progressLambda=(float) ((*curPosInRowsLambda) + ((*totalLoopsLambda)- (*loopsLeftLambda)) * songLength + lengthOfOneFile * (*curFileLambda)) / (float) totalLength;});
e->lockEngine(
[this, progressLambda, curPosInRowsLambda, curFileLambda, loopsLeftLambda, totalLoopsLambda] () {
int curRow=0; int curOrder=0;
e->getCurSongPos(curRow, curOrder);
*curFileLambda=0;
e->getCurFileIndex(*curFileLambda);
*curPosInRowsLambda=curRow;
for (int i=0; i<curOrder; i++) *curPosInRowsLambda+=songOrdersLengths[i];
if (!songHasSongEndCommand) {
e->getLoopsLeft(*loopsLeftLambda);
e->getTotalLoops(*totalLoopsLambda);
if ((*totalLoopsLambda)!=(*loopsLeftLambda)) { // we are going 2nd, 3rd, etc. time through the song
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); // a hack so progress bar does not jump?
}
if (e->getIsFadingOut()) { // we are in fadeout??? why it works like that bruh
// LIVE WITH IT damn it
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); // a hack so progress bar does not jump?
}
}
*progressLambda=(float)((*curPosInRowsLambda)+((*totalLoopsLambda)-(*loopsLeftLambda))*songLength+lengthOfOneFile*(*curFileLambda))/(float)totalLength;
}
);
}
ImGui::Text(_("Row %d of %d"),curPosInRows+((totalLoops)-(loopsLeft))*songLength,lengthOfOneFile);
if (audioExportOptions.mode==DIV_EXPORT_MODE_MANY_CHAN) {
ImGui::Text(_("Channel %d of %d"),curFile+1,totalFiles);
}
if (audioExportOptions.mode==DIV_EXPORT_MODE_MANY_CHAN) ImGui::Text(_("Channel %d of %d"),curFile+1,totalFiles);
ImGui::ProgressBar(curProgress,ImVec2(320.0f*dpiScale,0),fmt::sprintf("%.2f%%",curProgress*100.0f).c_str());

View file

@ -39,7 +39,7 @@
#define FURNACE_APP_ID "org.tildearrow.furnace"
#define rightClickable if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) ImGui::SetKeyboardFocusHere(-1);
#define ctrlWheeling ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && wheelY!=0)
#define ctrlWheeling (isCtrlWheelModifierHeld() && wheelY!=0)
#define handleUnimportant if (settings.insFocusesPattern && patternOpen) {nextWindow=GUI_WINDOW_PATTERN;}
#define unimportant(x) if (x) {handleUnimportant}
@ -354,6 +354,8 @@ enum FurnaceGUIColors {
GUI_COLOR_INSTR_GBA_MINMOD,
GUI_COLOR_INSTR_BIFURCATOR,
GUI_COLOR_INSTR_SID2,
GUI_COLOR_INSTR_SUPERVISION,
GUI_COLOR_INSTR_UPD1771C,
GUI_COLOR_INSTR_SID3,
GUI_COLOR_INSTR_UNKNOWN,
@ -819,6 +821,8 @@ enum FurnaceGUIActions {
GUI_ACTION_PAT_SCROLL_MODE,
GUI_ACTION_PAT_CLEAR_LATCH,
GUI_ACTION_PAT_ABSORB_INSTRUMENT,
GUI_ACTION_PAT_CURSOR_UNDO,
GUI_ACTION_PAT_CURSOR_REDO,
GUI_ACTION_PAT_MAX,
GUI_ACTION_INS_LIST_MIN,
@ -1104,6 +1108,22 @@ struct UndoStep {
newPatLen(0) {}
};
struct CursorJumpPoint {
SelectionPoint point;
int order;
int subSong;
CursorJumpPoint(const SelectionPoint& p, int o, int ss):
point(p), order(o), subSong(ss) {}
CursorJumpPoint():
point(), order(0), subSong(0) {}
bool operator== (const CursorJumpPoint& spot) {
return point.xCoarse==spot.point.xCoarse && point.xFine==spot.point.xFine && point.y==spot.point.y && order==spot.order && subSong==spot.subSong;
}
bool operator!= (const CursorJumpPoint& spot) {
return !(*this == spot);
}
};
// -1 = any
struct MIDIBind {
int type, channel, data1, data2;
@ -1753,6 +1773,7 @@ class FurnaceGUI {
int opnbCore;
int opl2Core;
int opl3Core;
int opl4Core;
int esfmCore;
int opllCore;
int ayCore;
@ -1779,6 +1800,7 @@ class FurnaceGUI {
int opnbCoreRender;
int opl2CoreRender;
int opl3CoreRender;
int opl4CoreRender;
int esfmCoreRender;
int opllCoreRender;
int ayCoreRender;
@ -1805,6 +1827,7 @@ class FurnaceGUI {
int patRowsBase;
int orderRowsBase;
int soloAction;
int ctrlWheelModifier;
int pullDeleteBehavior;
int wrapHorizontal;
int wrapVertical;
@ -2013,6 +2036,7 @@ class FurnaceGUI {
opnbCore(1),
opl2Core(0),
opl3Core(0),
opl4Core(0),
esfmCore(0),
opllCore(0),
ayCore(0),
@ -2039,6 +2063,7 @@ class FurnaceGUI {
opnbCoreRender(1),
opl2CoreRender(0),
opl3CoreRender(0),
opl4CoreRender(0),
esfmCoreRender(0),
opllCoreRender(0),
ayCoreRender(0),
@ -2064,6 +2089,7 @@ class FurnaceGUI {
patRowsBase(0),
orderRowsBase(1),
soloAction(0),
ctrlWheelModifier(0),
pullDeleteBehavior(1),
wrapHorizontal(0),
wrapVertical(0),
@ -2501,6 +2527,8 @@ class FurnaceGUI {
std::map<unsigned short,DivPattern*> oldPatMap;
FixedQueue<UndoStep,256> undoHist;
FixedQueue<UndoStep,256> redoHist;
FixedQueue<CursorJumpPoint,256> cursorUndoHist;
FixedQueue<CursorJumpPoint,256> cursorRedoHist;
// sample editor specific
double sampleZoom;
@ -2741,6 +2769,7 @@ class FurnaceGUI {
static bool LocalizedComboGetter(void* data, int idx, const char** out_text);
// these ones offer ctrl-wheel fine value changes.
bool isCtrlWheelModifierHeld() const;
bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0);
bool CWVSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0);
bool CWSliderInt(const char* label, int* v, int v_min, int v_max, const char* format="%d", ImGuiSliderFlags flags=0);
@ -2941,6 +2970,12 @@ class FurnaceGUI {
void doGenerateWave();
CursorJumpPoint getCurrentCursorJumpPoint();
void applyCursorJumpPoint(const CursorJumpPoint& spot);
void makeCursorUndo();
void doCursorUndo();
void doCursorRedo();
void doUndoSample();
void doRedoSample();

View file

@ -184,6 +184,8 @@ const char* insTypes[DIV_INS_MAX+1][3]={
{"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD},
{"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR},
{"SID2",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2},
{"Watara Supervision",ICON_FA_GAMEPAD,ICON_FUR_INS_SUPERVISION},
{"NEC μPD1771C",ICON_FA_BAR_CHART,ICON_FUR_INS_UPD1771C},
{"SID3",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID3},
{NULL,ICON_FA_QUESTION,ICON_FA_QUESTION}
};
@ -209,7 +211,7 @@ const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
"8-bit µ-law PCM",
"C219 PCM",
"IMA ADPCM",
NULL,
"12-bit PCM",
NULL,
"16-bit PCM"
};
@ -689,6 +691,8 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
D("PAT_SCROLL_MODE", _N("Change mobile scroll mode"), 0),
D("PAT_CLEAR_LATCH", _N("Clear note input latch"), 0),
D("PAT_ABSORB_INSTRUMENT", _N("Absorb instrument/octave from status at cursor"), 0),
D("PAT_CURSOR_UNDO", _N("Return cursor to previous jump point"), 0),
D("PAT_CURSOR_REDO", _N("Reverse recent cursor undo"), 0),
D("PAT_MAX", "", NOT_AN_ACTION),
D("INS_LIST_MIN", _N("---Instrument list"), NOT_AN_ACTION),
@ -1017,6 +1021,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_INSTR_GBA_MINMOD,"",ImVec4(0.5f,0.45f,0.7f,1.0f)),
D(GUI_COLOR_INSTR_BIFURCATOR,"",ImVec4(0.8925f,0.8925f,0.8925f,1.0f)),
D(GUI_COLOR_INSTR_SID2,"",ImVec4(0.6f,0.75f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_SUPERVISION,"",ImVec4(0.52f,1.0f,0.6f,1.0f)),
D(GUI_COLOR_INSTR_UPD1771C,"",ImVec4(0.94f,0.52f,0.6f,1.0f)),
D(GUI_COLOR_INSTR_SID3,"",ImVec4(0.6f,0.75f,0.6f,1.0f)),
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
@ -1266,6 +1272,10 @@ const int availableSystems[]={
DIV_SYSTEM_5E01,
DIV_SYSTEM_BIFURCATOR,
DIV_SYSTEM_SID2,
DIV_SYSTEM_OPL4,
DIV_SYSTEM_OPL4_DRUMS,
DIV_SYSTEM_SUPERVISION,
DIV_SYSTEM_UPD1771C,
DIV_SYSTEM_SID3,
0 // don't remove this last one!
};
@ -1302,6 +1312,8 @@ const int chipsFM[]={
DIV_SYSTEM_OPL3_DRUMS,
DIV_SYSTEM_OPZ,
DIV_SYSTEM_ESFM,
DIV_SYSTEM_OPL4,
DIV_SYSTEM_OPL4_DRUMS,
0 // don't remove this last one!
};
@ -1362,6 +1374,8 @@ const int chipsSpecial[]={
DIV_SYSTEM_5E01,
DIV_SYSTEM_BIFURCATOR,
DIV_SYSTEM_SID2,
DIV_SYSTEM_SUPERVISION,
DIV_SYSTEM_UPD1771C,
DIV_SYSTEM_SID3,
0 // don't remove this last one!
};
@ -1388,6 +1402,8 @@ const int chipsSample[]={
DIV_SYSTEM_NDS,
DIV_SYSTEM_GBA_DMA,
DIV_SYSTEM_GBA_MINMOD,
DIV_SYSTEM_OPL4,
DIV_SYSTEM_OPL4_DRUMS,
0 // don't remove this last one!
};

View file

@ -2746,48 +2746,68 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros, FurnaceGUI
drawMacroEdit(m,totalFit,availableWidth,index);
if (m.macro->open&1) {
if ((m.macro->open&6)==0) {
ImGui::Text(_("Length"));
ImGui::SameLine();
ImGui::SetNextItemWidth(120.0f*dpiScale);
int macroLen=m.macro->len;
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED
if (macroLen<0) macroLen=0;
if (macroLen>255) macroLen=255;
m.macro->len=macroLen;
}
ImGui::SameLine();
}
ImGui::Text(_("StepLen"));
ImGui::SameLine();
ImGui::SetNextItemWidth(120.0f*dpiScale);
if (ImGui::InputScalar("##IMacroSpeed",ImGuiDataType_U8,&m.macro->speed,&_ONE,&_THREE)) {
if (m.macro->speed<1) m.macro->speed=1;
MARK_MODIFIED;
}
ImGui::SameLine();
ImGui::Text(_("Delay"));
ImGui::SameLine();
ImGui::SetNextItemWidth(120.0f*dpiScale);
if (ImGui::InputScalar("##IMacroDelay",ImGuiDataType_U8,&m.macro->delay,&_ONE,&_THREE)) {
MARK_MODIFIED;
}
ImGui::SameLine();
{
FurnaceGUIMacroDesc& i=m;
BUTTON_TO_SET_MODE(ImGui::Button);
if ((i.macro->open&6)==0) {
bool showLen=((m.macro->open&6)==0);
int colCount=showLen ? 4 : 3;
float availX=ImGui::GetContentRegionAvail().x;
// fairly arbitrary scaling logic
bool shortLabels=(availX<600.0f*dpiScale);
float scalarItemWidth=MIN((availX-90.0f*dpiScale)/colCount, 120.0f*dpiScale);
if (ImGui::BeginTable("##MacroMetaData",colCount)) {
if (showLen) ImGui::TableSetupColumn("len",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("stepLen",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("delay",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("buttons",ImGuiTableColumnFlags_WidthFixed,0.0);
ImGui::TableNextRow();
if (showLen) {
ImGui::TableNextColumn();
ImGui::Text(shortLabels ? _("Len##macroEditLengthShortLabel") : _("Length"));
if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("Length"));
ImGui::SameLine();
BUTTON_TO_SET_RELEASE(ImGui::Button);
ImGui::SetNextItemWidth(scalarItemWidth);
int macroLen=m.macro->len;
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED
if (macroLen<0) macroLen=0;
if (macroLen>255) macroLen=255;
m.macro->len=macroLen;
}
}
}
if (m.modeName!=NULL) {
bool modeVal=m.macro->mode;
String modeName=fmt::sprintf("%s##IMacroMode",m.modeName);
ImGui::TableNextColumn();
ImGui::Text(shortLabels ? _("SLen##macroEditStepLenShortLabel") : _("StepLen"));
if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("StepLen"));
ImGui::SameLine();
if (ImGui::Checkbox(modeName.c_str(),&modeVal)) {
m.macro->mode=modeVal;
ImGui::SetNextItemWidth(scalarItemWidth);
if (ImGui::InputScalar("##IMacroSpeed",ImGuiDataType_U8,&m.macro->speed,&_ONE,&_THREE)) {
if (m.macro->speed<1) m.macro->speed=1;
MARK_MODIFIED;
}
ImGui::TableNextColumn();
ImGui::Text(shortLabels ? _("Del##macroEditDelayShortLabel") : _("Delay"));
if (shortLabels && ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _("Delay"));
ImGui::SameLine();
ImGui::SetNextItemWidth(scalarItemWidth);
if (ImGui::InputScalar("##IMacroDelay",ImGuiDataType_U8,&m.macro->delay,&_ONE,&_THREE)) {
MARK_MODIFIED;
}
ImGui::TableNextColumn();
{
FurnaceGUIMacroDesc& i=m;
BUTTON_TO_SET_MODE(ImGui::Button);
if ((i.macro->open&6)==0) {
ImGui::SameLine();
BUTTON_TO_SET_RELEASE(ImGui::Button);
}
}
if (m.modeName!=NULL) {
bool modeVal=m.macro->mode;
String modeName=fmt::sprintf("%s##IMacroMode",m.modeName);
ImGui::SameLine();
if (ImGui::Checkbox(modeName.c_str(),&modeVal)) {
m.macro->mode=modeVal;
}
}
ImGui::EndTable();
}
} else {
ImGui::Text(_("The heck? No, this isn't even working correctly..."));
@ -3289,6 +3309,7 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
ins->type==DIV_INS_VRC6 ||
ins->type==DIV_INS_SU ||
ins->type==DIV_INS_NDS ||
ins->type==DIV_INS_SUPERVISION ||
ins->type==DIV_INS_SID3) {
P(ImGui::Checkbox(_("Use sample"),&ins->amiga.useSample));
if (ins->type==DIV_INS_X1_010) {
@ -4120,8 +4141,8 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
opllPreview.alg=ins->fm.alg;
opllPreview.fb=patch->fb;
opllPreview.fms=patch->dm;
opllPreview.ams=patch->dc;
opllPreview.fms=patch->dc;
opllPreview.ams=patch->dm;
opllPreview.op[0].tl=patch->tl;
opllPreview.op[1].tl=ins->fm.op[1].tl;
@ -4131,6 +4152,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
opllPreview.op[i].vib=patch->vib[i];
opllPreview.op[i].ssgEnv=patch->et[i]?8:0;
opllPreview.op[i].ksr=patch->ksr[i];
opllPreview.op[i].ksl=patch->ksl[i];
opllPreview.op[i].mult=patch->multi[i];
opllPreview.op[i].ar=patch->ar[i];
opllPreview.op[i].dr=patch->dr[i];
@ -4650,7 +4672,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
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)"));
ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)"));
}
if (ins->type==DIV_INS_ESFM && fixedOn) {
if (ImGui::Checkbox(FM_SHORT_NAME(FM_VIB),&vibOn)) { PARAMETER
@ -5014,7 +5036,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
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)"));
ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)"));
}
// params
@ -5064,7 +5086,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
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)"));
ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)"));
}
// params
@ -5772,7 +5794,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
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)"));
ImGui::SetTooltip(_("OPL2/3/4 only (last 4 waveforms are OPL3/4 only)"));
}
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_WS));
@ -7475,7 +7497,8 @@ void FurnaceGUI::drawInsEdit() {
ins->type==DIV_INS_C219 ||
ins->type==DIV_INS_NDS ||
ins->type==DIV_INS_GBA_DMA ||
ins->type==DIV_INS_GBA_MINMOD) {
ins->type==DIV_INS_GBA_MINMOD ||
ins->type==DIV_INS_SUPERVISION) {
insTabSample(ins);
}
if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("Namco 163")) {
@ -7789,6 +7812,19 @@ void FurnaceGUI::drawInsEdit() {
P(CWSliderScalar(_("AM Depth"),ImGuiDataType_U8,&ins->multipcm.am,&_ZERO,&_SEVEN)); rightClickable
ImGui::EndTable();
}
P(ImGui::Checkbox(_("Damp"),&ins->multipcm.damp));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("Only for OPL4 PCM."));
}
P(ImGui::Checkbox(_("Pseudo Reverb"),&ins->multipcm.pseudoReverb));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("Only for OPL4 PCM."));
}
P(ImGui::Checkbox(_("LFO Reset"),&ins->multipcm.lfoReset));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("Only for OPL4 PCM."));
}
P(ImGui::Checkbox(_("Level Direct"),&ins->multipcm.levelDirect));
ImGui::EndTabItem();
}
}
@ -8225,6 +8261,9 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-7,7,45,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO Speed"),&ins->std.ex1Macro,0,7,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO Vib Depth"),&ins->std.fmsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_PITCH]));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO AM Depth"),&ins->std.amsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
break;
case DIV_INS_SNES:
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
@ -8376,6 +8415,13 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc(_("Pulse Width"),&ins->std.dutyMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
break;
case DIV_INS_SUPERVISION:
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Noise"),&ins->std.dutyMacro,0,3,160,uiColors[GUI_COLOR_MACRO_NOISE]));
macroList.push_back(FurnaceGUIMacroDesc(_("Noise/PCM Pan"),&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
break;
case DIV_INS_SM8521:
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
@ -8518,8 +8564,17 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Mode"),&ins->std.fmsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_NOISE]));
macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.amsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID2WaveMixMode));
break;
case DIV_INS_SID3: break;
case DIV_INS_UPD1771C:
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,31,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,7,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL));
macroList.push_back(FurnaceGUIMacroDesc(_("Wave Pos"),&ins->std.ex1Macro,0,31,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Duty/Mode"),&ins->std.dutyMacro,0,1,160,uiColors[GUI_COLOR_MACRO_NOISE]));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
break;
case DIV_INS_SID3:
// TODO: put stuff here to kill that goto.
break;
case DIV_INS_MAX:
case DIV_INS_NULL:
break;

View file

@ -320,6 +320,11 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_NDS, 1.0f, 0, "")
}
);
ENTRY(
"Watara Supervision", {
CH(DIV_SYSTEM_SUPERVISION, 1.0f, 0, "")
}
);
CATEGORY_END;
CATEGORY_BEGIN(_("Computers"),_("let's get to work on chiptune today."));
@ -519,6 +524,18 @@ void FurnaceGUI::initSystemPresets() {
) // variable rate, Mono DAC
}
);
SUB_ENTRY(
"MSX + MoonSound", {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "chipType=1"),
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
}
);
SUB_ENTRY(
"MSX + MoonSound (drums mode)", {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "chipType=1"),
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
}
);
ENTRY(
_("NEC PC-6001"), {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "customClock=3993600")
@ -1319,6 +1336,11 @@ void FurnaceGUI::initSystemPresets() {
)
}
);
ENTRY(
"Epoch Super Cassette Vision", {
CH(DIV_SYSTEM_UPD1771C, 1.0f, 0, "")
}
);
CATEGORY_END;
CATEGORY_BEGIN(_("Arcade systems"),_("INSERT COIN"));
@ -1895,6 +1917,30 @@ void FurnaceGUI::initSystemPresets() {
}
);
ENTRY(
_("Psikyo"), {}
);
SUB_ENTRY(
_("Psikyo 68EC020 hardware with OPL4"), {
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
}
);
SUB_ENTRY(
_("Psikyo 68EC020 hardware with OPL4 (drums mode)"), {
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
}
);
SUB_ENTRY(
_("Psikyo SH-2 hardware"), {
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "clockSel=1")
}
);
SUB_ENTRY(
_("Psikyo SH-2 hardware (drums mode)"), {
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "clockSel=1")
}
);
ENTRY(
_("Sega"), {}
);
@ -2719,6 +2765,16 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_ESFM, 1.0f, 0, "")
}
);
ENTRY(
"Yamaha YMF278B (OPL4)", {
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
}
);
SUB_ENTRY(
"Yamaha YMF278B (drums mode)", {
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
}
);
if (settings.hiddenSystems) {
ENTRY(
_("Yamaha YMU759 (MA-2)"), {
@ -2930,6 +2986,16 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_NDS, 1.0f, 0, "")
}
);
ENTRY(
"Yamaha YMF278B (OPL4)", {
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
}
);
SUB_ENTRY(
"Yamaha YMF278B (drums mode)", {
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
}
);
CATEGORY_END;
CATEGORY_BEGIN(_("Wavetable"),_("chips which use user-specified waveforms to generate sound."));
@ -3125,6 +3191,16 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_SID3, 1.0f, 0, "")
}
);
ENTRY(
_("Watara Supervision"), {
CH(DIV_SYSTEM_SUPERVISION, 1.0f, 0, "")
}
);
ENTRY(
_("NEC μPD1771C"), {
CH(DIV_SYSTEM_UPD1771C, 1.0f, 0, "")
}
);
CATEGORY_END;
CATEGORY_BEGIN(_("DefleMask-compatible"),_("these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."));

View file

@ -413,6 +413,25 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_WARN(warnLength,_("GBA DMA: sample length will be padded to multiple of 16"));
}
break;
case DIV_SYSTEM_OPL4:
case DIV_SYSTEM_OPL4_DRUMS:
if (sample->samples>65535) {
SAMPLE_WARN(warnLength,_("OPL4: maximum sample length is 65535"));
}
break;
case DIV_SYSTEM_SUPERVISION:
if (sample->loop) {
if (sample->loopStart!=0 || sample->loopEnd!=(int)(sample->samples)) {
SAMPLE_WARN(warnLoopPos,_("Supervision: loop point ignored on sample channel"));
}
}
if (sample->samples&31) {
SAMPLE_WARN(warnLength,_("Supervision: sample length will be padded to multiple of 32"));
}
if (sample->samples>8192) {
SAMPLE_WARN(warnLength,_("Supervision: maximum sample length is 8192"));
}
break;
default:
break;
}

View file

@ -189,6 +189,11 @@ const char* opl3Cores[]={
"YMF262-LLE"
};
const char* opl4Cores[]={
"Nuked-OPL3 (FM) + openMSX (PCM)",
"ymfm"
};
const char* esfmCores[]={
"ESFMu",
_N("ESFMu (fast)")
@ -2058,6 +2063,17 @@ void FurnaceGUI::drawSettings() {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL3CoreRender",&settings.opl3CoreRender,opl3Cores,3)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("OPL4");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL4Core",&settings.opl4Core,opl4Cores,2)) settingsChanged=true;
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL4CoreRender",&settings.opl4CoreRender,opl4Cores,2)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
@ -2137,7 +2153,6 @@ void FurnaceGUI::drawSettings() {
ImGui::SameLine();
if (ImGui::Combo("##PCSOutMethod",&settings.pcSpeakerOutMethod,LocalizedComboGetter,pcspkrOutMethods,5)) settingsChanged=true;
/*
ImGui::Separator();
ImGui::Text(_("Sample ROMs:"));
@ -2150,6 +2165,7 @@ void FurnaceGUI::drawSettings() {
openFileDialog(GUI_FILE_YRW801_ROM_OPEN);
}
/*
ImGui::AlignTextToFramePadding();
ImGui::Text(_("MultiPCM TG100 path"));
ImGui::SameLine();
@ -2428,6 +2444,8 @@ void FurnaceGUI::drawSettings() {
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CLEAR_LATCH);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_ABSORB_INSTRUMENT);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CURSOR_UNDO);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CURSOR_REDO);
KEYBIND_CONFIG_END;
ImGui::TreePop();
@ -2720,6 +2738,27 @@ void FurnaceGUI::drawSettings() {
}
ImGui::Unindent();
ImGui::Text(_("Modifier for alternate wheel-scrolling (vertical/zoom/slider-input):"));
ImGui::Indent();
if (ImGui::RadioButton(_("Ctrl or Meta/Cmd##cwm1"),settings.ctrlWheelModifier==0)) {
settings.ctrlWheelModifier=0;
settingsChanged=true;
}
if (ImGui::RadioButton(_("Ctrl##cwm2"),settings.ctrlWheelModifier==1)) {
settings.ctrlWheelModifier=1;
settingsChanged=true;
}
if (ImGui::RadioButton(_("Meta/Cmd##cwm3"),settings.ctrlWheelModifier==2)) {
settings.ctrlWheelModifier=2;
settingsChanged=true;
}
// technically this key is called Option on mac, but we call it Alt in getKeyName(s)
if (ImGui::RadioButton(_("Alt##cwm4"),settings.ctrlWheelModifier==3)) {
settings.ctrlWheelModifier=3;
settingsChanged=true;
}
ImGui::Unindent();
bool doubleClickColumnB=settings.doubleClickColumn;
if (ImGui::Checkbox(_("Double click selects entire column"),&doubleClickColumnB)) {
settings.doubleClickColumn=doubleClickColumnB;
@ -4126,6 +4165,8 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID2,_("SID2"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SUPERVISION,_("Supervision"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UPD1771C,_("μPD1771C"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID3,_("SID3"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,_("Other/Unknown"));
ImGui::TreePop();
@ -4820,6 +4861,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
if (groups&GUI_SETTINGS_BEHAVIOR) {
settings.soloAction=conf.getInt("soloAction",0);
settings.ctrlWheelModifier=conf.getInt("ctrlWheelModifier",0);
settings.pullDeleteBehavior=conf.getInt("pullDeleteBehavior",1);
settings.wrapHorizontal=conf.getInt("wrapHorizontal",0);
settings.wrapVertical=conf.getInt("wrapVertical",0);
@ -4999,6 +5041,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.opnbCore=conf.getInt("opnbCore",1);
settings.opl2Core=conf.getInt("opl2Core",0);
settings.opl3Core=conf.getInt("opl3Core",0);
settings.opl4Core=conf.getInt("opl4Core",0);
settings.esfmCore=conf.getInt("esfmCore",0);
settings.opllCore=conf.getInt("opllCore",0);
settings.ayCore=conf.getInt("ayCore",0);
@ -5027,6 +5070,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.opnbCoreRender=conf.getInt("opnbCoreRender",1);
settings.opl2CoreRender=conf.getInt("opl2CoreRender",0);
settings.opl3CoreRender=conf.getInt("opl3CoreRender",0);
settings.opl4CoreRender=conf.getInt("opl4CoreRender",0);
settings.esfmCoreRender=conf.getInt("esfmCoreRender",0);
settings.opllCoreRender=conf.getInt("opllCoreRender",0);
settings.ayCoreRender=conf.getInt("ayCoreRender",0);
@ -5072,6 +5116,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.opnbCore,0,2);
clampSetting(settings.opl2Core,0,2);
clampSetting(settings.opl3Core,0,2);
clampSetting(settings.opl4Core,0,1);
clampSetting(settings.esfmCore,0,1);
clampSetting(settings.opllCore,0,1);
clampSetting(settings.ayCore,0,1);
@ -5098,6 +5143,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.opnbCoreRender,0,2);
clampSetting(settings.opl2CoreRender,0,2);
clampSetting(settings.opl3CoreRender,0,2);
clampSetting(settings.opl4CoreRender,0,1);
clampSetting(settings.esfmCoreRender,0,1);
clampSetting(settings.opllCoreRender,0,1);
clampSetting(settings.ayCoreRender,0,1);
@ -5118,6 +5164,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.patRowsBase,0,1);
clampSetting(settings.orderRowsBase,0,1);
clampSetting(settings.soloAction,0,2);
clampSetting(settings.ctrlWheelModifier,0,3);
clampSetting(settings.pullDeleteBehavior,0,1);
clampSetting(settings.wrapHorizontal,0,2);
clampSetting(settings.wrapVertical,0,3);
@ -5405,6 +5452,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
// behavior
if (groups&GUI_SETTINGS_BEHAVIOR) {
conf.set("soloAction",settings.soloAction);
conf.set("ctrlWheelModifier",settings.ctrlWheelModifier);
conf.set("pullDeleteBehavior",settings.pullDeleteBehavior);
conf.set("wrapHorizontal",settings.wrapHorizontal);
conf.set("wrapVertical",settings.wrapVertical);
@ -5588,6 +5636,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("opnbCore",settings.opnbCore);
conf.set("opl2Core",settings.opl2Core);
conf.set("opl3Core",settings.opl3Core);
conf.set("opl4Core",settings.opl4Core);
conf.set("esfmCore",settings.esfmCore);
conf.set("opllCore",settings.opllCore);
conf.set("ayCore",settings.ayCore);
@ -5616,6 +5665,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("opnbCoreRender",settings.opnbCoreRender);
conf.set("opl2CoreRender",settings.opl2CoreRender);
conf.set("opl3CoreRender",settings.opl3CoreRender);
conf.set("opl4CoreRender",settings.opl4CoreRender);
conf.set("esfmCoreRender",settings.esfmCoreRender);
conf.set("opllCoreRender",settings.opllCoreRender);
conf.set("ayCoreRender",settings.ayCoreRender);
@ -5679,6 +5729,7 @@ void FurnaceGUI::commitSettings() {
settings.opnbCore!=e->getConfInt("opnbCore",1) ||
settings.opl2Core!=e->getConfInt("opl2Core",0) ||
settings.opl3Core!=e->getConfInt("opl3Core",0) ||
settings.opl4Core!=e->getConfInt("opl4Core",0) ||
settings.esfmCore!=e->getConfInt("esfmCore",0) ||
settings.opllCore!=e->getConfInt("opllCore",0) ||
settings.ayCore!=e->getConfInt("ayCore",0) ||

View file

@ -36,6 +36,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable(id,i==e->getCurrentSubSong())) {
makeCursorUndo();
e->changeSongP(i);
updateScroll(0);
oldRow=0;
@ -72,6 +73,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
if (!e->addSubSong()) {
showError(_("too many subsongs!"));
} else {
makeCursorUndo();
e->changeSongP(e->song.subsong.size()-1);
updateScroll(0);
oldRow=0;
@ -92,6 +94,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
if (!e->duplicateSubSong(e->getCurrentSubSong())) {
showError(_("too many subsongs!"));
} else {
makeCursorUndo();
e->changeSongP(e->song.subsong.size()-1);
updateScroll(0);
oldRow=0;

View file

@ -1970,6 +1970,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
echoFilter[7]=flags.getInt("echoFilter7",0);
bool interpolationOff=flags.getBool("interpolationOff",false);
bool antiClick=flags.getBool("antiClick",true);
ImGui::Text(_("Volume scale:"));
if (CWSliderInt(_("Left##VolScaleL"),&vsL,0,127)) {
@ -2090,6 +2091,10 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
altered=true;
}
if (ImGui::Checkbox(_("Anti-click"),&antiClick)) {
altered=true;
}
if (altered) {
e->lockSave([&]() {
flags.set("volScaleL",127-vsL);
@ -2109,6 +2114,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
flags.set("echoFilter7",echoFilter[7]);
flags.set("echoMask",echoMask);
flags.set("interpolationOff",interpolationOff);
flags.set("antiClick",antiClick);
});
}
@ -2324,6 +2330,29 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
}
break;
}
case DIV_SYSTEM_SUPERVISION: {
bool swapDuty=flags.getInt("swapDuty",true);
if (ImGui::Checkbox(_("Swap noise duty cycles"),&swapDuty)) {
altered=true;
}
bool sqStereo=flags.getInt("sqStereo",false);
if (ImGui::Checkbox(_("Stereo pulse waves"),&sqStereo)) {
altered=true;
}
if (altered) {
e->lockSave([&]() {
flags.set("swapDuty",(int)swapDuty);
});
e->lockSave([&]() {
flags.set("sqStereo",(int)sqStereo);
});
}
break;
}
case DIV_SYSTEM_SM8521:/* {
bool noAntiClick=flags.getBool("noAntiClick",false);
@ -2514,6 +2543,67 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
}
break;
}
case DIV_SYSTEM_OPL4:
case DIV_SYSTEM_OPL4_DRUMS: {
int clockSel=flags.getInt("clockSel",0);
int ramSize=flags.getInt("ramSize",0);
ImGui::Text(_("Clock rate:"));
ImGui::Indent();
if (ImGui::RadioButton(_("33.8688MHz"),clockSel==0)) {
clockSel=0;
altered=true;
}
if (ImGui::RadioButton(_("28.64MHz (NTSC)"),clockSel==1)) {
clockSel=1;
altered=true;
}
if (ImGui::RadioButton(_("28.38MHz (PAL)"),clockSel==2)) {
clockSel=2;
altered=true;
}
ImGui::Unindent();
ImGui::Text(_("RAM size:"));
ImGui::Indent();
if (ImGui::RadioButton(_("4MB"),ramSize==0)) {
ramSize=0;
altered=true;
}
if (ImGui::RadioButton(_("2MB"),ramSize==1)) {
ramSize=1;
altered=true;
}
if (ImGui::RadioButton(_("1MB"),ramSize==2)) {
ramSize=2;
altered=true;
}
if (ImGui::RadioButton(_("640KB"),ramSize==3)) {
ramSize=3;
altered=true;
}
if (ImGui::RadioButton(_("512KB"),ramSize==4)) {
ramSize=4;
altered=true;
}
if (ImGui::RadioButton(_("256KB"),ramSize==5)) {
ramSize=5;
altered=true;
}
if (ImGui::RadioButton(_("128KB"),ramSize==6)) {
ramSize=6;
altered=true;
}
ImGui::Unindent();
if (altered) {
e->lockSave([&]() {
flags.set("clockSel",clockSel);
flags.set("ramSize",ramSize);
});
}
break;
}
case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_BUBSYS_WSG:
case DIV_SYSTEM_PET:
@ -2522,6 +2612,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
case DIV_SYSTEM_C219:
case DIV_SYSTEM_BIFURCATOR:
case DIV_SYSTEM_POWERNOISE:
case DIV_SYSTEM_UPD1771C:
break;
case DIV_SYSTEM_YMU759:
case DIV_SYSTEM_ESFM:

View file

@ -279,6 +279,12 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) {
break;
case DIV_SYSTEM_ESFM:
return "ES1xxx";
case DIV_SYSTEM_SUPERVISION:
return "Watara Supervision";
break;
case DIV_SYSTEM_UPD1771C:
return "μPD1771C";
break;
default:
return FurnaceGUI::getSystemName(sys);
break;

View file

@ -475,7 +475,8 @@ void FurnaceGUI::drawUserPresets() {
ImGui::SetTooltip(_(
"insert additional settings in `option=value` format.\n"
"available options:\n"
"- tickRate"
"- tickRate \n"
"- chanMask \n"
));
}

View file

@ -948,6 +948,7 @@ void FurnaceGUI::drawWaveEdit() {
wave->len=waveGenScaleX;
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::TableNextRow();
@ -966,6 +967,7 @@ void FurnaceGUI::drawWaveEdit() {
wave->max=waveGenScaleY-1;
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::TableNextRow();
@ -988,6 +990,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::TableNextRow();
@ -1005,6 +1008,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::TableNextRow();
@ -1031,6 +1035,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::TableNextRow();
@ -1050,6 +1055,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::EndTable();
@ -1093,6 +1099,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
if (ImGui::Button(_("Invert"),buttonSizeHalf)) {
e->lockEngine([this,wave]() {
@ -1101,6 +1108,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::SameLine();
if (ImGui::Button(_("Reverse"),buttonSizeHalf)) {
@ -1113,6 +1121,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
if (ImGui::Button(_("Half"),buttonSizeHalf)) {
@ -1122,6 +1131,7 @@ void FurnaceGUI::drawWaveEdit() {
for (int i=0; i<wave->len; i++) {
wave->data[i]=origData[i>>1];
}
e->notifyWaveChange(curWave);
MARK_MODIFIED;
}
ImGui::SameLine();
@ -1132,6 +1142,7 @@ void FurnaceGUI::drawWaveEdit() {
for (int i=0; i<wave->len; i++) {
wave->data[i]=origData[(i*2)%wave->len];
}
e->notifyWaveChange(curWave);
MARK_MODIFIED;
}
@ -1146,6 +1157,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
if (ImGui::Button(_("Randomize"),buttonSize)) {
if (wave->max>0) e->lockEngine([this,wave]() {
@ -1154,6 +1166,7 @@ void FurnaceGUI::drawWaveEdit() {
}
MARK_MODIFIED;
});
e->notifyWaveChange(curWave);
}
ImGui::EndTabItem();
}