diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c3129128..63144c540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,6 +308,7 @@ endif() set(ENGINE_SOURCES src/log.cpp +src/baseutils.cpp src/fileutils.cpp src/utfutils.cpp @@ -572,6 +573,7 @@ src/gui/guiConst.cpp src/gui/about.cpp src/gui/channels.cpp src/gui/chanOsc.cpp +src/gui/clock.cpp src/gui/compatFlags.cpp src/gui/cursor.cpp src/gui/dataList.cpp diff --git a/README.md b/README.md index 000c66100..e5573b4ba 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Furnace Tracker +# Furnace (chiptune tracker) ![screenshot](papers/screenshot2.png) diff --git a/demos/SeeingRed.fur b/demos/SeeingRed.fur new file mode 100644 index 000000000..e7c95a535 Binary files /dev/null and b/demos/SeeingRed.fur differ diff --git a/demos/bruno_time.fur b/demos/bruno_time.fur index 0ad2d841e..4c8822e79 100644 Binary files a/demos/bruno_time.fur and b/demos/bruno_time.fur differ diff --git a/demos/splashingwater.fur b/demos/splashingwater.fur new file mode 100644 index 000000000..e983d7c14 Binary files /dev/null and b/demos/splashingwater.fur differ diff --git a/demos/watching_paint_dry.fur b/demos/watching_paint_dry.fur new file mode 100644 index 000000000..6023ce4d9 Binary files /dev/null and b/demos/watching_paint_dry.fur differ diff --git a/instruments/other/TIA Bass Drum.fui b/instruments/other/TIA Bass Drum.fui new file mode 100644 index 000000000..a65fa2ea8 Binary files /dev/null and b/instruments/other/TIA Bass Drum.fui differ diff --git a/instruments/other/TIA Clap.fui b/instruments/other/TIA Clap.fui new file mode 100644 index 000000000..b90cf2691 Binary files /dev/null and b/instruments/other/TIA Clap.fui differ diff --git a/instruments/other/TIA Hi-Hat Long.fui b/instruments/other/TIA Hi-Hat Long.fui new file mode 100644 index 000000000..0edd37f11 Binary files /dev/null and b/instruments/other/TIA Hi-Hat Long.fui differ diff --git a/instruments/other/TIA Hi-Hat.fui b/instruments/other/TIA Hi-Hat.fui new file mode 100644 index 000000000..0f5f3a595 Binary files /dev/null and b/instruments/other/TIA Hi-Hat.fui differ diff --git a/instruments/other/TIA Snare Drum.fui b/instruments/other/TIA Snare Drum.fui new file mode 100644 index 000000000..22cb3667c Binary files /dev/null and b/instruments/other/TIA Snare Drum.fui differ diff --git a/papers/doc/7-systems/ay8930.md b/papers/doc/7-systems/ay8930.md index 6d5200cac..0d471bcaf 100644 --- a/papers/doc/7-systems/ay8930.md +++ b/papers/doc/7-systems/ay8930.md @@ -3,7 +3,7 @@ a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator. sadly, this soundchip has only ever observed minimal success, and has remained rather obscure since. -it is known for being used in the Covox Sound Master, which didn't sell well either. +it is best known for being used in the Covox Sound Master, which didn't sell well either. It also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910. emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted. diff --git a/papers/doc/7-systems/ym2612.md b/papers/doc/7-systems/ym2612.md index 56b1a3b18..ac17cedc3 100644 --- a/papers/doc/7-systems/ym2612.md +++ b/papers/doc/7-systems/ym2612.md @@ -2,8 +2,6 @@ one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player. -For 0.6pre1, Furnace can now support advanced YM2612 features that [Fractal](https://gitlab.com/Natsumi/Fractal-Sound) sound driver adds: two software-mixed PCM channels (variable pitch, sample offsets, max 13.7 khz rate) and CSM - ch3 special mode feature that can be abused to produce rudimentary speech synthesis. - # effects - `10xy`: set LFO parameters. diff --git a/papers/format.md b/papers/format.md index f3a7566f1..391029eab 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 123: Furnace dev123 +- 122: Furnace dev122 - 121: Furnace dev121 - 120: Furnace dev120 - 119: Furnace dev119 @@ -1096,7 +1098,11 @@ size | description | - 9: BRR (SNES) | - 10: VOX | - 16: 16-bit PCM - 3 | reserved + 1 | loop direction (>=123) or reserved + | - 0: forward + | - 0: backward + | - 0: ping-pong + 2 | reserved 4 | loop start | - -1 means no loop 4 | loop end diff --git a/src/baseutils.cpp b/src/baseutils.cpp new file mode 100644 index 000000000..aad61eb48 --- /dev/null +++ b/src/baseutils.cpp @@ -0,0 +1,89 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "baseutils.h" +#include + +const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::string taEncodeBase64(const std::string& data) { + std::string ret; + + ret.reserve((2+data.size()*4)/3); + + unsigned int groupOfThree=0; + unsigned char pos=0; + for (const char& i: data) { + groupOfThree|=((unsigned char)i)<<((2-pos)<<3); + if (++pos>=3) { + pos=0; + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+=base64Table[(groupOfThree>>6)&63]; + ret+=base64Table[groupOfThree&63]; + groupOfThree=0; + } + } + if (pos==2) { + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+=base64Table[(groupOfThree>>6)&63]; + ret+='='; + } else if (pos==1) { + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+="=="; + } + + return ret; +} + +std::string taDecodeBase64(const char* buf) { + std::string data; + + unsigned int groupOfThree=0; + signed char pos=18; + for (const char* i=buf; *i; i++) { + unsigned char nextVal=0; + if ((*i)=='/') { + nextVal=63; + } else if ((*i)=='+') { + nextVal=62; + } else if ((*i)>='0' && (*i)<='9') { + nextVal=52+((*i)-'0'); + } else if ((*i)>='a' && (*i)<='z') { + nextVal=26+((*i)-'a'); + } else if ((*i)>='A' && (*i)<='Z') { + nextVal=((*i)-'A'); + } else { + nextVal=0; + } + groupOfThree|=nextVal<>16)&0xff) data+=(groupOfThree>>16)&0xff; + if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff; + if (groupOfThree&0xff) data+=groupOfThree&0xff; + groupOfThree=0; + } + } + + return data; +} diff --git a/src/baseutils.h b/src/baseutils.h new file mode 100644 index 000000000..438696aaa --- /dev/null +++ b/src/baseutils.h @@ -0,0 +1,28 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _BASEUTILS_H +#define _BASEUTILS_H + +#include + +std::string taEncodeBase64(const std::string& data); +std::string taDecodeBase64(const char* str); + +#endif diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 47ff3997d..ce7b1b4ad 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -19,6 +19,7 @@ #include "config.h" #include "../ta-log.h" +#include "../baseutils.h" #include "../fileutils.h" #include @@ -48,41 +49,9 @@ String DivConfig::toString() { return ret; } -const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - String DivConfig::toBase64() { String data=toString(); - String ret; - - ret.reserve((2+data.size()*4)/3); - - unsigned int groupOfThree=0; - unsigned char pos=0; - for (char& i: data) { - groupOfThree|=((unsigned char)i)<<((2-pos)<<3); - if (++pos>=3) { - pos=0; - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+=base64Table[(groupOfThree>>6)&63]; - ret+=base64Table[groupOfThree&63]; - groupOfThree=0; - } - } - if (pos==2) { - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+=base64Table[(groupOfThree>>6)&63]; - ret+='='; - } else if (pos==1) { - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+="=="; - } - - logV("toBase64: %s",ret); - - return ret; + return taEncodeBase64(data); } void DivConfig::parseLine(const char* line) { @@ -143,38 +112,7 @@ bool DivConfig::loadFromMemory(const char* buf) { } bool DivConfig::loadFromBase64(const char* buf) { - String data; - - unsigned int groupOfThree=0; - signed char pos=18; - for (const char* i=buf; *i; i++) { - unsigned char nextVal=0; - if ((*i)=='/') { - nextVal=63; - } else if ((*i)=='+') { - nextVal=62; - } else if ((*i)>='0' && (*i)<='9') { - nextVal=52+((*i)-'0'); - } else if ((*i)>='a' && (*i)<='z') { - nextVal=26+((*i)-'a'); - } else if ((*i)>='A' && (*i)<='Z') { - nextVal=((*i)-'A'); - } else { - nextVal=0; - } - groupOfThree|=nextVal<>16)&0xff) data+=(groupOfThree>>16)&0xff; - if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff; - if (groupOfThree&0xff) data+=groupOfThree&0xff; - groupOfThree=0; - } - } - - logV("fromBase64: %s",data); - + String data=taDecodeBase64(buf); return loadFromMemory(data.c_str()); } diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 1887e5b00..3090e1859 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1390,10 +1390,14 @@ String DivEngine::decodeSysDesc(String desc) { return newDesc.toBase64(); } -void DivEngine::initSongWithDesc(const char* description) { +void DivEngine::initSongWithDesc(const char* description, bool inBase64) { int chanCount=0; DivConfig c; - c.loadFromBase64(description); + if (inBase64) { + c.loadFromBase64(description); + } else { + c.loadFromMemory(description); + } int index=0; for (; index<32; index++) { song.system[index]=systemFromFileFur(c.getInt(fmt::sprintf("id%d",index),0)); @@ -1414,7 +1418,7 @@ void DivEngine::initSongWithDesc(const char* description) { song.systemLen=index; } -void DivEngine::createNew(const char* description, String sysName) { +void DivEngine::createNew(const char* description, String sysName, bool inBase64) { quitDispatch(); BUSY_BEGIN; saveLock.lock(); @@ -1422,7 +1426,7 @@ void DivEngine::createNew(const char* description, String sysName) { song=DivSong(); changeSong(0); if (description!=NULL) { - initSongWithDesc(description); + initSongWithDesc(description,inBase64); } if (sysName=="") { song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0)); @@ -2358,6 +2362,9 @@ void DivEngine::reset() { firstTick=false; shallStop=false; shallStopSched=false; + pendingMetroTick=0; + elapsedBars=0; + elapsedBeats=0; nextSpeed=speed1; divider=60; if (curSubSong->customTempo) { @@ -2548,6 +2555,14 @@ int DivEngine::getRow() { return prevRow; } +int DivEngine::getElapsedBars() { + return elapsedBars; +} + +int DivEngine::getElapsedBeats() { + return elapsedBeats; +} + size_t DivEngine::getCurrentSubSong() { return curSubSongIndex; } @@ -2673,12 +2688,17 @@ void DivEngine::unmuteAll() { BUSY_END; } -int DivEngine::addInstrument(int refChan) { +int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) { if (song.ins.size()>=256) return -1; BUSY_BEGIN; DivInstrument* ins=new DivInstrument; int insCount=(int)song.ins.size(); - DivInstrumentType prefType=getPreferInsType(refChan); + DivInstrumentType prefType; + if (refChan<0) { + prefType=fallbackType; + } else { + prefType=getPreferInsType(refChan); + } switch (prefType) { case DIV_INS_OPLL: *ins=song.nullInsOPLL; @@ -2692,8 +2712,10 @@ int DivEngine::addInstrument(int refChan) { default: break; } - if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) { - *ins=song.nullInsQSound; + if (refChan>=0) { + if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) { + *ins=song.nullInsQSound; + } } ins->name=fmt::sprintf("Instrument %d",insCount); if (prefType!=DIV_INS_NULL) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 510ef23a1..4a36b27d7 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -47,8 +47,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev122" -#define DIV_ENGINE_VERSION 122 +#define DIV_VERSION "dev125" +#define DIV_ENGINE_VERSION 125 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 @@ -351,14 +351,14 @@ class DivEngine { bool midiOutClock; int midiOutMode; int softLockCount; - int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed; + int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats; size_t curSubSongIndex; double divider; int cycles; double clockDrift; int stepPlay; int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch; - unsigned char extValue; + unsigned char extValue, pendingMetroTick; unsigned char speed1, speed2; short tempoAccum; DivStatusView view; @@ -382,9 +382,9 @@ class DivEngine { std::vector midiOuts; std::vector cmdStream; std::vector possibleInsTypes; - DivSysDef* sysDefs[256]; - DivSystem sysFileMapFur[256]; - DivSystem sysFileMapDMF[256]; + static DivSysDef* sysDefs[256]; + static DivSystem sysFileMapFur[256]; + static DivSystem sysFileMapDMF[256]; struct SamplePreview { double rate; @@ -440,8 +440,6 @@ class DivEngine { void reset(); void playSub(bool preserveDrift, int goalRow=0); - void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys); - bool loadDMF(unsigned char* file, size_t len); bool loadFur(unsigned char* file, size_t len); bool loadMod(unsigned char* file, size_t len); @@ -469,7 +467,7 @@ class DivEngine { bool deinitAudioBackend(bool dueToSwitchMaster=false); void registerSystems(); - void initSongWithDesc(const char* description); + void initSongWithDesc(const char* description, bool inBase64=true); void exchangeIns(int one, int two); void swapChannels(int src, int dest); @@ -503,7 +501,7 @@ class DivEngine { // parse old system setup description String decodeSysDesc(String desc); // start fresh - void createNew(const char* description, String sysName); + void createNew(const char* description, String sysName, bool inBase64=true); // load a file. bool load(unsigned char* f, size_t length); // save as .dmf. @@ -532,10 +530,14 @@ class DivEngine { void notifyWaveChange(int wave); // get system IDs - DivSystem systemFromFileFur(unsigned char val); - unsigned char systemToFileFur(DivSystem val); - DivSystem systemFromFileDMF(unsigned char val); - unsigned char systemToFileDMF(DivSystem val); + static DivSystem systemFromFileFur(unsigned char val); + static unsigned char systemToFileFur(DivSystem val); + static DivSystem systemFromFileDMF(unsigned char val); + static unsigned char systemToFileDMF(DivSystem val); + + // convert old flags + static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys); + // benchmark (returns time in seconds) double benchmarkPlayback(); @@ -709,6 +711,10 @@ class DivEngine { // get current row int getRow(); + // get beat/bar + int getElapsedBars(); + int getElapsedBeats(); + // get current subsong size_t getCurrentSubSong(); @@ -753,7 +759,7 @@ class DivEngine { bool isExporting(); // add instrument - int addInstrument(int refChan=0); + int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD); // add instrument from pointer int addInstrumentPtr(DivInstrument* which); @@ -1058,6 +1064,8 @@ class DivEngine { lastLoopPos(0), exportLoopCount(0), nextSpeed(3), + elapsedBars(0), + elapsedBeats(0), curSubSongIndex(0), divider(60), cycles(0), @@ -1073,6 +1081,7 @@ class DivEngine { cmdsPerSecond(0), globalPitch(0), extValue(0), + pendingMetroTick(0), speed1(3), speed2(3), tempoAccum(0), diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index fdc216ac1..a5502040b 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2383,11 +2383,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (isNewSample) { sample->centerRate=reader.readI(); sample->depth=(DivSampleDepth)reader.readC(); + if (ds.version>=123) { + sample->loopMode=(DivSampleLoopMode)reader.readC(); + } else { + sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; + reader.readC(); + } // reserved reader.readC(); reader.readC(); - reader.readC(); sample->loopStart=reader.readI(); sample->loopEnd=reader.readI(); @@ -2611,6 +2616,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // ExtCh compat flag + if (ds.version<125) { + for (int i=0; i>4)*10)+(fxVal&15)); @@ -4624,9 +4644,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(sample->rate); w->writeI(sample->centerRate); w->writeC(sample->depth); + w->writeC(sample->loopMode); w->writeC(0); // reserved w->writeC(0); - w->writeC(0); w->writeI(sample->loop?sample->loopStart:-1); w->writeI(sample->loop?sample->loopEnd:-1); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index c68799e23..fbc1e7dd0 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -285,7 +285,7 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].freqChanged=true; } } else { - if (chan[i].std.arp.had) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } @@ -1224,6 +1224,7 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) { break; } ladder=flags.getBool("ladderEffect",false); + noExtMacros=flags.getBool("noExtMacros",false); OPN2_SetChipType(ladder?ym3438_mode_ym2612:0); if (useYMFM) { if (fm_ymfm!=NULL) delete fm_ymfm; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 14e8dae5b..f4eb25d7a 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -116,7 +116,7 @@ class DivPlatformGenesis: public DivPlatformOPN { int softPCMTimer; - bool extMode, softPCM, useYMFM; + bool extMode, softPCM, noExtMacros, useYMFM; bool ladder; unsigned char dacVolTable[128]; diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 3e2714101..45a8898db 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -52,6 +52,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { chan[2].state.ams=ins->fm.ams; chan[2].state.op[ordch]=ins->fm.op[ordch]; } + + if (noExtMacros) { + opChan[ch].macroInit(NULL); + } else { + opChan[ch].macroInit(ins); + } + if (!opChan[ch].std.vol.will) { + opChan[ch].outVol=opChan[ch].vol; + } unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; @@ -60,7 +69,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -81,6 +90,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.value!=DIV_NOTE_NULL) { opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].portaPause=false; + opChan[ch].note=c.value; opChan[ch].freqChanged=true; } opChan[ch].keyOn=true; @@ -92,14 +102,28 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[ch].keyOn=false; opChan[ch].active=false; break; + case DIV_CMD_NOTE_OFF_ENV: + if (noExtMacros) break; + opChan[ch].keyOff=true; + opChan[ch].keyOn=false; + opChan[ch].active=false; + opChan[ch].std.release(); + break; + case DIV_CMD_ENV_RELEASE: + if (noExtMacros) break; + opChan[ch].std.release(); + break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; + if (!opChan[ch].std.vol.has) { + opChan[ch].outVol=c.value; + } unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } break; } @@ -210,7 +234,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (KVS(2,c.value)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -393,8 +417,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { rWrite(baseAddr+0x40,127); immWrite(baseAddr+0x40,127); } else if (KVS(2,ordch)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127)); - immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); + immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); immWrite(baseAddr+0x40,op.tl); @@ -438,6 +462,91 @@ void DivPlatformGenesisExt::tick(bool sysTick) { } } + if (extMode && !noExtMacros) for (int i=0; i<4; i++) { + opChan[i].std.next(); + + if (opChan[i].std.vol.had) { + opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127); + unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; + if (isOpMuted[i]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } + } + + if (opChan[i].std.arp.had) { + if (!opChan[i].inPorta) { + opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); + } + opChan[i].freqChanged=true; + } + + if (opChan[i].std.pitch.had) { + if (opChan[i].std.pitch.mode) { + opChan[i].pitch2+=opChan[i].std.pitch.val; + CLAMP_VAR(opChan[i].pitch2,-32768,32767); + } else { + opChan[i].pitch2=opChan[i].std.pitch.val; + } + opChan[i].freqChanged=true; + } + + // param macros + unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; + DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]]; + if (m.am.had) { + op.am=m.am.val; + rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); + } + if (m.ar.had) { + op.ar=m.ar.val; + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); + } + if (m.dr.had) { + op.dr=m.dr.val; + rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); + } + if (m.mult.had) { + op.mult=m.mult.val; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); + } + if (m.rr.had) { + op.rr=m.rr.val; + rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + if (m.sl.had) { + op.sl=m.sl.val; + rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + if (m.tl.had) { + op.tl=127-m.tl.val; + if (isOpMuted[i]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } + } + if (m.rs.had) { + op.rs=m.rs.val; + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); + } + if (m.dt.had) { + op.dt=m.dt.val; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); + } + if (m.d2r.had) { + op.d2r=m.d2r.val; + rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); + } + if (m.ssg.had) { + op.ssgEnv=m.ssg.val; + rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); + } + } + DivPlatformGenesis::tick(sysTick); bool writeNoteOn=false; @@ -527,7 +636,7 @@ void DivPlatformGenesisExt::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (KVS(i,j)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -601,7 +710,9 @@ void DivPlatformGenesisExt::reset() { for (int i=0; i<4; i++) { opChan[i]=DivPlatformGenesisExt::OpChannel(); + opChan[i].std.setEngine(parent); opChan[i].vol=127; + opChan[i].outVol=127; } // channel 3 mode diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 6f46402f8..fb68ecfff 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -25,11 +25,15 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins, note; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; - int vol; + int vol, outVol; unsigned char pan; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } OpChannel(): freqH(0), freqL(0), @@ -39,6 +43,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pitch2(0), portaPauseFreq(0), ins(-1), + note(0), active(false), insChanged(true), freqChanged(false), @@ -48,6 +53,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { inPorta(false), mask(true), vol(0), + outVol(0), pan(3) {} }; OpChannel opChan[4]; diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 42a9ac5cb..226ee98ca 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -587,7 +587,17 @@ bool DivPlatformPCSpeaker::keyOffAffectsArp(int ch) { } void DivPlatformPCSpeaker::setFlags(const DivConfig& flags) { - chipClock=COLOR_NTSC/3.0; + switch (flags.getInt("clockSel",0)) { + case 1: // PC-98 + chipClock=38400*52; + break; + case 2: // PC-98 + chipClock=38400*64; + break; + default: // IBM PC + chipClock=COLOR_NTSC/3.0; + break; + } rate=chipClock/PCSPKR_DIVIDER; speakerType=flags.getInt("speakerType",0)&3; oscBuf->rate=rate; diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d55e9349c..60cb13c58 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -129,7 +129,7 @@ void DivPlatformSMS::tick(bool sysTick) { if (chan[i].outVol<0) chan[i].outVol=0; // old formula // ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; - rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); + chan[i].writeVol=true; } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -235,6 +235,12 @@ void DivPlatformSMS::tick(bool sysTick) { chan[3].freqChanged=false; updateSNMode=false; } + for (int i=0; i<4; i++) { + if (chan[i].writeVol) { + rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); + chan[i].writeVol=false; + } + } } int DivPlatformSMS::dispatch(DivCommand c) { @@ -249,9 +255,11 @@ int DivPlatformSMS::dispatch(DivCommand c) { chan[c.chan].actualNote=c.value; } chan[c.chan].active=true; - if (!parent->song.brokenOutVol2) { - rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); - } + //if (!parent->song.brokenOutVol2) { + chan[c.chan].writeVol=true; + chan[c.chan].outVol=chan[c.chan].vol; + //rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + //} chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; @@ -276,7 +284,9 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + if (chan[c.chan].active) { + chan[c.chan].writeVol=true; + } } break; case DIV_CMD_GET_VOLUME: @@ -356,7 +366,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { void DivPlatformSMS::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (chan[ch].active) rWrite(0,0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15)))); + if (chan[ch].active) chan[ch].writeVol=true; } void DivPlatformSMS::forceIns() { diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 0a4b121f1..e636b9d88 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -31,7 +31,7 @@ extern "C" { class DivPlatformSMS: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, actualNote, ins; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, writeVol; signed char vol, outVol; DivMacroInt std; void macroInit(DivInstrument* which) { @@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch { keyOn(false), keyOff(false), inPorta(false), + writeVol(false), vol(15), outVol(15) {} }; diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index d3a5e5ed3..b3dc596c1 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -952,6 +952,7 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) { ayDiv=16; break; } + noExtMacros=flags.getBool("noExtMacros",false); rate=fm->sample_rate(chipClock); for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index b51a42343..b93e45ddb 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -91,7 +91,7 @@ class DivPlatformYM2203: public DivPlatformOPN { DivPlatformAY8910* ay; unsigned char sampleBank; - bool extMode; + bool extMode, noExtMacros; unsigned char prescale; friend void putDispatchChip(void*,int); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 79ae95111..a58bad8d6 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1394,6 +1394,7 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) { ayDiv=32; break; } + noExtMacros=flags.getBool("noExtMacros",false); rate=fm->sample_rate(chipClock); for (int i=0; i<16; i++) { oscBuf[i]->rate=rate; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 7a9eefa97..f4c101c20 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -106,7 +106,7 @@ class DivPlatformYM2608: public DivPlatformOPN { unsigned char writeRSSOff, writeRSSOn; int globalRSSVolume; - bool extMode; + bool extMode, noExtMacros; unsigned char prescale; double NOTE_OPNB(int ch, int note); diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 3641306ce..4b69920c9 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -141,7 +141,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { unsigned char sampleBank; - bool extMode; + bool extMode, noExtMacros; unsigned char writeADPCMAOff, writeADPCMAOn; int globalADPCMAVolume; @@ -269,6 +269,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { chipClock=8000000.0; break; } + noExtMacros=flags.getBool("noExtMacros",false); rate=chipClock/16; for (int i=0; irate=rate; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1f5953fc8..489758130 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -975,6 +975,20 @@ void DivEngine::nextRow() { printf("| %.2x:%s | \x1b[1;33m%3d%s\x1b[m\n",curOrder,pb1,curRow,pb3); } + if (curSubSong->hilightA>0) { + if ((curRow%curSubSong->hilightA)==0) { + pendingMetroTick=1; + elapsedBeats++; + } + } + if (curSubSong->hilightB>0) { + if ((curRow%curSubSong->hilightB)==0) { + pendingMetroTick=2; + elapsedBars++; + elapsedBeats=0; + } + } + prevOrder=curOrder; prevRow=curRow; @@ -1608,16 +1622,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi // 2. check whether we gonna tick if (cycles<=0) { // we have to tick - if (!freelance && stepPlay!=-1 && subticks==1) { - unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC); - if (realPos>=size) realPos=size-1; - if (curSubSong->hilightA>0) { - if ((curRow%curSubSong->hilightA)==0 && ticks==1) metroTick[realPos]=1; - } - if (curSubSong->hilightB>0) { - if ((curRow%curSubSong->hilightB)==0 && ticks==1) metroTick[realPos]=2; - } - } if (nextTick()) { lastLoopPos=size-(runLeftG>>MASTER_CLOCK_PREC); logD("last loop pos: %d for a size of %d and runLeftG of %d",lastLoopPos,size,runLeftG); @@ -1634,6 +1638,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } + if (pendingMetroTick) { + unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC); + if (realPos>=size) realPos=size-1; + metroTick[realPos]=pendingMetroTick; + pendingMetroTick=0; + } } else { // 3. tick the clock and fill buffers as needed if (cycles= 0) disCont[VERA].dispatch->toggleRegisterDump(true); if (YM >= 0) { disCont[YM].dispatch->toggleRegisterDump(true); - zsm.writeYM(0x18,0); // initialize the LFO freq to 0 - // note - I think there's a bug where Furnace writes AMD/PMD=max - // that shouldn't be there, requiring this initialization that shouldn't - // be there for ZSM. + // emit LFO initialization commands + zsm.writeYM(0x18,0); // freq = 0 + zsm.writeYM(0x19,0x7F); // AMD = 7F + zsm.writeYM(0x19,0xFF); // PMD = 7F + // TODO: incorporate the Furnace meta-command for init data and filter + // out writes to otherwise-unused channels. } while (!done) { diff --git a/src/gui/about.cpp b/src/gui/about.cpp index d5bac49e6..924f2c0cc 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -66,6 +66,7 @@ const char* aboutLine[]={ "BlueElectric05", "breakthetargets", "brickblock369", + "Burnt Fishy", "CaptainMalware", "DeMOSic", "DevEd", @@ -91,6 +92,7 @@ const char* aboutLine[]={ "Raijin", "SnugglyBun", "SuperJet Spade", + "TakuikaNinja", "TheDuccinator", "theloredev", "TheRealHedgehogSonic", @@ -153,7 +155,6 @@ const char* aboutLine[]={ "MSM6295 emulator by cam900", "", "greetings to:", - "Fractal Sound team", "NEOART Costa Rica", "all members of Deflers of Noice!", "", diff --git a/src/gui/clock.cpp b/src/gui/clock.cpp new file mode 100644 index 000000000..e8450d10a --- /dev/null +++ b/src/gui/clock.cpp @@ -0,0 +1,116 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "gui.h" +#include "imgui_internal.h" +#include "imgui.h" + +void FurnaceGUI::drawClock() { + if (nextWindow==GUI_WINDOW_CLOCK) { + clockOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!clockOpen) return; + if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) { + int row=e->getRow(); + int elapsedBars=e->getElapsedBars(); + int elapsedBeats=e->getElapsedBeats(); + bool playing=e->isPlaying(); + if (clockShowRow) { + ImGui::PushFont(bigFont); + ImGui::Text("%.3d:%.3d",e->getOrder(),row); + ImGui::PopFont(); + } + if (clockShowBeat) { + ImGui::PushFont(bigFont); + ImGui::Text("%.3d:%.1d",elapsedBars,elapsedBeats+1); + ImGui::PopFont(); + } + if (clockShowMetro) { + ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 size=ImGui::GetContentRegionAvail(); + size.y=12.0f*dpiScale; + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + /*ImRect inRect=rect; + inRect.Min.x+=dpiScale; + inRect.Min.y+=dpiScale; + inRect.Max.x-=dpiScale; + inRect.Max.y-=dpiScale;*/ + ImGuiStyle& style=ImGui::GetStyle(); + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("metroQ"))) { + int h1=e->curSubSong->hilightA; + int h2=e->curSubSong->hilightB; + if (h1>0 && h2>0) { + int beats=(h2+(h1-1))/h1; + if (beats<0) beats=1; + if (beats>16) beats=16; + if (playing) { + if (elapsedBeats!=oldBeat || elapsedBars!=oldBar) { + if (elapsedBeats>15) elapsedBeats=15; + clockMetroTick[elapsedBeats]=1.0f; + oldBeat=elapsedBeats; + oldBar=elapsedBars; + } + } else { + oldBeat=-1; + oldBar=-1; + } + for (int i=0; iAddQuadFilled( + ImLerp(minB,maxB,ImVec2(0.35f,0.0f)), + ImLerp(minB,maxB,ImVec2(0.9f,0.0f)), + ImLerp(minB,maxB,ImVec2(0.65f,1.0f)), + ImLerp(minB,maxB,ImVec2(0.1f,1.0f)), + ImGui::GetColorU32(col) + ); + + if (elapsedBeats==i && playing) { + clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f; + if (clockMetroTick[i]<0.3f) clockMetroTick[i]=0.3f; + } else { + clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f; + if (clockMetroTick[i]<0.0f) clockMetroTick[i]=0.0f; + } + } + } + } + } + if (clockShowTime) { + int totalTicks=e->getTotalTicks(); + int totalSeconds=e->getTotalSeconds(); + ImGui::PushFont(bigFont); + ImGui::Text("%.2d:%.2d.%.2d",(totalSeconds/60),totalSeconds%60,totalTicks/10000); + ImGui::PopFont(); + } + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SPOILER; + ImGui::End(); +} diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 8a62c822f..20f66dd59 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -60,6 +60,11 @@ void FurnaceGUI::drawInsList(bool asChild) { } ImGui::EndPopup(); } + } else { + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + displayInsTypeList=true; + displayInsTypeListMakeInsSample=-1; + } } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FILES_O "##InsClone")) { diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index d4145276b..941d037c5 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1291,14 +1291,54 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_SAMPLE_MAKE_INS: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; + // determine instrument type + std::vector tempTypeList=e->getPossibleInsTypes(); + makeInsTypeList.clear(); + + for (DivInstrumentType& i: tempTypeList) { + if (i==DIV_INS_PCE || + i==DIV_INS_MSM6258 || + i==DIV_INS_MSM6295 || + i==DIV_INS_ADPCMA || + i==DIV_INS_ADPCMB || + i==DIV_INS_SEGAPCM || + i==DIV_INS_QSOUND || + i==DIV_INS_YMZ280B || + i==DIV_INS_RF5C68 || + i==DIV_INS_MULTIPCM || + i==DIV_INS_MIKEY || + i==DIV_INS_X1_010 || + i==DIV_INS_SWAN || + i==DIV_INS_AY || + i==DIV_INS_AY8930 || + i==DIV_INS_VRC6 || + i==DIV_INS_SU || + i==DIV_INS_SNES || + i==DIV_INS_ES5506) { + makeInsTypeList.push_back(i); + } + } + + if (makeInsTypeList.size()>1) { + displayInsTypeList=true; + displayInsTypeListMakeInsSample=curSample; + break; + } + + DivInstrumentType insType=DIV_INS_AMIGA; + if (!makeInsTypeList.empty()) { + insType=makeInsTypeList[0]; + } + DivSample* sample=e->song.sample[curSample]; curIns=e->addInstrument(cursor.xCoarse); if (curIns==-1) { showError("too many instruments!"); } else { - e->song.ins[curIns]->type=DIV_INS_AMIGA; + e->song.ins[curIns]->type=insType; e->song.ins[curIns]->name=sample->name; e->song.ins[curIns]->amiga.initSample=curSample; + if (insType!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true; nextWindow=GUI_WINDOW_INS_EDIT; MARK_MODIFIED; wavePreviewInit=true; diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 86a7325ec..fe72351a6 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -242,6 +242,7 @@ void FurnaceGUI::drawMobileControls() { ImGui::SameLine(); if (ImGui::Button("Settings")) { mobileMenuOpen=false; + settingsOpen=true; } ImGui::SameLine(); if (ImGui::Button("Log")) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 30cb0850b..93c333689 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2651,8 +2651,11 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { #ifdef IS_MOBILE - if (ev->type==SDL_APP_WILLENTERBACKGROUND) { - // TODO: save "last state" and potentially suspend engine + if (ev->type==SDL_APP_TERMINATING) { + // TODO: save last song state here + } else if (ev->type==SDL_APP_WILLENTERBACKGROUND) { + commitState(); + e->saveConf(); } #endif if (ev->type==SDL_KEYDOWN) { @@ -2958,7 +2961,11 @@ bool FurnaceGUI::detectOutOfBoundsWindow() { } bool FurnaceGUI::loop() { +#ifdef IS_MOBILE + bool doThreadedInput=true; +#else bool doThreadedInput=!settings.noThreadedInput; +#endif if (doThreadedInput) { logD("key input: event filter"); SDL_SetEventFilter(_processEvent,this); @@ -3620,6 +3627,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("oscilloscope (master)",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; if (ImGui::MenuItem("oscilloscope (per-channel)",BIND_FOR(GUI_ACTION_WINDOW_CHAN_OSC),chanOscOpen)) chanOscOpen=!chanOscOpen; if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; + if (ImGui::MenuItem("clock",BIND_FOR(GUI_ACTION_WINDOW_CLOCK),clockOpen)) clockOpen=!clockOpen; if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; @@ -3747,6 +3755,7 @@ bool FurnaceGUI::loop() { } globalWinFlags=0; + drawSettings(); drawDebug(); drawLog(); } else { @@ -3782,6 +3791,7 @@ bool FurnaceGUI::loop() { drawChannels(); drawPatManager(); drawSysManager(); + drawClock(); drawRegView(); drawLog(); drawEffectList(); @@ -4399,6 +4409,11 @@ bool FurnaceGUI::loop() { ImGui::OpenPopup("Import Raw Sample"); } + if (displayInsTypeList) { + displayInsTypeList=false; + ImGui::OpenPopup("InsTypeList"); + } + if (displayExporting) { displayExporting=false; ImGui::OpenPopup("Rendering..."); @@ -4428,9 +4443,14 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } - ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(canvasW,canvasH)); + ImVec2 newSongMinSize=mobileUI?ImVec2(canvasW-(portrait?0:(60.0*dpiScale)),canvasH-60.0*dpiScale):ImVec2(400.0f*dpiScale,200.0f*dpiScale); + ImVec2 newSongMaxSize=ImVec2(canvasW-((mobileUI && !portrait)?(60.0*dpiScale):0),canvasH-(mobileUI?(60.0*dpiScale):0)); + ImGui::SetNextWindowSizeConstraints(newSongMinSize,newSongMaxSize); if (ImGui::BeginPopupModal("New Song",NULL,ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) { ImGui::SetWindowPos(ImVec2(((canvasW)-ImGui::GetWindowSize().x)*0.5,((canvasH)-ImGui::GetWindowSize().y)*0.5)); + if (ImGui::GetWindowSize().xaddInstrument(-1,i); + if (curIns==-1) { + showError("too many instruments!"); + } else { + if (displayInsTypeListMakeInsSample>=0 && displayInsTypeListMakeInsSample<(int)e->song.sample.size()) { + e->song.ins[curIns]->type=i; + e->song.ins[curIns]->name=e->song.sample[displayInsTypeListMakeInsSample]->name; + e->song.ins[curIns]->amiga.initSample=displayInsTypeListMakeInsSample; + if (i!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true; + nextWindow=GUI_WINDOW_INS_EDIT; + wavePreviewInit=true; + } + MARK_MODIFIED; + } + } + } + ImGui::EndPopup(); + } + // TODO: // - multiple selection // - replace instrument @@ -5020,6 +5065,7 @@ bool FurnaceGUI::init() { channelsOpen=e->getConfBool("channelsOpen",false); patManagerOpen=e->getConfBool("patManagerOpen",false); sysManagerOpen=e->getConfBool("sysManagerOpen",false); + clockOpen=e->getConfBool("clockOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); logOpen=e->getConfBool("logOpen",false); effectListOpen=e->getConfBool("effectListOpen",false); @@ -5333,15 +5379,10 @@ bool FurnaceGUI::init() { return true; } -bool FurnaceGUI::finish() { +void FurnaceGUI::commitState() { if (!mobileUI) { ImGui::SaveIniSettingsToDisk(finalLayoutPath); } - ImGui_ImplSDLRenderer_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - SDL_DestroyRenderer(sdlRend); - SDL_DestroyWindow(sdlWin); e->setConf("configVersion",(int)DIV_ENGINE_VERSION); @@ -5383,6 +5424,7 @@ bool FurnaceGUI::finish() { e->setConf("channelsOpen",channelsOpen); e->setConf("patManagerOpen",patManagerOpen); e->setConf("sysManagerOpen",sysManagerOpen); + e->setConf("clockOpen",clockOpen); e->setConf("regViewOpen",regViewOpen); e->setConf("logOpen",logOpen); e->setConf("effectListOpen",effectListOpen); @@ -5454,6 +5496,15 @@ bool FurnaceGUI::finish() { e->setConf(key,recentFile[i]); } } +} + +bool FurnaceGUI::finish() { + commitState(); + ImGui_ImplSDLRenderer_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + SDL_DestroyRenderer(sdlRend); + SDL_DestroyWindow(sdlWin); for (int i=0; i definition; - FurnaceGUISysDef(const char* n, std::initializer_list def): - name(n), definition(def) { - } + String definition; + FurnaceGUISysDef(const char* n, std::initializer_list def); + FurnaceGUISysDef(const char* n, std::initializer_list def); }; struct FurnaceGUISysCategory { @@ -945,6 +961,12 @@ struct FurnaceGUIMacroDesc { } }; +struct FurnaceGUIMacroEditState { + int selectedMacro; + FurnaceGUIMacroEditState(): + selectedMacro(0) {} +}; + enum FurnaceGUIFindQueryModes { GUI_QUERY_IGNORE=0, GUI_QUERY_MATCH, @@ -1033,9 +1055,11 @@ class FurnaceGUI { std::vector sysSearchResults; std::vector newSongSearchResults; std::deque recentFile; + std::vector makeInsTypeList; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, vgmExportPatternHints; - bool vgmExportDirectStream; + bool vgmExportDirectStream, displayInsTypeList; bool portrait, injectBackUp, mobileMenuOpen; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; @@ -1046,6 +1070,7 @@ class FurnaceGUI { int zsmExportTickRate; int macroPointSize; int waveEditStyle; + int displayInsTypeListMakeInsSample; float mobileMenuPos, autoButtonSize; const int* curSysSection; @@ -1216,6 +1241,7 @@ class FurnaceGUI { int persistFadeOut; int exportLoops; double exportFadeOut; + int macroLayout; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1346,6 +1372,7 @@ class FurnaceGUI { persistFadeOut(1), exportLoops(0), exportFadeOut(0.0), + macroLayout(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -1367,7 +1394,7 @@ class FurnaceGUI { int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget; - int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY; + int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY, oldBeat, oldBar; double exportFadeOut; @@ -1375,7 +1402,10 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen; + bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen; + + bool clockShowReal, clockShowRow, clockShowBeat, clockShowMetro, clockShowTime; + float clockMetroTick[16]; SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1387,7 +1417,7 @@ class FurnaceGUI { float patChanX[DIV_MAX_CHANS+1]; float patChanSlideY[DIV_MAX_CHANS+1]; float lastPatternWidth; - const int* nextDesc; + String nextDesc; String nextDescName; OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue; @@ -1511,6 +1541,8 @@ class FurnaceGUI { int macroLoopDragLen; bool macroLoopDragActive; + FurnaceGUIMacroEditState macroEditStateFM, macroEditStateOP[4], macroEditStateMacros; + ImVec2 waveDragStart; ImVec2 waveDragAreaSize; int* waveDragTarget; @@ -1675,7 +1707,8 @@ class FurnaceGUI { void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel); - void drawMacros(std::vector& macros); + void drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index); + void drawMacros(std::vector& macros, FurnaceGUIMacroEditState& state); void actualWaveList(); void actualSampleList(); @@ -1717,6 +1750,7 @@ class FurnaceGUI { void drawSubSongs(); void drawFindReplace(); void drawSpoiler(); + void drawClock(); void parseKeybinds(); void promptKey(int which); @@ -1736,6 +1770,7 @@ class FurnaceGUI { void syncSettings(); void commitSettings(); + void commitState(); void processDrags(int dragX, int dragY); void processPoint(SDL_Event& ev); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index dee644f7e..dfc27b3b7 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -513,6 +513,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_CHAN_OSC", "Oscilloscope (per-channel)", 0), D("WINDOW_SUBSONGS", "Subsongs", 0), D("WINDOW_FIND", "Find/Replace", FURKMOD_CMD|SDLK_f), + D("WINDOW_CLOCK", "Clock", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), @@ -874,6 +875,10 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE,"",ImVec4(0.5f,0.5f,0.5f,1.0f)), D(GUI_COLOR_PIANO_KEY_TOP_ACTIVE,"",ImVec4(0.4f,0.4f,0.4f,1.0f)), + D(GUI_COLOR_CLOCK_TEXT,"",ImVec4(1.0f,1.0f,1.0f,1.0f)), + D(GUI_COLOR_CLOCK_BEAT_LOW,"",ImVec4(0.1f,0.13f,0.25f,1.0f)), + D(GUI_COLOR_CLOCK_BEAT_HIGH,"",ImVec4(0.5f,0.8f,1.0f,1.0f)), + D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)), D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)), D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1bb852f99..efee89a36 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -411,7 +411,7 @@ String macroLFOWaves(int id, float val, void* u) { case 1: return "Square"; case 2: - return "Sine"; + return "Triangle"; case 3: return "Random"; default: @@ -1294,518 +1294,668 @@ void FurnaceGUI::kvsConfig(DivInstrument* ins) { } } -void FurnaceGUI::drawMacros(std::vector& macros) { - float asFloat[256]; - int asInt[256]; - float loopIndicator[256]; - float bit30Indicator[256]; - bool doHighlight[256]; - int index=0; +void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index) { + static float asFloat[256]; + static int asInt[256]; + static float loopIndicator[256]; + static float bit30Indicator[256]; + static bool doHighlight[256]; - float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; - - if (ImGui::BeginTable("MacroSpace",2)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - float lenAvail=ImGui::GetContentRegionAvail().x; - //ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); - ImGui::SetNextItemWidth(120.0f*dpiScale); - if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) { - if (macroPointSize<1) macroPointSize=1; - if (macroPointSize>256) macroPointSize=256; - } - ImGui::TableNextColumn(); - float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; - int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); - if (macroDragScroll>255-totalFit) { - macroDragScroll=255-totalFit; - } - ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { - if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; - } - - // draw macros - for (FurnaceGUIMacroDesc& i: macros) { - ImGui::PushID(index); - ImGui::TableNextRow(); - - // description - ImGui::TableNextColumn(); - ImGui::Text("%s",i.displayName); - ImGui::SameLine(); - if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { - i.macro->open^=1; + if ((i.macro->open&6)==0) { + for (int j=0; j<256; j++) { + bit30Indicator[j]=0; + if (j+macroDragScroll>=i.macro->len) { + asFloat[j]=0; + asInt[j]=0; + } else { + asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); + asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; + if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); } - if (i.macro->open&1) { - if ((i.macro->open&6)==0) { - ImGui::SetNextItemWidth(lenAvail); - int macroLen=i.macro->len; - if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED - if (macroLen<0) macroLen=0; - if (macroLen>255) macroLen=255; - i.macro->len=macroLen; - } - } - if (ImGui::Button(macroTypeLabels[(i.macro->open>>1)&3])) { - unsigned char prevOpen=i.macro->open; - i.macro->open+=2; - if (i.macro->open>=6) { - i.macro->open-=6; - } + if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { + loopIndicator[j]=0; + } else { + loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); + } + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - // check whether macro type is now ADSR/LFO or sequence - if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { - // swap memory - // this way the macro isn't corrupted if the user decides to go - // back to sequence mode - i.macro->len^=i.macro->lenMemory; - i.macro->lenMemory^=i.macro->len; - i.macro->len^=i.macro->lenMemory; + if (i.macro->vZoom<1) { + if (i.macro->name=="arp") { + i.macro->vZoom=24; + i.macro->vScroll=120-12; + } else if (i.macro->name=="pitch") { + i.macro->vZoom=128; + i.macro->vScroll=2048-64; + } else { + i.macro->vZoom=i.max-i.min; + i.macro->vScroll=0; + } + } + if (i.macro->vZoom>(i.max-i.min)) { + i.macro->vZoom=i.max-i.min; + } - for (int j=0; j<16; j++) { - i.macro->val[j]^=i.macro->typeMemory[j]; - i.macro->typeMemory[j]^=i.macro->val[j]; - i.macro->val[j]^=i.macro->typeMemory[j]; - } - - // if ADSR/LFO, populate min/max - if (i.macro->open&6) { - i.macro->val[0]=i.min; - i.macro->val[1]=i.max; + memset(doHighlight,0,256*sizeof(bool)); + if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { + DivChannelState* chanState=e->getChanState(j); + if (chanState==NULL) continue; + + if (chanState->keyOff) continue; + if (chanState->lastIns!=curIns) continue; + + DivMacroInt* macroInt=e->getMacroInt(j); + if (macroInt==NULL) continue; + + DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name); + if (macroStruct==NULL) continue; + + if (macroStruct->lastPos>i.macro->len) continue; + if (macroStruct->lastPoslastPos>255) continue; + if (!macroStruct->actualHad) continue; + + doHighlight[macroStruct->lastPos-macroDragScroll]=true; + } + + if (i.isBitfield) { + PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); + } else { + PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight); + } + if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale); + if (i.isBitfield) { + macroDragMin=i.min; + macroDragMax=i.max; + } else { + macroDragMin=i.min+i.macro->vScroll; + macroDragMax=i.min+i.macro->vScroll+i.macro->vZoom; + } + macroDragBitOff=i.bitOffset; + macroDragBitMode=i.isBitfield; + macroDragInitialValueSet=false; + macroDragInitialValue=false; + macroDragLen=totalFit; + macroDragActive=true; + macroDragBit30=i.bit30; + macroDragSettingBit30=false; + macroDragTarget=i.macro->val; + macroDragChar=false; + macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); + macroDragLineInitial=ImVec2(0,0); + lastMacroDesc=i; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } + if ((i.macro->open&1)) { + if (ImGui::IsItemHovered()) { + if (ctrlWheeling) { + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + i.macro->vZoom+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vZoom<1) i.macro->vZoom=1; + if (i.macro->vZoom>(i.max-i.min)) i.macro->vZoom=i.max-i.min; + if ((i.macro->vScroll+i.macro->vZoom)>(i.max-i.min)) { + i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } + } else { + macroPointSize+=wheelY; + if (macroPointSize<1) macroPointSize=1; + if (macroPointSize>256) macroPointSize=256; } - PARAMETER; - } - if (ImGui::IsItemHovered()) { - switch (i.macro->open&6) { - case 0: - ImGui::SetTooltip("Macro type: Sequence"); - break; - case 2: - ImGui::SetTooltip("Macro type: ADSR"); - break; - case 4: - ImGui::SetTooltip("Macro type: LFO"); - break; - default: - ImGui::SetTooltip("Macro type: What's going on here?"); - break; - } - } - if (i.macro->open&6) { - i.macro->len=16; - } - ImGui::SameLine(); - ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Delay/Step Length"); - } - if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { - if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { - if (i.macro->speed<1) i.macro->speed=1; - MARK_MODIFIED; - } - if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { - MARK_MODIFIED; - } - ImGui::EndPopup(); - } - // do not change this! - // anything other than a checkbox will look ugly! - // if you really need more than two macro modes please tell me. - if (i.modeName!=NULL) { - bool modeVal=i.macro->mode; - String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); - if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { - i.macro->mode=modeVal; - } + } else if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && wheelY!=0) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } } - // macro area - ImGui::TableNextColumn(); - if ((i.macro->open&6)==0) { - for (int j=0; j<256; j++) { - bit30Indicator[j]=0; - if (j+macroDragScroll>=i.macro->len) { - asFloat[j]=0; - asInt[j]=0; - } else { - asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); - asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; - if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); + // slider + if (!i.isBitfield) { + if (settings.oldMacroVSlider) { + ImGui::SameLine(0.0f); + if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) { + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { - loopIndicator[j]=0; - } else { - loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); + if (ImGui::IsItemHovered() && ctrlWheeling) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - } - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - - if (i.macro->vZoom<1) { - if (i.macro->name=="arp") { - i.macro->vZoom=24; - i.macro->vScroll=120-12; - } else if (i.macro->name=="pitch") { - i.macro->vZoom=128; - i.macro->vScroll=2048-64; - } else { - i.macro->vZoom=i.max-i.min; - i.macro->vScroll=0; - } - } - if (i.macro->vZoom>(i.max-i.min)) { - i.macro->vZoom=i.max-i.min; - } - - memset(doHighlight,0,256*sizeof(bool)); - if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { - DivChannelState* chanState=e->getChanState(j); - if (chanState==NULL) continue; - - if (chanState->keyOff) continue; - if (chanState->lastIns!=curIns) continue; - - DivMacroInt* macroInt=e->getMacroInt(j); - if (macroInt==NULL) continue; - - DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name); - if (macroStruct==NULL) continue; - - if (macroStruct->lastPos>i.macro->len) continue; - if (macroStruct->lastPoslastPos>255) continue; - if (!macroStruct->actualHad) continue; - - doHighlight[macroStruct->lastPos-macroDragScroll]=true; - } - - if (i.isBitfield) { - PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); } else { - PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight); - } - if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { - macroDragStart=ImGui::GetItemRectMin(); - macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale); - if (i.isBitfield) { - macroDragMin=i.min; - macroDragMax=i.max; - } else { - macroDragMin=i.min+i.macro->vScroll; - macroDragMax=i.min+i.macro->vScroll+i.macro->vZoom; + ImS64 scrollV=(i.max-i.min-i.macro->vZoom)-i.macro->vScroll; + ImS64 availV=i.macro->vZoom; + ImS64 contentsV=(i.max-i.min); + + ImGui::SameLine(0.0f); + ImGui::SetCursorPosX(ImGui::GetCursorPosX()-ImGui::GetStyle().ItemSpacing.x); + ImRect scrollbarPos=ImRect(ImGui::GetCursorScreenPos(),ImGui::GetCursorScreenPos()); + scrollbarPos.Max.x+=ImGui::GetStyle().ScrollbarSize; + scrollbarPos.Max.y+=i.height*dpiScale; + ImGui::Dummy(ImVec2(ImGui::GetStyle().ScrollbarSize,i.height*dpiScale)); + if (ImGui::IsItemHovered() && ctrlWheeling) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - macroDragBitOff=i.bitOffset; - macroDragBitMode=i.isBitfield; + + ImGuiID scrollbarID=ImGui::GetID("IMacroVScroll"); + ImGui::KeepAliveID(scrollbarID); + if (ImGui::ScrollbarEx(scrollbarPos,scrollbarID,ImGuiAxis_Y,&scrollV,availV,contentsV,0)) { + i.macro->vScroll=(i.max-i.min-i.macro->vZoom)-scrollV; + } + } + } + + // bit 30 area + if (i.bit30) { + PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=totalFit; macroDragActive=true; macroDragBit30=i.bit30; - macroDragSettingBit30=false; + macroDragSettingBit30=true; macroDragTarget=i.macro->val; macroDragChar=false; - macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); + macroDragLineMode=false; macroDragLineInitial=ImVec2(0,0); lastMacroDesc=i; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - if ((i.macro->open&1)) { - if (ImGui::IsItemHovered()) { - if (ctrlWheeling) { - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->vZoom+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vZoom<1) i.macro->vZoom=1; - if (i.macro->vZoom>(i.max-i.min)) i.macro->vZoom=i.max-i.min; - if ((i.macro->vScroll+i.macro->vZoom)>(i.max-i.min)) { - i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } else { - macroPointSize+=wheelY; - if (macroPointSize<1) macroPointSize=1; - if (macroPointSize>256) macroPointSize=256; - } - } else if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && wheelY!=0) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } + } - // slider - if (!i.isBitfield) { - if (settings.oldMacroVSlider) { - ImGui::SameLine(0.0f); - if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) { - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - if (ImGui::IsItemHovered() && ctrlWheeling) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } else { - ImS64 scrollV=(i.max-i.min-i.macro->vZoom)-i.macro->vScroll; - ImS64 availV=i.macro->vZoom; - ImS64 contentsV=(i.max-i.min); - - ImGui::SameLine(0.0f); - ImGui::SetCursorPosX(ImGui::GetCursorPosX()-ImGui::GetStyle().ItemSpacing.x); - ImRect scrollbarPos=ImRect(ImGui::GetCursorScreenPos(),ImGui::GetCursorScreenPos()); - scrollbarPos.Max.x+=ImGui::GetStyle().ScrollbarSize; - scrollbarPos.Max.y+=i.height*dpiScale; - ImGui::Dummy(ImVec2(ImGui::GetStyle().ScrollbarSize,i.height*dpiScale)); - if (ImGui::IsItemHovered() && ctrlWheeling) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - - ImGuiID scrollbarID=ImGui::GetID("IMacroVScroll"); - ImGui::KeepAliveID(scrollbarID); - if (ImGui::ScrollbarEx(scrollbarPos,scrollbarID,ImGuiAxis_Y,&scrollV,availV,contentsV,0)) { - i.macro->vScroll=(i.max-i.min-i.macro->vZoom)-scrollV; - } - } - } - - // bit 30 area - if (i.bit30) { - PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroDragStart=ImGui::GetItemRectMin(); - macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); - macroDragInitialValueSet=false; - macroDragInitialValue=false; - macroDragLen=totalFit; - macroDragActive=true; - macroDragBit30=i.bit30; - macroDragSettingBit30=true; - macroDragTarget=i.macro->val; - macroDragChar=false; - macroDragLineMode=false; - macroDragLineInitial=ImVec2(0,0); - lastMacroDesc=i; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); - } - } - - // loop area - PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroLoopDragStart=ImGui::GetItemRectMin(); - macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); - macroLoopDragLen=totalFit; - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - macroLoopDragTarget=&i.macro->rel; - } else { - macroLoopDragTarget=&i.macro->loop; - } - macroLoopDragActive=true; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); - } - if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->rel=255; - } else { - i.macro->loop=255; - } - } - ImGui::SetNextItemWidth(availableWidth); - String& mmlStr=mmlString[index]; - if (ImGui::InputText("##IMacroMML",&mmlStr)) { - decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); - } - if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); - } + // loop area + PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); + macroLoopDragLen=totalFit; + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + macroLoopDragTarget=&i.macro->rel; + } else { + macroLoopDragTarget=&i.macro->loop; } - ImGui::PopStyleVar(); - } else { - if (i.macro->open&2) { - if (ImGui::BeginTable("MacroADSR",4)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); - //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Bottom"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER - if (i.macro->val[0]val[0]=i.min; - if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; - } - - ImGui::TableNextColumn(); - ImGui::Text("Top"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER - if (i.macro->val[1]val[1]=i.min; - if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; - } - - /*ImGui::TableNextColumn(); - ImGui::Text("the envelope goes here");*/ - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Attack"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER - if (i.macro->val[2]<0) i.macro->val[2]=0; - if (i.macro->val[2]>255) i.macro->val[2]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("Sustain"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER - if (i.macro->val[5]<0) i.macro->val[5]=0; - if (i.macro->val[5]>255) i.macro->val[5]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Hold"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER - if (i.macro->val[3]<0) i.macro->val[3]=0; - if (i.macro->val[3]>255) i.macro->val[3]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("SusTime"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER - if (i.macro->val[6]<0) i.macro->val[6]=0; - if (i.macro->val[6]>255) i.macro->val[6]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Decay"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER - if (i.macro->val[4]<0) i.macro->val[4]=0; - if (i.macro->val[4]>255) i.macro->val[4]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("SusDecay"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER - if (i.macro->val[7]<0) i.macro->val[7]=0; - if (i.macro->val[7]>255) i.macro->val[7]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - - ImGui::TableNextColumn(); - ImGui::Text("Release"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER - if (i.macro->val[8]<0) i.macro->val[8]=0; - if (i.macro->val[8]>255) i.macro->val[8]=255; - } - - ImGui::EndTable(); - } - } - if (i.macro->open&4) { - if (ImGui::BeginTable("MacroLFO",4)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); - //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Bottom"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER - if (i.macro->val[0]val[0]=i.min; - if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; - } - - ImGui::TableNextColumn(); - ImGui::Text("Top"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER - if (i.macro->val[1]val[1]=i.min; - if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; - } - - /*ImGui::TableNextColumn(); - ImGui::Text("the envelope goes here");*/ - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Speed"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER - if (i.macro->val[11]<0) i.macro->val[11]=0; - if (i.macro->val[11]>255) i.macro->val[11]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("Phase"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER - if (i.macro->val[13]<0) i.macro->val[13]=0; - if (i.macro->val[13]>1023) i.macro->val[13]=1023; - } - - ImGui::TableNextColumn(); - ImGui::Text("Shape"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER - if (i.macro->val[12]<0) i.macro->val[12]=0; - if (i.macro->val[12]>2) i.macro->val[12]=2; - } - - ImGui::EndTable(); - } + macroLoopDragActive=true; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + i.macro->rel=255; + } else { + i.macro->loop=255; } } - ImGui::PopID(); - index++; + ImGui::SetNextItemWidth(availableWidth); + String& mmlStr=mmlString[index]; + if (ImGui::InputText("##IMacroMML",&mmlStr)) { + decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); + } + if (!ImGui::IsItemActive()) { + encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); + } } + ImGui::PopStyleVar(); + } else { + if (i.macro->open&2) { + if (ImGui::BeginTable("MacroADSR",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); + //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { - if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Bottom"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER + if (i.macro->val[0]val[0]=i.min; + if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; + } + + ImGui::TableNextColumn(); + ImGui::Text("Top"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER + if (i.macro->val[1]val[1]=i.min; + if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; + } + + /*ImGui::TableNextColumn(); + ImGui::Text("the envelope goes here");*/ + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Attack"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER + if (i.macro->val[2]<0) i.macro->val[2]=0; + if (i.macro->val[2]>255) i.macro->val[2]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("Sustain"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER + if (i.macro->val[5]<0) i.macro->val[5]=0; + if (i.macro->val[5]>255) i.macro->val[5]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Hold"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER + if (i.macro->val[3]<0) i.macro->val[3]=0; + if (i.macro->val[3]>255) i.macro->val[3]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("SusTime"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER + if (i.macro->val[6]<0) i.macro->val[6]=0; + if (i.macro->val[6]>255) i.macro->val[6]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Decay"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER + if (i.macro->val[4]<0) i.macro->val[4]=0; + if (i.macro->val[4]>255) i.macro->val[4]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("SusDecay"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER + if (i.macro->val[7]<0) i.macro->val[7]=0; + if (i.macro->val[7]>255) i.macro->val[7]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + + ImGui::TableNextColumn(); + ImGui::Text("Release"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER + if (i.macro->val[8]<0) i.macro->val[8]=0; + if (i.macro->val[8]>255) i.macro->val[8]=255; + } + + ImGui::EndTable(); + } + } + if (i.macro->open&4) { + if (ImGui::BeginTable("MacroLFO",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); + //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Bottom"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER + if (i.macro->val[0]val[0]=i.min; + if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; + } + + ImGui::TableNextColumn(); + ImGui::Text("Top"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER + if (i.macro->val[1]val[1]=i.min; + if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; + } + + /*ImGui::TableNextColumn(); + ImGui::Text("the envelope goes here");*/ + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Speed"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER + if (i.macro->val[11]<0) i.macro->val[11]=0; + if (i.macro->val[11]>255) i.macro->val[11]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("Phase"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER + if (i.macro->val[13]<0) i.macro->val[13]=0; + if (i.macro->val[13]>1023) i.macro->val[13]=1023; + } + + ImGui::TableNextColumn(); + ImGui::Text("Shape"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER + if (i.macro->val[12]<0) i.macro->val[12]=0; + if (i.macro->val[12]>2) i.macro->val[12]=2; + } + + ImGui::EndTable(); + } + } + } +} + +#define BUTTON_TO_SET_MODE(buttonType) \ + if (buttonType(macroTypeLabels[(i.macro->open>>1)&3])) { \ + unsigned char prevOpen=i.macro->open; \ + i.macro->open+=2; \ + if (i.macro->open>=6) { \ + i.macro->open-=6; \ + } \ +\ + /* check whether macro type is now ADSR/LFO or sequence */ \ + if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { \ + /* swap memory */ \ + /* this way the macro isn't corrupted if the user decides to go */ \ + /* back to sequence mode */ \ + i.macro->len^=i.macro->lenMemory; \ + i.macro->lenMemory^=i.macro->len; \ + i.macro->len^=i.macro->lenMemory; \ +\ + for (int j=0; j<16; j++) { \ + i.macro->val[j]^=i.macro->typeMemory[j]; \ + i.macro->typeMemory[j]^=i.macro->val[j]; \ + i.macro->val[j]^=i.macro->typeMemory[j]; \ + } \ +\ + /* if ADSR/LFO, populate min/max */ \ + if (i.macro->open&6) { \ + i.macro->val[0]=i.min; \ + i.macro->val[1]=i.max; \ + } \ + } \ + PARAMETER; \ + } \ + if (ImGui::IsItemHovered()) { \ + switch (i.macro->open&6) { \ + case 0: \ + ImGui::SetTooltip("Macro type: Sequence"); \ + break; \ + case 2: \ + ImGui::SetTooltip("Macro type: ADSR"); \ + break; \ + case 4: \ + ImGui::SetTooltip("Macro type: LFO"); \ + break; \ + default: \ + ImGui::SetTooltip("Macro type: What's going on here?"); \ + break; \ + } \ + } \ + if (i.macro->open&6) { \ + i.macro->len=16; \ + } + +#define BUTTON_TO_SET_PROPS(_x) \ + ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); \ + if (ImGui::IsItemHovered()) { \ + ImGui::SetTooltip("Delay/Step Length"); \ + } \ + if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { \ + if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&_x.macro->speed,&_ONE,&_THREE)) { \ + if (_x.macro->speed<1) _x.macro->speed=1; \ + MARK_MODIFIED; \ + } \ + if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&_x.macro->delay,&_ONE,&_THREE)) { \ + MARK_MODIFIED; \ + } \ + ImGui::EndPopup(); \ + } + +void FurnaceGUI::drawMacros(std::vector& macros, FurnaceGUIMacroEditState& state) { + int index=0; + float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; + switch (settings.macroLayout) { + case 0: { + if (ImGui::BeginTable("MacroSpace",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + float lenAvail=ImGui::GetContentRegionAvail().x; + //ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); + ImGui::SetNextItemWidth(120.0f*dpiScale); + if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) { + if (macroPointSize<1) macroPointSize=1; + if (macroPointSize>256) macroPointSize=256; + } + ImGui::TableNextColumn(); + float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; + int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); + if (macroDragScroll>255-totalFit) { + macroDragScroll=255-totalFit; + } + ImGui::SetNextItemWidth(availableWidth); + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { + if (macroDragScroll<0) macroDragScroll=0; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + } + + // draw macros + for (FurnaceGUIMacroDesc& i: macros) { + ImGui::PushID(index); + ImGui::TableNextRow(); + + // description + ImGui::TableNextColumn(); + ImGui::Text("%s",i.displayName); + ImGui::SameLine(); + if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { + i.macro->open^=1; + } + if (i.macro->open&1) { + if ((i.macro->open&6)==0) { + ImGui::SetNextItemWidth(lenAvail); + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; + } + } + BUTTON_TO_SET_MODE(ImGui::Button); + ImGui::SameLine(); + BUTTON_TO_SET_PROPS(i); + // do not change this! + // anything other than a checkbox will look ugly! + // if you really need more than two macro modes please tell me. + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; + } + } + } + + // macro area + ImGui::TableNextColumn(); + drawMacroEdit(i,totalFit,availableWidth,index); + ImGui::PopID(); + index++; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(availableWidth); + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { + if (macroDragScroll<0) macroDragScroll=0; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + } + ImGui::EndTable(); + } + break; + } + case 1: { + ImGui::Text("Mobile"); + break; + } + case 2: { + int columns=round(ImGui::GetContentRegionAvail().x/(400.0*dpiScale)); + int curColumn=0; + if (ImGui::BeginTable("MacroGrid",columns,ImGuiTableFlags_BordersInner)) { + for (FurnaceGUIMacroDesc& i: macros) { + if (curColumn==0) ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + if (++curColumn>=columns) curColumn=0; + + float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; + int totalFit=i.macro->len; + if (totalFit<1) totalFit=1; + + ImGui::PushID(index); + + ImGui::TextUnformatted(i.displayName); + ImGui::SameLine(); + if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { + i.macro->open^=1; + } + + if (i.macro->open&1) { + ImGui::SameLine(); + BUTTON_TO_SET_MODE(ImGui::SmallButton); + } + + drawMacroEdit(i,totalFit,availableWidth,index); + + if (i.macro->open&1) { + if ((i.macro->open&6)==0) { + ImGui::Text("Length"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; + } + ImGui::SameLine(); + } + BUTTON_TO_SET_PROPS(i); + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + ImGui::SameLine(); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; + } + } + } + + ImGui::PopID(); + index++; + } + ImGui::EndTable(); + } + break; + } + case 3: { + if (ImGui::BeginTable("MacroList",2,ImGuiTableFlags_Borders)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + for (size_t i=0; i255-totalFit) { + macroDragScroll=255-totalFit; + } + + if (state.selectedMacro<0 || state.selectedMacro>=(int)macros.size()) { + state.selectedMacro=0; + } + + if (state.selectedMacro>=0 && state.selectedMacro<(int)macros.size()) { + FurnaceGUIMacroDesc& m=macros[state.selectedMacro]; + m.macro->open|=1; + + m.height=ImGui::GetContentRegionAvail().y-ImGui::GetFontSize()-ImGui::GetFrameHeightWithSpacing()-12.0f*dpiScale-ImGui::GetStyle().ItemSpacing.y*3.0f; + if (m.macro->name=="arp") m.height-=12.0f*dpiScale; + if (m.height<10.0f*dpiScale) m.height=10.0f*dpiScale; + m.height/=dpiScale; + 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,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + m.macro->len=macroLen; + } + ImGui::SameLine(); + } + BUTTON_TO_SET_PROPS(m); + 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; + } + } + } else { + ImGui::Text("The heck? No, this isn't even working correctly..."); + } + } else { + ImGui::Text("The only problem with that selectedMacro is that it's a bug..."); + } + + // goes here + ImGui::EndTable(); + } + break; + } + case 4: { + ImGui::Text("Single (combo box)"); + break; } - ImGui::EndTable(); } } @@ -3570,7 +3720,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("LFO2 Speed",&ins->std.ex7Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO2 Shape",&ins->std.ex8Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } - drawMacros(macroList); + drawMacros(macroList,macroEditStateFM); ImGui::EndTabItem(); } for (int i=0; istd.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } - drawMacros(macroList); + drawMacros(macroList,macroEditStateOP[ordi]); ImGui::PopID(); ImGui::EndTabItem(); } @@ -5190,7 +5340,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Noise",&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } - drawMacros(macroList); + drawMacros(macroList,macroEditStateMacros); ImGui::EndTabItem(); } ImGui::EndTabBar(); diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 7959149b8..0df3a2538 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -107,7 +107,7 @@ void FurnaceGUI::drawNewSong() { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) { - nextDesc=i.definition.data(); + nextDesc=i.definition; nextDescName=i.name; accepted=true; } @@ -129,7 +129,7 @@ void FurnaceGUI::drawNewSong() { ImGui::CloseCurrentPopup(); } else { unsigned int selection=rand()%newSystemCat->systems.size(); - nextDesc=newSystemCat->systems[selection].definition.data(); + nextDesc=newSystemCat->systems[selection].definition; nextDescName=newSystemCat->systems[selection].name; accepted=true; } @@ -143,16 +143,7 @@ void FurnaceGUI::drawNewSong() { } if (accepted) { - // TODO: remove after porting all presets to new format - String oldDescFormat; - for (const int* i=nextDesc; *i; i+=4) { - oldDescFormat+=fmt::sprintf("%d ",e->systemToFileFur((DivSystem)i[0])); - oldDescFormat+=fmt::sprintf("%d ",i[1]); - oldDescFormat+=fmt::sprintf("%d ",i[2]); - oldDescFormat+=fmt::sprintf("%d ",i[3]); - } - String oldDesc=e->decodeSysDesc(oldDescFormat.c_str()); - e->createNew(oldDesc.c_str(),nextDescName); + e->createNew(nextDesc.c_str(),nextDescName,false); undoHist.clear(); redoHist.clear(); curFileName=""; diff --git a/src/gui/piano.cpp b/src/gui/piano.cpp index 1e606d774..a100e3ba1 100644 --- a/src/gui/piano.cpp +++ b/src/gui/piano.cpp @@ -219,11 +219,14 @@ void FurnaceGUI::drawPiano() { // render piano //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { - ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay")); + bool canInput=false; + if (ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) { + canInput=true; + } if (view) { int notes=oct*12; // evaluate input - for (TouchPoint& i: activePoints) { + if (canInput) for (TouchPoint& i: activePoints) { if (rect.Contains(ImVec2(i.x,i.y))) { int note=(((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*notes)+12*off; if (note<0) continue; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 863ff5392..c2900ac52 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -18,2320 +18,2072 @@ */ #include "gui.h" +#include "../baseutils.h" +#include // add system configurations here. // every entry is written in the following format: -// cat.systems.push_back(FurnaceGUISysDef( +// ENTRY( // "System Name", { -// DIV_SYSTEM_???, Volume, Panning, Flags, -// DIV_SYSTEM_???, Volume, Panning, Flags, +// CH(DIV_SYSTEM_???, Volume, Panning, Flags), +// CH(DIV_SYSTEM_???, Volume, Panning, Flags), // ... -// 0 -// } -// )); +// } +// ); +// flags are a string of new line-separated values. + +#define CH FurnaceGUISysDefChip +#define CATEGORY_BEGIN(x,y) cat=FurnaceGUISysCategory(x,y); +#define CATEGORY_END sysCategories.push_back(cat); +#define ENTRY(...) cat.systems.push_back(FurnaceGUISysDef(__VA_ARGS__)); void FurnaceGUI::initSystemPresets() { sysCategories.clear(); FurnaceGUISysCategory cat; - cat=FurnaceGUISysCategory("Game consoles","let's play some chiptune making games!"); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Game consoles","let's play some chiptune making games!"); + ENTRY( "Sega Genesis", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Sega Genesis (Fractal Sound template)", { - DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + ); + ENTRY( + "Sega Genesis (DualPCM)", { + CH(DIV_SYSTEM_YM2612_FRAC, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Sega Genesis (Fractal Sound template, extended channel 3)", { - DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + ); + ENTRY( + "Sega Genesis (DualPCM, extended channel 3)", { + CH(DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (with Sega CD)", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - DIV_SYSTEM_RF5C68, 64, 0, 18, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), + CH(DIV_SYSTEM_RF5C68, 64, 0, + "clockSel=2\n" + "chipType=1\n" + ) } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3 with Sega CD)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - DIV_SYSTEM_RF5C68, 64, 0, 18, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), + CH(DIV_SYSTEM_RF5C68, 64, 0, + "clockSel=2\n" + "chipType=1\n" + ) } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion in drums mode)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Game Gear", { - DIV_SYSTEM_SMS, 64, 0, 0xc, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, "chipType=3") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC Engine/TurboGrafx-16", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC6", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC6, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC6, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC7", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC7, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC7, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with MMC5", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_MMC5, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_MMC5, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Sunsoft 5B", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 32, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=2") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Namco 163", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_N163, 64, 0, 112, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_N163, 64, 0, "channels=7") } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Comboy with Family Noraebang", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( - "Comboy with Family Noraebang (drums mode)", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 - } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_FDS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNES", { - DIV_SYSTEM_SNES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SNES, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Mattel Intellivision", { - DIV_SYSTEM_AY8910, 64, 0, 48, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=3") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Vectrex", { - DIV_SYSTEM_AY8910, 64, 0, 4, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "clockSel=4") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo AES", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 1, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo AES (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 1, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari 2600/7800", { - DIV_SYSTEM_TIA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_TIA, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Lynx", { - DIV_SYSTEM_LYNX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_LYNX, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "WonderSwan", { - DIV_SYSTEM_SWAN, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SWAN, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Virtual Boy", { - DIV_SYSTEM_VBOY, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VBOY, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Gamate", { - DIV_SYSTEM_AY8910, 64, 0, 73, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, + "clockSel=9\n" + "chipType=0\n" + "stereo=true\n" + ) } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Computers","let's get to work on chiptune today."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Computers","let's get to work on chiptune today."); + ENTRY( "Commodore PET", { - DIV_SYSTEM_PET, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PET, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore VIC-20", { - DIV_SYSTEM_VIC20, 64, 0, 1, - 0 + CH(DIV_SYSTEM_VIC20, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + Sound Expander)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + Sound Expander in drums mode)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + Sound Expander)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + Sound Expander in drums mode)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + FM-YAM)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + FM-YAM in drums mode)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + FM-YAM)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + FM-YAM in drums mode)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Amiga", { - DIV_SYSTEM_AMIGA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AMIGA, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX", { - DIV_SYSTEM_AY8910, 64, 0, 16, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SFG-01", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2151, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2151, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-AUDIO", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_Y8950, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_Y8950, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-AUDIO (drums mode)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_Y8950_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-MUSIC", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_OPLL, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-MUSIC (drums mode)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Darky", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_AY8930, 64, 0, 139, // 3.58MHz - DIV_SYSTEM_AY8930, 64, 0, 139, // 3.58MHz or 3.6MHz selectable via register + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_AY8930, 64, 0, + "clockSel=11\n" + "halfClock=true\n" + ), // 3.58MHz + CH(DIV_SYSTEM_AY8930, 64, 0, + "clockSel=11\n" + "halfClock=true\n" + ) // 3.58MHz or 3.6MHz selectable via register // per-channel mixer (soft panning, post processing) isn't emulated at all - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Playsoniq", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SMS, 64, 0, 0, // Sega VDP - DIV_SYSTEM_C64_8580, 64, 0, 0, - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SMS, 64, 0, ""), // Sega VDP + CH(DIV_SYSTEM_C64_8580, 64, 0, ""), + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SCC", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SCC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SCC, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SCC+", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (extended channel 2)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (with YM2610B)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610B, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (with YM2610B; extended channel 3)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SIMPL", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, Mono DAC - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_PCM_DAC, 64, 0, + "rate=55930\n" + "outDepth=8\n" + ) // variable rate, Mono DAC } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-26/K)", { - DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz - 0 + CH(DIV_SYSTEM_OPN, 64, 0, "clockSel=4"), // 3.9936MHz but some compatible card has 4MHz + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-26/K; extended channel 3)", { - DIV_SYSTEM_OPN_EXT, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz - 0 + CH(DIV_SYSTEM_OPN_EXT, 64, 0, "clockSel=4"), // 3.9936MHz but some compatible card has 4MHz + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + /* TODO: everything here + ENTRY( "NEC PC-98 (with Sound Orchestra)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-86)", { // -73 also has OPNA DIV_SYSTEM_PC98, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-86; extended channel 3)", { // -73 also has OPNA DIV_SYSTEM_PC98_EXT, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-73)", { DIV_SYSTEM_PC98, 64, 0, 1, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_OPL3, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_OPL3, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (48K)", { - DIV_SYSTEM_AY8910, 64, 0, 2, - DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SFX_BEEPER, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K)", { - DIV_SYSTEM_AY8910, 64, 0, 1, - 0 + DIV_SYSTEM_AY8910, 64, 0, 1, //beeper was also included } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on first OPN)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on second OPN)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on both OPNs)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Amstrad CPC", { DIV_SYSTEM_AY8910, 64, 0, 5, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari ST", { DIV_SYSTEM_AY8910, 64, 0, 19, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari STE", { DIV_SYSTEM_AY8910, 64, 0, 19, DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SAM Coupé", { - DIV_SYSTEM_SAA1099, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SAA1099, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "BBC Micro", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC (barebones)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "IBM PCjr", { // it can be enable sound output at once DIV_SYSTEM_SMS, 64, 0, 0x44, // SN76496 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tandy 1000", { DIV_SYSTEM_SMS, 64, 0, 0x44, // NCR 8496 or SN76496 or Tandy PSSJ(with 8 bit DAC) - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Covox Sound Master", { DIV_SYSTEM_AY8930, 64, 0, 3, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + SSI 2001", { DIV_SYSTEM_C64_6581, 64, 0, 2, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Game Blaster", { DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib (drums mode)", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib/Sound Blaster (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster w/Game Blaster Compatible", { - DIV_SYSTEM_OPL2, 64, 0, 0, + CH(DIV_SYSTEM_OPL2, 64, 0, ""), DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster w/Game Blaster Compatible (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro", { DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro 2", { - DIV_SYSTEM_OPL3, 64, 0, 0, + CH(DIV_SYSTEM_OPL3, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro 2 (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + PC-FXGA", { DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + SAAYM", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz or 4MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // 7.16MHz or 8MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // "" - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X1", { DIV_SYSTEM_AY8910, 64, 0, 3, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X1 + FM Addon", { DIV_SYSTEM_AY8910, 64, 0, 3, DIV_SYSTEM_YM2151, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X68000", { DIV_SYSTEM_YM2151, 64, 0, 2, - DIV_SYSTEM_MSM6258, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6258, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "FM Towns", { DIV_SYSTEM_YM2612, 64, 0, 2, // YM3438 - DIV_SYSTEM_RF5C68, 64, 0, 0, - 0 + CH(DIV_SYSTEM_RF5C68, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commander X16", { - DIV_SYSTEM_VERA, 64, 0, 0, - DIV_SYSTEM_YM2151, 32, 0, 0, - 0 + CH(DIV_SYSTEM_VERA, 64, 0, ""), + CH(DIV_SYSTEM_YM2151, 32, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI-99/4A", { DIV_SYSTEM_SMS, 64, 0, 0x182, // SN94624 447KHz - 0 } - )); - sysCategories.push_back(cat); + ); + */ + CATEGORY_END; - cat=FurnaceGUISysCategory("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels)."); - cat.systems.push_back(FurnaceGUISysDef( + /* TODO: everything here + CATEGORY_BEGIN("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels)."); + ENTRY( "Yamaha YM2151 (OPM)", { - DIV_SYSTEM_YM2151, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2203 (OPN)", { DIV_SYSTEM_OPN, 64, 0, 3, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2203 (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2608 (OPNA)", { - DIV_SYSTEM_PC98, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PC98, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2608 (extended channel 3)", { - DIV_SYSTEM_PC98_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PC98_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610 (OPNB)", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610 (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610B (OPNB2)", { - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610B (extended channel 3)", { - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (OPN2)", { DIV_SYSTEM_YM2612, 64, 0, (int)0x80000000, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, (int)0x80000000, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (OPN2) with DualPCM", { DIV_SYSTEM_YM2612_FRAC, 64, 0, (int)0x80000000, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (extended channel 3) with DualPCM", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, (int)0x80000000, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2413 (OPLL)", { - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2413 (drums mode)", { - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2414 (OPZ)", { - DIV_SYSTEM_OPZ, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPZ, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (OPN2C)", { - DIV_SYSTEM_YM2612, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (OPN2C) with DualPCM", { - DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (extended channel 3) with DualPCM", { - DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3526 (OPL)", { - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3526 (drums mode)", { - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha Y8950", { - DIV_SYSTEM_Y8950, 64, 0, 0, - 0 + CH(DIV_SYSTEM_Y8950, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha Y8950 (drums mode)", { - DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_Y8950_DRUMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3812 (OPL2)", { - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3812 (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMF262 (OPL3)", { - DIV_SYSTEM_OPL3, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMF262 (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), } - )); + ); if (settings.hiddenSystems) { - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "Yamaha YMU759 (MA-2)", { - DIV_SYSTEM_YMU759, 64, 0, 0, + CH(DIV_SYSTEM_YMU759, 64, 0, ""), 0 } - )); + ); } - sysCategories.push_back(cat); + CATEGORY_END; - cat=FurnaceGUISysCategory("Square","these chips generate square/pulse tones only (but may include noise)."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Square","these chips generate square/pulse tones only (but may include noise)."); + ENTRY( "TI SN76489", { DIV_SYSTEM_SMS, 64, 0, 4, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76489A", { DIV_SYSTEM_SMS, 64, 0, 0x40, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76496", { DIV_SYSTEM_SMS, 64, 0, 0x44, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NCR 8496", { DIV_SYSTEM_SMS, 64, 0, 0x48, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tandy PSSJ 3-voice sound", { DIV_SYSTEM_SMS, 64, 0, 0x4c, // 8 bit DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega PSG (SN76489-like)", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega PSG (SN76489-like, Stereo)", { DIV_SYSTEM_SMS, 64, 0, 0xc, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN94624", { DIV_SYSTEM_SMS, 64, 0, 0x182, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76494", { DIV_SYSTEM_SMS, 64, 0, 0x186, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toshiba T6W28", { - DIV_SYSTEM_T6W28, 64, 0, 0, - 0 + CH(DIV_SYSTEM_T6W28, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "AY-3-8910", { - DIV_SYSTEM_AY8910, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "AY-3-8914", { DIV_SYSTEM_AY8910, 64, 0, 48, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2149(F)", { DIV_SYSTEM_AY8910, 64, 0, 16, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Philips SAA1099", { - DIV_SYSTEM_SAA1099, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SAA1099, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC Speaker", { - DIV_SYSTEM_PCSPKR, 32, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 32, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore VIC", { DIV_SYSTEM_VIC20, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM5232", { - DIV_SYSTEM_MSM5232, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM5232, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Pong", { - DIV_SYSTEM_PONG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PONG, 64, 0, ""), } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis."); + ENTRY( "Amiga", { - DIV_SYSTEM_AMIGA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AMIGA, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SegaPCM", { - DIV_SYSTEM_SEGAPCM, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SEGAPCM, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom QSound", { - DIV_SYSTEM_QSOUND, 64, 0, 0, - 0 + CH(DIV_SYSTEM_QSOUND, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta/Allumer X1-010", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMZ280B (PCMD8)", { - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Ricoh RF5C68", { - DIV_SYSTEM_RF5C68, 64, 0, 0, - 0 + CH(DIV_SYSTEM_RF5C68, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM6258", { - DIV_SYSTEM_MSM6258, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6258, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM6295", { - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNES", { - DIV_SYSTEM_SNES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SNES, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Generic PCM DAC", { - DIV_SYSTEM_PCM_DAC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCM_DAC, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Ensoniq ES5506 (OTTO)", { - DIV_SYSTEM_ES5506, 64, 0, 31, - 0 + CH(DIV_SYSTEM_ES5506, 64, 0, "channels=31") } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Wavetable","chips which use user-specified waveforms to generate sound."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound."); + ENTRY( "PC Engine", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore PET (pseudo-wavetable)", { - DIV_SYSTEM_PET, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PET, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Bubble System WSG", { - DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_BUBSYS_WSG, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami SCC", { - DIV_SYSTEM_SCC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SCC, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami SCC+", { - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco WSG", { - DIV_SYSTEM_NAMCO, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco C15 (8-channel mono)", { - DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_15XX, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco C30 (8-channel stereo)", { - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco 163", { - DIV_SYSTEM_N163, 64, 0, 0, - 0 + CH(DIV_SYSTEM_N163, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System (chip)", { - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_FDS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "WonderSwan", { - DIV_SYSTEM_SWAN, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SWAN, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Virtual Boy", { - DIV_SYSTEM_VBOY, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VBOY, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta/Allumer X1-010", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Specialized","chips/systems with unique sound synthesis methods."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Specialized","chips/systems with unique sound synthesis methods."); + ENTRY( "MOS Technology SID (6581)", { DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MOS Technology SID (8580)", { DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Microchip AY8930", { - DIV_SYSTEM_AY8930, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8930, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Lynx", { - DIV_SYSTEM_LYNX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_LYNX, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari TIA", { - DIV_SYSTEM_TIA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_TIA, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES (Ricoh 2A03)", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commander X16 (VERA only)", { - DIV_SYSTEM_VERA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VERA, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (beeper only)", { - DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SFX_BEEPER, 64, 0, ""), } - )); + ); if (settings.hiddenSystems) { - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "Dummy System", { - DIV_SYSTEM_DUMMY, 64, 0, 0, + CH(DIV_SYSTEM_DUMMY, 64, 0, ""), 0 } - )); + ); } - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "tildearrow Sound Unit", { - DIV_SYSTEM_SOUND_UNIT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SOUND_UNIT, 64, 0, ""), } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Arcade systems","INSERT COIN"); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Arcade systems","INSERT COIN"); + ENTRY( "Pong", { - DIV_SYSTEM_PONG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PONG, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Bally Midway MCR", { // SSIO sound board DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz // additional sound boards, mostly software controlled DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Williams/Midway Y/T unit w/ADPCM sound board", { // ADPCM sound board - DIV_SYSTEM_YM2151, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 15624|(7<<16), // variable via OPM timer? - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Gyruss", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), // additional discrete sound logics - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Bubble System", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_BUBSYS_WSG, 64, 0, ""), // VLM5030 exists but not used for music at all - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on first OPL2)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on second OPL2)", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on both OPL2s)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Hexion", { DIV_SYSTEM_SCC, 64, 0, 2, // 1.5MHz (3MHz input) DIV_SYSTEM_MSM6295, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Kyugo", { DIV_SYSTEM_AY8910, 64, 0, 14, DIV_SYSTEM_AY8910, 64, 0, 14, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 1", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz DIV_SYSTEM_SMS, 64, 0, 0x0141, // SN76489A 2MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E (with FM expansion in drums mode)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Hang-On", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Hang-On (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega OutRun/X Board", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // ASIC, 31.25KHz output rate - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 24", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 61499|(7<<16), // software controlled, variable rate via configurable timers - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on first OPN2C)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on second OPN2C)", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on both OPN2Cs)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32", { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on first OPN2C)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on second OPN2C)", { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on both OPN2Cs)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Exed Eyes", { DIV_SYSTEM_AY8910, 64, 0, 4, // 1.5MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade", { // 1943, Side arms, etc DIV_SYSTEM_OPN, 64, 0, 5, // 4 or 1.5MHz; various per games DIV_SYSTEM_OPN, 64, 0, 5, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on first OPN)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN, 64, 0, 5, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on second OPN)", { DIV_SYSTEM_OPN, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on both OPNs)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom CPS-1", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom CPS-2 (QSound)", { - DIV_SYSTEM_QSOUND, 64, 0, 0, - 0 + CH(DIV_SYSTEM_QSOUND, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Ginga NinkyouDen", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950, 64, 0, 0, // 3.58MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Ginga NinkyouDen (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, // 3.58MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Mega System 1", { DIV_SYSTEM_YM2151, 64, 0, 1, // 3.5MHz (7MHz / 2) DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NMK 16-bit Arcade", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NMK 16-bit Arcade (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko DJ Boy", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko DJ Boy (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Air Buster", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Air Buster (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Toybox System", { DIV_SYSTEM_AY8910, 64, 0, 19, // YM2149 2MHz DIV_SYSTEM_AY8910, 64, 0, 19, // ^^ DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Jackie Chan", { DIV_SYSTEM_YMZ280B, 64, 0, 3, // 16MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Super Kaneko Nova System", { DIV_SYSTEM_YMZ280B, 64, 0, 4, // 16.67MHz (33.33MHz / 2) - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on first OPN)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on second OPN)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on both OPNs)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo System", { - DIV_SYSTEM_OPL3, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo System (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seibu Kaihatsu Raiden", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seibu Kaihatsu Raiden (drums mode)", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Shanghai 3", { DIV_SYSTEM_AY8910, 64, 0, 20, // YM2149 1.5MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Arcade", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Arcade (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Klax", { DIV_SYSTEM_MSM6295, 64, 0, 7, // 0.895MHz (3.579545MHz / 4) - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Rampart", { DIV_SYSTEM_OPLL, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Rampart (drums mode)", { DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari JSA IIIs", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, -127, 14, // 1.193MHz (3.579545MHz / 3), Left output DIV_SYSTEM_MSM6295, 64, 127, 14, // 1.193MHz (3.579545MHz / 3), Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (extended channel 3)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (drums mode)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (extended channel 3; drums mode)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East PCX", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz - DIV_SYSTEM_PCE, 64, 0, 0, + CH(DIV_SYSTEM_PCE, 64, 0, ""), // software controlled MSM5205 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East PCX (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz - DIV_SYSTEM_PCE, 64, 0, 0, + CH(DIV_SYSTEM_PCE, 64, 0, ""), // software controlled MSM5205 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Dark Seal", { // Dark Seal, Crude Buster, Vapor Trail, etc DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) DIV_SYSTEM_OPN, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional // HuC6280 is for control them, internal sound isn't used - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Dark Seal (extended channel 3)", { // Dark Seal, Crude Buster, Vapor Trail, etc DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional // HuC6280 is for control them, internal sound isn't used - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Deco 156", { DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.007MHz (32.22MHz / 32); various per games DIV_SYSTEM_MSM6295, 64, 0, 8, // 1 or 2 or 2.014MHz (32.22MHz / 16); various per games - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East MLC", { DIV_SYSTEM_YMZ280B, 64, 0, 5, // 14MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on first OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on second OPL)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on both OPLs)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on OPL)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on Y8950 and OPL)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on OPL2)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on Y8950 and OPL2)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on Y8950)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on OPL and Y8950)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo MVS", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo MVS (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Nichibutsu Mag Max", { DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco (3-channel WSG)", { // Pac-Man, Galaga, Xevious, etc - DIV_SYSTEM_NAMCO, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Mappy", { // Mappy, Super Pac-Man, Libble Rabble, etc - DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_15XX, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Pac-Land", { // Pac-Land, Baraduke, Sky kid, etc - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco System 86", { // without expansion board case; Hopping Mappy, etc - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Thunder Ceptor", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 7999|(7<<16), // M65C02 software driven, correct sample rate? - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco System 1", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // sample rate verified from https://github.com/mamedev/mame/blob/master/src/devices/sound/n63701x.cpp DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // "" - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Taito Arcade", { - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Taito Arcade (extended channel 3)", { - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1 + FM addon", { - DIV_SYSTEM_X1_010, 64, 0, 0, + CH(DIV_SYSTEM_X1_010, 64, 0, ""), DIV_SYSTEM_YM2612, 64, 0, 2, // Discrete YM3438 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1 + FM addon (extended channel 3)", { - DIV_SYSTEM_X1_010, 64, 0, 0, + CH(DIV_SYSTEM_X1_010, 64, 0, ""), DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // Discrete YM3438 - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 2", { DIV_SYSTEM_X1_010, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sammy/Seta/Visco SSV", { - DIV_SYSTEM_ES5506, 64, 0, 31, - 0 + CH(DIV_SYSTEM_ES5506, 64, 0, "channels=31") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Cave 68000", { - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Coreland Cyber Tank", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Coreland Cyber Tank (drums mode)", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ICE Skimaxx", { DIV_SYSTEM_MSM6295, 64, -127, 130, // 4MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 130, // 4MHz, Right output DIV_SYSTEM_MSM6295, 64, -127, 8, // 2MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 8, // 2MHz, Right output - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toaplan 1", { DIV_SYSTEM_OPL2, 64, 0, 5, // 3.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toaplan 1 (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 5, // 3.5MHz - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon 3rd generation hardware", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game - DIV_SYSTEM_OPLL, 64, 0, 0, + CH(DIV_SYSTEM_OPLL, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon 3rd generation hardware (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon Real Break", { - DIV_SYSTEM_OPLL, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon Real Break (drums mode)", { - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Irem M72", { - DIV_SYSTEM_YM2151, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 7811|(7<<16), - 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); + ENTRY( "Sega Genesis", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC Engine/TurboGrafx-16", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC7", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC7, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC7, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_FDS, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID)", { DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID)", { DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Arcade (YM2151 and SegaPCM)", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo CD", { - DIV_SYSTEM_YM2610, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610, 64, 0, ""), } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo CD (extended channel 2)", { - DIV_SYSTEM_YM2610_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_EXT, 64, 0, ""), } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; + */ +} + +FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def): + name(n) { + std::vector uncompiled=def; + int index=0; + + for (size_t i=0; i def): + name(n) { + std::vector uncompiled=def; + int index=0; + for (FurnaceGUISysDefChip& i: uncompiled) { + definition+=fmt::sprintf( + "id%d=%d\nvol%d=%d\npan%d=%d\nflags%d=%s\n", + index, + DivEngine::systemToFileFur(i.sys), + index, + i.vol, + index, + i.pan, + index, + taEncodeBase64(i.flags) + ); + index++; + } } diff --git a/src/gui/scaling.cpp b/src/gui/scaling.cpp index aee55c8c0..7c42a1e33 100644 --- a/src/gui/scaling.cpp +++ b/src/gui/scaling.cpp @@ -197,10 +197,12 @@ double getScaleFactor(const char* driverHint) { // SDL fallback #ifdef ANDROID - float dpiScaleF=192.0f; + float dpiScaleF=160.0f; if (SDL_GetDisplayDPI(0,&dpiScaleF,NULL,NULL)==0) { - ret=round(dpiScaleF/192.0f); + ret=dpiScaleF/160.0f; if (ret<1) ret=1; + logI("dpiScaleF: %f",dpiScaleF); + logI("ret: %f",ret); } #else diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 6cf332fc1..7f95ffa04 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -33,14 +33,14 @@ #define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;" -#if defined(_WIN32) || defined(__APPLE__) +#if defined(_WIN32) || defined(__APPLE__) || defined(IS_MOBILE) #define POWER_SAVE_DEFAULT 1 #else // currently off on Linux/other due to Mesa catch-up behavior. #define POWER_SAVE_DEFAULT 0 #endif -#if defined(__HAIKU__) +#if defined(__HAIKU__) || defined(IS_MOBILE) // NFD doesn't support Haiku #define SYS_FILE_DIALOG_DEFAULT 0 #else @@ -239,6 +239,12 @@ void FurnaceGUI::drawSettings() { nextWindow=GUI_WINDOW_NOTHING; } if (!settingsOpen) return; + if (mobileUI) { + ImVec2 setWindowPos=ImVec2(0,0); + ImVec2 setWindowSize=ImVec2(canvasW,canvasH); + ImGui::SetNextWindowPos(setWindowPos); + ImGui::SetNextWindowSize(setWindowSize); + } if (ImGui::Begin("Settings",&settingsOpen,ImGuiWindowFlags_NoDocking|globalWinFlags)) { if (!settingsOpen) { settingsOpen=true; @@ -332,7 +338,7 @@ void FurnaceGUI::drawSettings() { settings.initialSys.set("pan0",0); settings.initialSys.set("flags0",""); settings.initialSys.set("id1",e->systemToFileFur(DIV_SYSTEM_SMS)); - settings.initialSys.set("vol1",64); + settings.initialSys.set("vol1",32); settings.initialSys.set("pan1",0); settings.initialSys.set("flags1",""); settings.initialSysName="Sega Genesis/Mega Drive"; @@ -343,11 +349,15 @@ void FurnaceGUI::drawSettings() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputText("##InitSysName",&settings.initialSysName); + int sysCount=0; + int doRemove=-1; for (size_t i=0; settings.initialSys.getInt(fmt::sprintf("id%d",i),0); i++) { DivSystem sysID=e->systemFromFileFur(settings.initialSys.getInt(fmt::sprintf("id%d",i),0)); signed char sysVol=settings.initialSys.getInt(fmt::sprintf("vol%d",i),0); signed char sysPan=settings.initialSys.getInt(fmt::sprintf("pan%d",i),0); + sysCount=i+1; + //bool doRemove=false; bool doInvert=sysVol&128; signed char vol=sysVol&127; @@ -373,7 +383,7 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); //ImGui::BeginDisabled(settings.initialSys.size()<=4); if (ImGui::Button(ICON_FA_MINUS "##InitSysRemove")) { - //doRemove=true; + doRemove=i; } //ImGui::EndDisabled(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale)); @@ -398,17 +408,31 @@ void FurnaceGUI::drawSettings() { } ImGui::PopID(); - /*if (doRemove && settings.initialSys.size()>=8) { - settings.initialSys.erase(settings.initialSys.begin()+i,settings.initialSys.begin()+i+4); - i-=4; - }*/ } - if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) { - /*settings.initialSys.push_back(DIV_SYSTEM_YM2612); - settings.initialSys.push_back(64); - settings.initialSys.push_back(0); - settings.initialSys.push_back(0);*/ + if (doRemove>=0 && sysCount>1) { + for (int i=doRemove; isystemToFileFur(DIV_SYSTEM_YM2612)); + settings.initialSys.set(fmt::sprintf("vol%d",sysCount),64); + settings.initialSys.set(fmt::sprintf("pan%d",sysCount),0); + settings.initialSys.set(fmt::sprintf("flags%d",sysCount),""); } ImGui::Separator(); @@ -522,6 +546,7 @@ void FurnaceGUI::drawSettings() { ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!"); } +#ifndef IS_MOBILE bool noThreadedInputB=settings.noThreadedInput; if (ImGui::Checkbox("Disable threaded input (restart after changing!)",&noThreadedInputB)) { settings.noThreadedInput=noThreadedInputB; @@ -537,6 +562,7 @@ void FurnaceGUI::drawSettings() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("remembers the window's last position on startup."); } +#endif bool blankInsB=settings.blankIns; if (ImGui::Checkbox("New instruments are blank",&blankInsB)) { @@ -1318,6 +1344,23 @@ void FurnaceGUI::drawSettings() { settings.susPosition=1; } + ImGui::Text("Macro editor layout:"); + if (ImGui::RadioButton("Unified##mel0",settings.macroLayout==0)) { + settings.macroLayout=0; + } + if (ImGui::RadioButton("Mobile##mel1",settings.macroLayout==1)) { + settings.macroLayout=1; + } + if (ImGui::RadioButton("Grid##mel2",settings.macroLayout==2)) { + settings.macroLayout=2; + } + if (ImGui::RadioButton("Single (with list)##mel3",settings.macroLayout==3)) { + settings.macroLayout=3; + } + if (ImGui::RadioButton("Single (combo box)##mel4",settings.macroLayout==4)) { + settings.macroLayout=4; + } + ImGui::Separator(); ImGui::Text("Namco 163 chip name"); @@ -2397,6 +2440,7 @@ void FurnaceGUI::syncSettings() { settings.persistFadeOut=e->getConfInt("persistFadeOut",1); settings.exportLoops=e->getConfInt("exportLoops",0); settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0); + settings.macroLayout=e->getConfInt("macroLayout",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2503,6 +2547,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.centerPattern,0,1); clampSetting(settings.ordersCursor,0,1); clampSetting(settings.persistFadeOut,0,1); + clampSetting(settings.macroLayout,0,4); if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; @@ -2675,6 +2720,7 @@ void FurnaceGUI::commitSettings() { e->setConf("persistFadeOut",settings.persistFadeOut); e->setConf("exportLoops",settings.exportLoops); e->setConf("exportFadeOut",settings.exportFadeOut); + e->setConf("macroLayout",settings.macroLayout); // colors for (int i=0; ilockSave([&]() { flags.set("clockSel",clockSel); flags.set("ladderEffect",ladder); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -439,6 +446,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_YM2610B: case DIV_SYSTEM_YM2610B_EXT: { int clockSel=flags.getInt("clockSel",0); + bool noExtMacros=flags.getBool("noExtMacros",false); if (ImGui::RadioButton("8MHz (Neo Geo MVS)",clockSel==0)) { clockSel=0; @@ -449,9 +457,16 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_YM2610_EXT || type==DIV_SYSTEM_YM2610_FULL_EXT || type==DIV_SYSTEM_YM2610B_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -668,8 +683,23 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo break; } case DIV_SYSTEM_PCSPKR: { + int clockSel=flags.getInt("clockSel",0); int speakerType=flags.getInt("speakerType",0); + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("1.19MHz (PC)",clockSel==0)) { + clockSel=0; + altered=true; + } + if (ImGui::RadioButton("1.99MHz (PC-98)",clockSel==1)) { + clockSel=1; + altered=true; + } + if (ImGui::RadioButton("2.46MHz (PC-98)",clockSel==2)) { + clockSel=2; + altered=true; + } + ImGui::Text("Speaker type:"); if (ImGui::RadioButton("Unfiltered",speakerType==0)) { speakerType=0; @@ -690,6 +720,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo if (altered) { e->lockSave([&]() { + flags.set("clockSel",clockSel); flags.set("speakerType",speakerType); }); } @@ -805,6 +836,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_OPN_EXT: { int clockSel=flags.getInt("clockSel",0); int prescale=flags.getInt("prescale",0); + bool noExtMacros=flags.getBool("noExtMacros",false); ImGui::Text("Clock rate:"); if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) { @@ -845,10 +877,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_OPN_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); flags.set("prescale",prescale); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -857,6 +896,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_PC98_EXT: { int clockSel=flags.getInt("clockSel",0); int prescale=flags.getInt("prescale",0); + bool noExtMacros=flags.getBool("noExtMacros",false); ImGui::Text("Clock rate:"); if (ImGui::RadioButton("8MHz (Arcade)",clockSel==0)) { @@ -881,10 +921,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_PC98_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); flags.set("prescale",prescale); + flags.set("noExtMacros",noExtMacros); }); } break;