From 9b35ca77c586426ae7312b9e903b0113221fdce4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 17 Nov 2025 19:38:45 -0500 Subject: [PATCH] giga-refactor, part 14 - READ a new way to define chip channels has been introduced, replacing the old one. it looks cleaner and is more flexible (even supporting dynamic channel count). it works by defining a function in the chip definition, which returns a DivChanDef with channel information (name, short name, type and instrument type(s)). alternatively, a list can be provided in the DivChanDefFunc() constructor, in the event channels differ greatly and/or the number of channels is small. some helper templates, such as stockChanDef and simpleChanDef also exist, which automatically map channel names and types regardless of count. --- src/engine/engine.h | 126 +--- src/engine/song.cpp | 15 +- src/engine/song.h | 122 +--- src/engine/sysDef.cpp | 1408 ++++++++++++++++++++++++--------------- src/engine/sysDef.h | 272 ++++++++ src/gui/sysMiscInfo.cpp | 43 +- 6 files changed, 1171 insertions(+), 815 deletions(-) create mode 100644 src/engine/sysDef.h diff --git a/src/engine/engine.h b/src/engine/engine.h index 5a173c829..869d0a12c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -27,6 +27,7 @@ #include "export.h" #include "dataErrors.h" #include "safeWriter.h" +#include "sysDef.h" #include "cmdStream.h" #include "filePlayer.h" #include "../audio/taAudio.h" @@ -332,131 +333,6 @@ struct DivEffectContainer { } }; -typedef int EffectValConversion(unsigned char,unsigned char); - -struct EffectHandler { - DivDispatchCmds dispatchCmd; - const char* description; - EffectValConversion* val; - EffectValConversion* val2; - EffectHandler( - DivDispatchCmds dispatchCmd_, - const char* description_, - EffectValConversion val_=NULL, - EffectValConversion val2_=NULL - ): - dispatchCmd(dispatchCmd_), - description(description_), - val(val_), - val2(val2_) {} -}; - -struct DivDoNotHandleEffect { -}; - -typedef std::unordered_map EffectHandlerMap; - -struct DivSysDef { - const char* name; - const char* nameJ; - const char* description; - unsigned char id; - unsigned char id_DMF; - int channels, minChans, maxChans; - bool isFM, isSTD, isCompound; - // width 0: variable - // height 0: no wavetable support - unsigned short waveWidth, waveHeight; - unsigned int vgmVersion; - unsigned int sampleFormatMask; - const char* chanNames[DIV_MAX_CHANS]; - const char* chanShortNames[DIV_MAX_CHANS]; - int chanTypes[DIV_MAX_CHANS]; - // 0: primary - // 1: alternate (usually PCM) - DivInstrumentType chanInsType[DIV_MAX_CHANS][2]; - const EffectHandlerMap effectHandlers; - const EffectHandlerMap postEffectHandlers; - const EffectHandlerMap preEffectHandlers; - DivSysDef( - const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans, int minCh, int maxCh, - bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, unsigned int formatMask, unsigned short waveWid, unsigned short waveHei, - const char* desc, - std::initializer_list chNames, - std::initializer_list chShortNames, - std::initializer_list chTypes, - std::initializer_list chInsType1, - std::initializer_list chInsType2={}, - const EffectHandlerMap fxHandlers_={}, - const EffectHandlerMap postFxHandlers_={}, - const EffectHandlerMap preFxHandlers_={}): - name(sysName), - nameJ(sysNameJ), - description(desc), - id(fileID), - id_DMF(fileID_DMF), - channels(chans), - minChans(minCh), - maxChans(maxCh), - isFM(isFMChip), - isSTD(isSTDChip), - isCompound(compound), - waveWidth(waveWid), - waveHeight(waveHei), - vgmVersion(vgmVer), - sampleFormatMask(formatMask), - effectHandlers(fxHandlers_), - postEffectHandlers(postFxHandlers_), - preEffectHandlers(preFxHandlers_) { - memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*)); - memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*)); - memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int)); - for (int i=0; i=DIV_MAX_CHANS) break; - } - - index=0; - for (const char* i: chShortNames) { - chanShortNames[index++]=i; - if (index>=DIV_MAX_CHANS) break; - } - - index=0; - for (int i: chTypes) { - chanTypes[index++]=i; - if (index>=DIV_MAX_CHANS) break; - } - - index=0; - for (DivInstrumentType i: chInsType1) { - chanInsType[index++][0]=i; - if (index>=DIV_MAX_CHANS) break; - } - - index=0; - for (DivInstrumentType i: chInsType2) { - chanInsType[index++][1]=i; - if (index>=DIV_MAX_CHANS) break; - } - } -}; - -enum DivChanTypes { - DIV_CH_FM=0, - DIV_CH_PULSE=1, - DIV_CH_NOISE=2, - DIV_CH_WAVE=3, - DIV_CH_PCM=4, - DIV_CH_OP=5 -}; - extern const char* cmdName[]; class DivEngine { diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 5d8451aa0..4045bd572 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -928,17 +928,20 @@ void DivSong::recalcChans() { dispatchChanOfChan[chanIndex]=-1; } dispatchFirstChan[chanIndex]=firstChan; - chanIndex++; - if (sysDef!=NULL) { - if (sysDef->chanInsType[j][0]!=DIV_INS_NULL) { - isInsTypePossible[sysDef->chanInsType[j][0]]=true; + chanDef[chanIndex]=sysDef->getChanDef(j); + if (chanDef[chanIndex].insType[0]!=DIV_INS_NULL) { + isInsTypePossible[chanDef[chanIndex].insType[0]]=true; } - if (sysDef->chanInsType[j][1]!=DIV_INS_NULL) { - isInsTypePossible[sysDef->chanInsType[j][1]]=true; + if (chanDef[chanIndex].insType[1]!=DIV_INS_NULL) { + isInsTypePossible[chanDef[chanIndex].insType[1]]=true; } + } else { + chanDef[chanIndex]=DivChanDef(); } + + chanIndex++; } } diff --git a/src/engine/song.h b/src/engine/song.h index 7c2745d1d..eb6dfc804 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -32,125 +32,7 @@ #include "pattern.h" #include "wavetable.h" #include "sample.h" - -enum DivSystem { - DIV_SYSTEM_NULL=0, - DIV_SYSTEM_YMU759, - DIV_SYSTEM_GENESIS, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_GENESIS_EXT, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_SMS, - DIV_SYSTEM_SMS_OPLL, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_GB, - DIV_SYSTEM_PCE, - DIV_SYSTEM_NES, - DIV_SYSTEM_NES_VRC7, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_NES_FDS, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_C64_6581, - DIV_SYSTEM_C64_8580, - DIV_SYSTEM_ARCADE, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_MSX2, // ** COMPOUND SYSTEM - DO NOT USE! ** - DIV_SYSTEM_YM2610, - DIV_SYSTEM_YM2610_EXT, - - DIV_SYSTEM_AY8910, - DIV_SYSTEM_AMIGA, - DIV_SYSTEM_YM2151, - DIV_SYSTEM_YM2612, - DIV_SYSTEM_TIA, - DIV_SYSTEM_SAA1099, - DIV_SYSTEM_AY8930, - DIV_SYSTEM_VIC20, - DIV_SYSTEM_PET, - DIV_SYSTEM_SNES, - DIV_SYSTEM_VRC6, - DIV_SYSTEM_OPLL, - DIV_SYSTEM_FDS, - DIV_SYSTEM_MMC5, - DIV_SYSTEM_N163, - DIV_SYSTEM_YM2203, - DIV_SYSTEM_YM2203_EXT, - DIV_SYSTEM_YM2608, - DIV_SYSTEM_YM2608_EXT, - DIV_SYSTEM_OPL, - DIV_SYSTEM_OPL2, - DIV_SYSTEM_OPL3, - DIV_SYSTEM_MULTIPCM, - DIV_SYSTEM_PCSPKR, - DIV_SYSTEM_POKEY, - DIV_SYSTEM_RF5C68, - DIV_SYSTEM_SWAN, - DIV_SYSTEM_OPZ, - DIV_SYSTEM_POKEMINI, - DIV_SYSTEM_SEGAPCM, - DIV_SYSTEM_VBOY, - DIV_SYSTEM_VRC7, - DIV_SYSTEM_YM2610B, - DIV_SYSTEM_SFX_BEEPER, - DIV_SYSTEM_SFX_BEEPER_QUADTONE, - DIV_SYSTEM_YM2612_EXT, - DIV_SYSTEM_SCC, - DIV_SYSTEM_OPL_DRUMS, - DIV_SYSTEM_OPL2_DRUMS, - DIV_SYSTEM_OPL3_DRUMS, - DIV_SYSTEM_YM2610_FULL, - DIV_SYSTEM_YM2610_FULL_EXT, - DIV_SYSTEM_OPLL_DRUMS, - DIV_SYSTEM_LYNX, - DIV_SYSTEM_QSOUND, - DIV_SYSTEM_VERA, - DIV_SYSTEM_YM2610B_EXT, - DIV_SYSTEM_SEGAPCM_COMPAT, - DIV_SYSTEM_X1_010, - DIV_SYSTEM_BUBSYS_WSG, - DIV_SYSTEM_OPL4, - DIV_SYSTEM_OPL4_DRUMS, - DIV_SYSTEM_ES5506, - DIV_SYSTEM_Y8950, - DIV_SYSTEM_Y8950_DRUMS, - DIV_SYSTEM_SCC_PLUS, - DIV_SYSTEM_SOUND_UNIT, - DIV_SYSTEM_MSM6295, - DIV_SYSTEM_MSM6258, - DIV_SYSTEM_YMZ280B, - DIV_SYSTEM_NAMCO, - DIV_SYSTEM_NAMCO_15XX, - DIV_SYSTEM_NAMCO_CUS30, - DIV_SYSTEM_YM2612_DUALPCM, - DIV_SYSTEM_YM2612_DUALPCM_EXT, - DIV_SYSTEM_MSM5232, - DIV_SYSTEM_T6W28, - DIV_SYSTEM_K007232, - DIV_SYSTEM_GA20, - DIV_SYSTEM_PCM_DAC, - DIV_SYSTEM_PONG, - DIV_SYSTEM_DUMMY, - DIV_SYSTEM_YM2612_CSM, - DIV_SYSTEM_YM2610_CSM, - DIV_SYSTEM_YM2610B_CSM, - DIV_SYSTEM_YM2203_CSM, - DIV_SYSTEM_YM2608_CSM, - DIV_SYSTEM_SM8521, - DIV_SYSTEM_PV1000, - DIV_SYSTEM_K053260, - DIV_SYSTEM_TED, - DIV_SYSTEM_C140, - DIV_SYSTEM_C219, - DIV_SYSTEM_ESFM, - DIV_SYSTEM_POWERNOISE, - DIV_SYSTEM_DAVE, - DIV_SYSTEM_NDS, - DIV_SYSTEM_GBA_DMA, - DIV_SYSTEM_GBA_MINMOD, - DIV_SYSTEM_5E01, - DIV_SYSTEM_BIFURCATOR, - DIV_SYSTEM_SID2, - DIV_SYSTEM_SUPERVISION, - DIV_SYSTEM_UPD1771C, - DIV_SYSTEM_SID3, - DIV_SYSTEM_C64_PCM, - - DIV_SYSTEM_MAX -}; +#include "sysDef.h" enum DivEffectType: unsigned short { DIV_EFFECT_NULL=0, @@ -463,6 +345,8 @@ struct DivSong { int dispatchChanOfChan[DIV_MAX_CHANS]; // the first channel of a chip, indexed per channel int dispatchFirstChan[DIV_MAX_CHANS]; + // cached DivChanDef for each channel. + DivChanDef chanDef[DIV_MAX_CHANS]; std::vector possibleInsTypes; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 4d3f78e08..36098c711 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -313,44 +313,38 @@ bool DivEngine::isSTDSystem(DivSystem sys) { const char* DivEngine::getChannelName(int chan) { if (chan<0 || chan>song.chans) return "??"; if (!curSubSong->chanName[chan].empty()) return curSubSong->chanName[chan].c_str(); - if (sysDefs[song.sysOfChan[chan]]==NULL) return "??"; if (song.dispatchChanOfChan[chan]<0) return "??"; - const char* ret=sysDefs[song.sysOfChan[chan]]->chanNames[song.dispatchChanOfChan[chan]]; - if (ret==NULL) return "??"; - return ret; + return song.chanDef[chan].name.c_str(); } const char* DivEngine::getChannelShortName(int chan) { if (chan<0 || chan>song.chans) return "??"; if (!curSubSong->chanShortName[chan].empty()) return curSubSong->chanShortName[chan].c_str(); - if (sysDefs[song.sysOfChan[chan]]==NULL) return "??"; if (song.dispatchChanOfChan[chan]<0) return "??"; - const char* ret=sysDefs[song.sysOfChan[chan]]->chanShortNames[song.dispatchChanOfChan[chan]]; - if (ret==NULL) return "??"; - return ret; + return song.chanDef[chan].shortName.c_str(); } int DivEngine::getChannelType(int chan) { if (chan<0 || chan>song.chans) return DIV_CH_NOISE; - if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_CH_NOISE; if (song.dispatchChanOfChan[chan]<0) return DIV_CH_NOISE; - return sysDefs[song.sysOfChan[chan]]->chanTypes[song.dispatchChanOfChan[chan]]; + + return song.chanDef[chan].type; } DivInstrumentType DivEngine::getPreferInsType(int chan) { if (chan<0 || chan>song.chans) return DIV_INS_STD; - if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_INS_STD; if (song.dispatchChanOfChan[chan]<0) return DIV_INS_STD; - return sysDefs[song.sysOfChan[chan]]->chanInsType[song.dispatchChanOfChan[chan]][0]; + + return song.chanDef[chan].insType[0]; } DivInstrumentType DivEngine::getPreferInsSecondType(int chan) { if (chan<0 || chan>song.chans) return DIV_INS_NULL; - if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_INS_NULL; if (song.dispatchChanOfChan[chan]<0) return DIV_INS_NULL; - return sysDefs[song.sysOfChan[chan]]->chanInsType[song.dispatchChanOfChan[chan]][1]; + + return song.chanDef[chan].insType[1]; } int DivEngine::minVGMVersion(DivSystem which) { @@ -375,15 +369,21 @@ int DivEngine::minVGMVersion(DivSystem which) { // "Name", "Name (japanese, optional)", fileID, fileID_DMF, channels, minChans, maxChans, // isFM, isSTD, vgmVersion, waveWidth, waveHeight, // "Description", -// {"Channel Names", ...}, -// {"Channel Short Names", ...}, -// {chanTypes, ...}, -// {chanPreferInsType, ...}, -// {chanPreferInsType2, ...}, (optional) +// Channel Definition Function, // {{effect, {DIV_CMD_xx, "Description"}}, ...}, (effect handler, optional) // {{effect, {DIV_CMD_xx, "Description"}}, ...} (post effect handler, optional) // ); +// +// Channel Definition Function can be any of the following: +// - DivChanDefFunc(): invalid/default +// - DivChanDefFunc({...}): list of channel definitions. for example: +// DivChanDefFunc({ +// DivChanDef("Square", "S", DIV_CH_PULSE, DIV_INS_MY_SYSTEM), +// DivChanDef("PCM", "P", DIV_CH_PCM, DIV_INS_MY_SYSTEM) +// }) +// - DivChanDefFunc([]() -> DivChanDef {...}): custom function +// these are effect handler helpers. template int constVal(unsigned char, unsigned char) { return val; }; @@ -422,6 +422,38 @@ template int effectValLongShift(unsigned char c return (((((unsigned int)cmd)&((1<<(bits-8))-1))<<8)|((unsigned int)val))< std::function stockChanDef=[](unsigned short ch) -> DivChanDef { + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf("%d",ch+1), + type, + insType, + insType2 + ); +}; + +template std::function simpleChanDef=[](unsigned short ch) -> DivChanDef { + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf(_("CH%d"),ch+1), + type, + insType, + insType2 + ); +}; + +template std::function fmChanDef=[](unsigned short ch) -> DivChanDef { + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + type, + insType, + insType2 + ); +}; + void DivEngine::registerSystems() { logD("registering systems..."); @@ -823,35 +855,38 @@ void DivEngine::registerSystems() { _("Yamaha YMU759 (MA-2)"), NULL, 0x01, 0x01, 17, 17, 17, true, false, 0, false, (1U< DivChanDef { + if (ch==16) { + return DivChanDef(_("PCM"),_("PCM"),DIV_CH_PCM,DIV_INS_AMIGA); + } + return stockChanDef(ch); + }) ); sysDefs[DIV_SYSTEM_GENESIS]=new DivSysDef( _("Sega Genesis/Mega Drive"), "セガメガドライブ", 0x02, 0x02, 10, 10, 10, true, true, 0, true, 0, 0, 0, "", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_GENESIS_EXT]=new DivSysDef( _("Sega Genesis Extended Channel 3"), NULL, 0x42, 0x42, 13, 13, 13, true, true, 0, true, 0, 0, 0, "", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_SMS]=new DivSysDef( _("TI SN76489"), NULL, 0x03, 0x03, 4, 4, 4, false, true, 0x150, false, 0, 0, 0, _("a square/noise sound chip found on the Sega Master System, ColecoVision, Tandy, TI's own 99/4A and a few other places."), - {_("Square 1"), _("Square 2"), _("Square 3"), _("Noise")}, - {"S1", "S2", "S3", "NO"}, - {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, - {}, + DivChanDefFunc({ + DivChanDef(_("Square 1"), "S1", DIV_CH_PULSE, DIV_INS_STD), + DivChanDef(_("Square 2"), "S2", DIV_CH_PULSE, DIV_INS_STD), + DivChanDef(_("Square 3"), "S3", DIV_CH_PULSE, DIV_INS_STD), + DivChanDef(_("Noise") , "NO", DIV_CH_NOISE, DIV_INS_STD) + }), { {0x20, {DIV_CMD_STD_NOISE_MODE, _("20xy: Set noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)")}} } @@ -861,18 +896,19 @@ void DivEngine::registerSystems() { _("Sega Master System + FM Expansion"), NULL, 0x43, 0x43, 13, 13, 13, true, true, 0, true, 0, 0, 0, "", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_GB]=new DivSysDef( _("Game Boy"), NULL, 0x04, 0x04, 4, 4, 4, false, true, 0x161, false, 0, 32, 16, _("the most popular portable game console of the era."), - {_("Pulse 1"), _("Pulse 2"), _("Wavetable"), _("Noise")}, - {"S1", "S2", "WA", "NO"}, - {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE}, - {DIV_INS_GB, DIV_INS_GB, DIV_INS_GB, DIV_INS_GB}, - {}, + DivChanDefFunc({ + DivChanDef(_("Pulse 1") , "S1", DIV_CH_PULSE, DIV_INS_GB), + DivChanDef(_("Pulse 2") , "S2", DIV_CH_PULSE, DIV_INS_GB), + DivChanDef(_("Wavetable"), "WA", DIV_CH_WAVE , DIV_INS_GB), + DivChanDef(_("Noise") , "NO", DIV_CH_NOISE, DIV_INS_GB) + }), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Set noise length (0: long; 1: short)")}}, @@ -886,11 +922,7 @@ void DivEngine::registerSystems() { _("PC Engine/TurboGrafx-16"), NULL, 0x05, 0x05, 6, 6, 6, false, true, 0x161, false, 1U<), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Toggle noise mode")}}, @@ -903,11 +935,13 @@ void DivEngine::registerSystems() { _("NES (Ricoh 2A03)"), NULL, 0x06, 0x06, 5, 5, 5, false, true, 0x161, false, (1U<", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_NES_FDS]=new DivSysDef( _("Famicom Disk System"), NULL, 0, 0x86, 6, 6, 6, false, true, 0, true, 0, 0, 0, "", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_C64_6581]=new DivSysDef( _("Commodore 64 (SID 6581)"), NULL, 0x47, 0x47, 3, 3, 3, false, true, 0, false, 0, 0, 0, _("this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR."), - {_("Channel 1"), _("Channel 2"), _("Channel 3")}, - {"CH1", "CH2", "CH3"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, - {}, + DivChanDefFunc(simpleChanDef), {}, c64PostEffectHandlerMap ); @@ -953,11 +983,7 @@ void DivEngine::registerSystems() { _("Commodore 64 (SID 8580)"), NULL, 0x07, 0x07, 3, 3, 3, false, true, 0, false, 0, 0, 0, _("this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR.\nthis is the newer revision of the chip."), - {_("Channel 1"), _("Channel 2"), _("Channel 3")}, - {"CH1", "CH2", "CH3"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, - {}, + DivChanDefFunc(simpleChanDef), {}, c64PostEffectHandlerMap ); @@ -966,18 +992,28 @@ void DivEngine::registerSystems() { _("DefleCade"), NULL, 0x08, 0x08, 13, 13, 13, true, false, 0, true, 0, 0, 0, "", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_YM2610]=new DivSysDef( _("Neo Geo CD"), NULL, 0x09, 0x09, 13, 13, 13, true, true, 0x151, false, (1U<", - {}, {}, {}, {} + DivChanDefFunc() ); sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef( _("AY-3-8910"), NULL, 0x80, 0, 3, 3, 3, false, true, 0x151, false, 1U<), {}, { {0x10, {DIV_CMD_AMIGA_FILTER, _("10xx: Toggle filter (0 disables; 1 enables)")}}, @@ -1038,11 +1083,7 @@ void DivEngine::registerSystems() { _("Yamaha YM2151 (OPM)"), NULL, 0x82, 0, 8, 8, 8, true, false, 0x150, false, 0, 0, 0, _("this was Yamaha's first integrated FM chip.\nit was used in several synthesizers, computers and arcade boards."), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("FM 7"), _("FM 8")}, - {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM}, - {}, + DivChanDefFunc(fmChanDef), fmEffectHandlerMap, fmOPMPostEffectHandlerMap ); @@ -1051,11 +1092,14 @@ void DivEngine::registerSystems() { _("Yamaha YM2612 (OPN2)"), NULL, 0x83, 0, 6, 6, 6, true, false, 0x150, false, 1U<), {}, waveOnlyEffectHandlerMap ); @@ -1077,11 +1117,14 @@ void DivEngine::registerSystems() { _("Philips SAA1099"), NULL, 0x97, 0, 6, 6, 6, false, true, 0x171, false, 0, 0, 0, _("supposedly an upgrade from the AY-3-8910, this was present on the Creative Music System (Game Blaster) and SAM Coupé."), - {_("PSG 1"), _("PSG 2"), _("PSG 3"), _("PSG 4"), _("PSG 5"), _("PSG 6")}, - {"S1", "S2", "S3", "S4", "S5", "S6"}, - {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099}, - {}, + DivChanDefFunc({ + DivChanDef(_("PSG 1"), "S1", DIV_CH_PULSE, DIV_INS_SAA1099), + DivChanDef(_("PSG 2"), "S2", DIV_CH_PULSE, DIV_INS_SAA1099), + DivChanDef(_("PSG 3"), "S3", DIV_CH_PULSE, DIV_INS_SAA1099), + DivChanDef(_("PSG 4"), "S4", DIV_CH_PULSE, DIV_INS_SAA1099), + DivChanDef(_("PSG 5"), "S5", DIV_CH_PULSE, DIV_INS_SAA1099), + DivChanDef(_("PSG 6"), "S6", DIV_CH_PULSE, DIV_INS_SAA1099), + }), {}, { {0x10, {DIV_CMD_STD_NOISE_MODE, _("10xy: Set channel mode (x: noise; y: tone)")}}, @@ -1094,11 +1137,11 @@ void DivEngine::registerSystems() { _("Microchip AY8930"), NULL, 0x9a, 0, 3, 3, 3, false, true, 0x151, false, 1U<), { {0x18, {DIV_CMD_SNES_ECHO_ENABLE, _("18xx: Enable echo buffer")}}, {0x19, {DIV_CMD_SNES_ECHO_DELAY, _("19xx: Set echo delay (0 to F)")}}, @@ -1173,11 +1211,11 @@ void DivEngine::registerSystems() { _("Konami VRC6"), NULL, 0x88, 0, 3, 3, 3, false, true, 0, false, 1U<), fmEffectHandlerMap, fmOPLLPostEffectHandlerMap ); @@ -1200,11 +1234,9 @@ void DivEngine::registerSystems() { _("Famicom Disk System (chip)"), NULL, 0x8a, 0, 1, 1, 1, false, true, 0x161, false, 0, 64, 64, _("a disk drive for the Famicom which also contains one wavetable channel."), - {_("FDS")}, - {"FDS"}, - {DIV_CH_WAVE}, - {DIV_INS_FDS}, - {}, + DivChanDefFunc({ + DivChanDef(_("FDS"), "FDS", DIV_CH_WAVE, DIV_INS_FDS) + }), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, }, @@ -1222,11 +1254,11 @@ void DivEngine::registerSystems() { _("MMC5"), NULL, 0x8b, 0, 3, 3, 3, false, true, 0, false, 1U<), { {0x18, {DIV_CMD_N163_CHANNEL_LIMIT, _("18xx: Change channel limits (0 to 7, x + 1)")}}, {0x20, {DIV_CMD_N163_GLOBAL_WAVE_LOAD, _("20xx: Load a waveform into memory")}}, @@ -1259,11 +1287,14 @@ void DivEngine::registerSystems() { _("Yamaha YM2203 (OPN)"), NULL, 0x8d, 0, 6, 6, 6, true, true, 0x151, false, 1U<), fmEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1356,11 +1442,7 @@ void DivEngine::registerSystems() { _("Yamaha YM3812 (OPL2)"), NULL, 0x90, 0, 9, 9, 9, true, false, 0x151, false, 0, 0, 0, _("OPL, but what if you had more waveforms to choose than the normal sine?"), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("FM 7"), _("FM 8"), _("FM 9")}, - {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - {}, + DivChanDefFunc(fmChanDef), fmEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1369,11 +1451,22 @@ void DivEngine::registerSystems() { _("Yamaha YMF262 (OPL3)"), NULL, 0x91, 0, 18, 18, 18, true, false, 0x151, false, 0, 0, 0, _("OPL2, but what if you had twice the channels, 4-op mode, stereo and even more waveforms?"), - {_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18")}, - {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"}, - {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - {}, + DivChanDefFunc([](unsigned short ch) -> DivChanDef { + if (ch<12 && !(ch&1)) { + return DivChanDef( + fmt::sprintf(_("4OP %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_OP, + DIV_INS_OPL + ); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1382,11 +1475,7 @@ void DivEngine::registerSystems() { _("MultiPCM"), NULL, 0x92, 0, 28, 28, 28, false, true, 0x161, false, (1U<), {}, multiPCMPostEffectHandlerMap ); @@ -1395,31 +1484,25 @@ void DivEngine::registerSystems() { _("PC Speaker"), NULL, 0x93, 0, 1, 1, 1, false, true, 0, false, 0, 0, 0, _("good luck! you get one square and no volume control."), - {_("Square")}, - {"SQ"}, - {DIV_CH_PULSE}, - {DIV_INS_BEEPER} + DivChanDefFunc({ + DivChanDef(_("Square"), "SQ", DIV_CH_PULSE, DIV_INS_BEEPER) + }) ); sysDefs[DIV_SYSTEM_PONG]=new DivSysDef( _("Pong"), NULL, 0xfc, 0, 1, 1, 1, false, true, 0, false, 0, 0, 0, _("please don't use this chip. it was added as a joke."), - {_("Square")}, - {"SQ"}, - {DIV_CH_PULSE}, - {DIV_INS_BEEPER} + DivChanDefFunc({ + DivChanDef(_("Square"), "SQ", DIV_CH_PULSE, DIV_INS_BEEPER) + }) ); sysDefs[DIV_SYSTEM_POKEY]=new DivSysDef( _("POKEY"), NULL, 0x94, 0, 4, 4, 4, false, true, 0x161, false, 0, 0, 0, _("TIA, but better and more flexible.\nused in the Atari 8-bit family of computers (400/800/XL/XE)."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4")}, - {"CH1", "CH2", "CH3", "CH4"}, - {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_POKEY, DIV_INS_POKEY, DIV_INS_POKEY, DIV_INS_POKEY}, - {}, + DivChanDefFunc(simpleChanDef), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform (0 to 7)")}}, {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Set AUDCTL")}}, @@ -1431,22 +1514,19 @@ void DivEngine::registerSystems() { _("Ricoh RF5C68"), NULL, 0x95, 0, 8, 8, 8, false, true, 0x151, false, 1U<) ); sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef( _("WonderSwan"), NULL, 0x96, 0, 4, 4, 4, false, true, 0x171, false, 1U<), { {0x2f, {DIV_CMD_FM_HARD_RESET, _("2Fxx: Toggle hard envelope reset on new notes")}}, }, @@ -1477,21 +1553,16 @@ void DivEngine::registerSystems() { _("Pokémon Mini"), NULL, 0x99, 0, 1, 1, 1, false, true, 0, false, 0, 0, 0, _("this one is like PC Speaker but has duty cycles."), - {_("Pulse")}, - {"P"}, - {DIV_CH_PULSE}, - {DIV_INS_POKEMINI} + DivChanDefFunc({ + DivChanDef(_("Pulse"), "P", DIV_CH_PULSE, DIV_INS_POKEMINI) + }) ); sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef( _("SegaPCM"), NULL, 0x9b, 0, 16, 16, 16, false, true, 0x151, false, 1U<), {}, segaPCMPostEffectHandlerMap ); @@ -1500,11 +1571,22 @@ void DivEngine::registerSystems() { _("Virtual Boy"), NULL, 0x9c, 0, 6, 6, 6, false, true, 0x171, false, 1U< DivChanDef { + if (ch==5) { + return DivChanDef( + _("Noise"), + "NO", + DIV_CH_NOISE, + DIV_INS_VBOY + ); + } + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf(_("CH%d"),ch+1), + DIV_CH_WAVE, + DIV_INS_VBOY + ); + }), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Set noise length (0 to 7)")}}, @@ -1519,11 +1601,7 @@ void DivEngine::registerSystems() { _("Konami VRC7"), NULL, 0x9d, 0, 6, 6, 6, true, false, 0x151, false, 0, 0, 0, _("like OPLL, but even more cost reductions applied. three FM channels went missing, and drums mode did as well..."), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6")}, - {"F1", "F2", "F3", "F4", "F5", "F6"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, - {}, + DivChanDefFunc(fmChanDef), fmEffectHandlerMap, fmOPLLPostEffectHandlerMap ); @@ -1532,11 +1610,24 @@ void DivEngine::registerSystems() { _("Yamaha YM2610B (OPNB2)"), NULL, 0x9e, 0, 16, 16, 16, true, false, 0x151, false, (1U<), { {0x12, {DIV_CMD_STD_NOISE_MODE, _("12xx: Set pulse width")}}, {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Trigger overlay drum")}}, @@ -1560,11 +1647,17 @@ void DivEngine::registerSystems() { _("Yamaha YM2612 (OPN2) Extended Channel 3"), NULL, 0xa0, 0, 9, 9, 9, true, false, 0x150, false, 1U<), waveOnlyEffectHandlerMap ); @@ -1600,11 +1696,26 @@ void DivEngine::registerSystems() { _("Yamaha YM3526 (OPL) with drums"), NULL, 0xa2, 0, 11, 11, 11, true, false, 0x151, false, 0, 0, 0, _("the OPL chip but with drums mode enabled."), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("Kick/FM 7"), _("Snare"), _("Tom"), _("Top"), _("HiHat")}, - {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + DivChanDefFunc([](unsigned short ch) -> DivChanDef { + switch (ch) { + case 6: + return DivChanDef(_("Kick/FM 7"), _("BD"), DIV_CH_NOISE, DIV_INS_OPL); + case 7: + return DivChanDef(_("Snare") , _("SD"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 8: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 9: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 10: + return DivChanDef(_("HiHat") , _("HH"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1613,11 +1724,26 @@ void DivEngine::registerSystems() { _("Yamaha YM3812 (OPL2) with drums"), NULL, 0xa3, 0, 11, 11, 11, true, false, 0x151, false, 0, 0, 0, _("the OPL2 chip but with drums mode enabled."), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("Kick/FM 7"), _("Snare"), _("Tom"), _("Top"), _("HiHat")}, - {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + DivChanDefFunc([](unsigned short ch) -> DivChanDef { + switch (ch) { + case 6: + return DivChanDef(_("Kick/FM 7"), _("BD"), DIV_CH_NOISE, DIV_INS_OPL); + case 7: + return DivChanDef(_("Snare") , _("SD"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 8: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 9: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 10: + return DivChanDef(_("HiHat") , _("HH"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1626,11 +1752,34 @@ void DivEngine::registerSystems() { _("Yamaha YMF262 (OPL3) with drums"), NULL, 0xa4, 0, 20, 20, 20, true, false, 0x151, false, 0, 0, 0, _("the OPL3 chip but with drums mode enabled."), - {_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("Kick/FM 16"), _("Snare"), _("Tom"), _("Top"), _("HiHat")}, - {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"}, - {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + DivChanDefFunc([](unsigned short ch) -> DivChanDef { + switch (ch) { + case 15: + return DivChanDef(_("Kick/FM 16"), _("BD"), DIV_CH_NOISE, DIV_INS_OPL); + case 16: + return DivChanDef(_("Snare") , _("SD"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 17: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 18: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 19: + return DivChanDef(_("HiHat") , _("HH"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + } + if (ch<12 && !(ch&1)) { + return DivChanDef( + fmt::sprintf(_("4OP %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_OP, + DIV_INS_OPL + ); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1639,11 +1788,22 @@ void DivEngine::registerSystems() { _("Yamaha YM2610 (OPNB)"), NULL, 0xa5, 0, 14, 14, 14, true, false, 0x151, false, (1U< DivChanDef { + switch (ch) { + case 6: + return DivChanDef(_("Kick") , _("BD"), DIV_CH_NOISE, DIV_INS_OPLL); + case 7: + return DivChanDef(_("Snare"), _("SD"), DIV_CH_NOISE, DIV_INS_OPLL); + case 8: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPLL); + case 9: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPLL); + case 10: + return DivChanDef(_("HiHat"), _("HH"), DIV_CH_NOISE, DIV_INS_OPLL); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + DIV_CH_FM, + DIV_INS_OPLL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPLLPostEffectHandlerMap ); @@ -1699,11 +1903,7 @@ void DivEngine::registerSystems() { _("Atari Lynx"), NULL, 0xa8, 0, 4, 4, 4, false, true, 0x172, false, 1U<), {}, lynxEffectHandlerMap ); @@ -1722,11 +1922,24 @@ void DivEngine::registerSystems() { _("Capcom QSound"), NULL, 0xe0, 0, 19, 19, 19, false, true, 0x161, false, (1U< DivChanDef { + if (ch>=16) { + return DivChanDef( + fmt::sprintf(_("ADPCM %d"),ch-15), + fmt::sprintf("A%d",ch-15), + DIV_CH_NOISE, + DIV_INS_QSOUND, + DIV_INS_AMIGA + ); + } + return DivChanDef( + fmt::sprintf(_("PCM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_PCM, + DIV_INS_QSOUND, + DIV_INS_AMIGA + ); + }), qSoundEffectHandlerMap ); @@ -1734,11 +1947,22 @@ void DivEngine::registerSystems() { _("VERA"), NULL, 0xac, 0, 17, 17, 17, false, true, 0, false, (1U< DivChanDef { + if (ch==16) { + return DivChanDef( + _("PCM"), + _("PCM"), + DIV_CH_PCM, + DIV_INS_AMIGA + ); + } + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_PULSE, + DIV_INS_VERA + ); + }), { {0x20, {DIV_CMD_WAVE, _("20xx: Set waveform")}}, {0x22, {DIV_CMD_STD_NOISE_MODE, _("22xx: Set duty cycle (0 to 3F)")}}, @@ -1749,11 +1973,27 @@ void DivEngine::registerSystems() { _("Yamaha YM2610B (OPNB2) Extended Channel 3"), NULL, 0xde, 0, 19, 19, 19, true, false, 0x151, false, (1U<), {}, segaPCMPostEffectHandlerMap ); @@ -1791,11 +2044,7 @@ void DivEngine::registerSystems() { _("Seta/Allumer X1-010"), NULL, 0xb0, 0, 16, 16, 16, false, true, 0x171, false, 1U<), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, {0x11, {DIV_CMD_X1_010_ENVELOPE_SHAPE, _("11xx: Set envelope shape")}}, @@ -1815,10 +2064,7 @@ void DivEngine::registerSystems() { _("Konami Bubble System WSG"), NULL, 0xad, 0, 2, 2, 2, false, true, 0, false, 0, 32, 16, _("this is the wavetable part of the Bubble System, which also had two AY-3-8910s."), - {_("Channel 1"), _("Channel 2")}, - {"CH1", "CH2"}, - {DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_SCC, DIV_INS_SCC}, + DivChanDefFunc(simpleChanDef), {}, waveOnlyEffectHandlerMap ); @@ -1827,11 +2073,33 @@ void DivEngine::registerSystems() { _("Yamaha YMF278B (OPL4)"), NULL, 0xae, 0, 42, 42, 42, true, true, 0x151, false, (1U< DivChanDef { + if (ch>=18) { + return DivChanDef( + fmt::sprintf(_("PCM %d"),ch-17), + fmt::sprintf("P%d",ch-17), + DIV_CH_PCM, + DIV_INS_MULTIPCM, + DIV_INS_AMIGA + ); + } + if (ch<12 && !(ch&1)) { + return DivChanDef( + fmt::sprintf(_("4OP %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_OP, + DIV_INS_OPL, + DIV_INS_OPL + ); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL, + DIV_INS_OPL + ); + }), fmEffectHandlerMap, fmOPL4PostEffectHandlerMap ); @@ -1840,11 +2108,45 @@ void DivEngine::registerSystems() { _("Yamaha YMF278B (OPL4) with drums"), NULL, 0xaf, 0, 44, 44, 44, true, true, 0x151, false, (1U< DivChanDef { + if (ch>=20) { + return DivChanDef( + fmt::sprintf(_("PCM %d"),ch-19), + fmt::sprintf("P%d",ch-19), + DIV_CH_PCM, + DIV_INS_MULTIPCM, + DIV_INS_AMIGA + ); + } + switch (ch) { + case 15: + return DivChanDef(_("Kick/FM 16"), _("BD"), DIV_CH_NOISE, DIV_INS_OPL); + case 16: + return DivChanDef(_("Snare") , _("SD"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 17: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 18: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 19: + return DivChanDef(_("HiHat") , _("HH"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + } + if (ch<12 && !(ch&1)) { + return DivChanDef( + fmt::sprintf(_("4OP %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_OP, + DIV_INS_OPL, + DIV_INS_OPL + ); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL, + DIV_INS_OPL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPL4PostEffectHandlerMap ); @@ -1882,11 +2184,7 @@ void DivEngine::registerSystems() { _("Ensoniq ES5506"), NULL, 0xb1, 0, 32, 5, 32, false, true, 0/*0x171*/, false, (1U<), es5506PreEffectHandlerMap, es5506PostEffectHandlerMap ); @@ -1895,11 +2193,23 @@ void DivEngine::registerSystems() { _("Yamaha Y8950"), NULL, 0xb2, 0, 10, 10, 10, true, false, 0x151, false, 1U< DivChanDef { + if (ch==9) { + return DivChanDef( + _("ADPCM"), + _("P"), + DIV_CH_PCM, + DIV_INS_ADPCMB, + DIV_INS_AMIGA + ); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1908,11 +2218,28 @@ void DivEngine::registerSystems() { _("Yamaha Y8950 with drums"), NULL, 0xb3, 0, 12, 12, 12, true, false, 0x151, false, 1U< DivChanDef { + switch (ch) { + case 6: + return DivChanDef(_("Kick/FM 7"), _("BD"), DIV_CH_NOISE, DIV_INS_OPL); + case 7: + return DivChanDef(_("Snare") , _("SD"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 8: + return DivChanDef(_("Tom") , _("TM"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 9: + return DivChanDef(_("Top") , _("TP"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 10: + return DivChanDef(_("HiHat") , _("HH"), DIV_CH_NOISE, DIV_INS_OPL_DRUMS, DIV_INS_OPL); + case 11: + return DivChanDef(_("ADPCM") , _("P") , DIV_CH_PCM , DIV_INS_ADPCMB , DIV_INS_AMIGA); + } + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("F%d",ch+1), + DIV_CH_FM, + DIV_INS_OPL + ); + }), fmOPLDrumsEffectHandlerMap, fmOPLPostEffectHandlerMap ); @@ -1921,11 +2248,7 @@ void DivEngine::registerSystems() { _("Konami SCC+"), NULL, 0xb4, 0, 5, 5, 5, false, true, 0x161, false, 0, 32, 256, _("this is a variant of Konami's SCC chip with the last channel's wavetable being independent."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5")}, - {"CH1", "CH2", "CH3", "CH4", "CH5"}, - {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC}, - {}, + DivChanDefFunc(simpleChanDef), waveOnlyEffectHandlerMap ); @@ -1964,11 +2287,7 @@ void DivEngine::registerSystems() { _("tildearrow Sound Unit"), NULL, 0xb5, 0, 8, 8, 8, false, true, 0, false, 1U<), {}, suEffectHandlerMap ); @@ -1977,11 +2296,7 @@ void DivEngine::registerSystems() { _("OKI MSM6295"), NULL, 0xaa, 0, 4, 4, 4, false, true, 0x161, false, 1U<), { {0x20, {DIV_CMD_SAMPLE_FREQ, _("20xx: Set chip output rate (0: clock/132; 1: clock/165)")}}, } @@ -1991,11 +2306,9 @@ void DivEngine::registerSystems() { _("OKI MSM6258"), NULL, 0xab, 0, 1, 1, 1, false, true, 0x150, false, 1U< DivChanDef { + return DivChanDef( + fmt::sprintf(_("PCM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_PCM, + DIV_INS_YMZ280B, + DIV_INS_AMIGA + ); + }) ); EffectHandlerMap namcoEffectHandlerMap={ @@ -2026,11 +2343,7 @@ void DivEngine::registerSystems() { _("Namco WSG"), NULL, 0xb9, 0, 3, 3, 3, false, true, 0, false, 0, 32, 16, _("a wavetable sound chip used in Pac-Man, among other early Namco arcade games."), - {_("Channel 1"), _("Channel 2"), _("Channel 3")}, - {"CH1", "CH2", "CH3"}, - {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, - {}, + DivChanDefFunc(simpleChanDef), namcoEffectHandlerMap ); @@ -2038,11 +2351,7 @@ void DivEngine::registerSystems() { _("Namco C15 WSG"), NULL, 0xba, 0, 8, 8, 8, false, true, 0, false, 0, 32, 16, _("successor of the original Namco WSG chip, used in later Namco arcade games."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Channel 7"), _("Channel 8")}, - {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, - {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, - {}, + DivChanDefFunc(simpleChanDef), namcoEffectHandlerMap ); @@ -2050,11 +2359,7 @@ void DivEngine::registerSystems() { _("Namco C30 WSG"), NULL, 0xbb, 0, 8, 8, 8, false, true, 0, false, 0, 32, 16, _("like Namco C15 but with stereo sound."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Channel 7"), _("Channel 8")}, - {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, - {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, - {}, + DivChanDefFunc(simpleChanDef), namcoC30EffectHandlerMap ); @@ -2062,11 +2367,7 @@ void DivEngine::registerSystems() { _("OKI MSM5232"), NULL, 0xbc, 0, 8, 8, 8, false, true, 0, false, 0, 0, 0, _("a square wave additive synthesis chip made by OKI. used in some arcade machines and instruments."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Channel 7"), _("Channel 8")}, - {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, - {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232, DIV_INS_MSM5232}, - {}, + DivChanDefFunc(simpleChanDef), {}, { {0x10, {DIV_CMD_WAVE, _("10xy: Set group control (x: sustain; y: part toggle bitmask)")}}, @@ -2080,11 +2381,15 @@ void DivEngine::registerSystems() { _("Yamaha YM2612 (OPN2) with DualPCM"), NULL, 0xbe, 0, 7, 7, 7, true, false, 0x150, false, 1U<), { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, } @@ -2136,33 +2446,26 @@ void DivEngine::registerSystems() { _("Konami K007232"), NULL, 0xc6, 0, 2, 2, 2, false, true, 0, false, 1U<) ); sysDefs[DIV_SYSTEM_GA20]=new DivSysDef( _("Irem GA20"), NULL, 0xc7, 0, 4, 4, 4, false, true, 0x171, false, 1U<) ); sysDefs[DIV_SYSTEM_SUPERVISION]=new DivSysDef( _("Watara Supervision"), NULL, 0xe3, 0, 4, 4, 4, false, true, 0, false, 1U<), { {0xdf, {DIV_CMD_SAMPLE_DIR, _("DFxx: Set sample playback direction (0: normal; 1: reverse)")}} } @@ -2241,22 +2543,14 @@ void DivEngine::registerSystems() { _("MOS Technology TED"), NULL, 0xcd, 0, 2, 2, 2, false, true, 0, false, 0, 0, 0, _("two square waves (one may be turned into noise). used in the Commodore Plus/4, 16 and 116."), - {_("Channel 1"), _("Channel 2")}, - {"CH1", "CH2"}, - {DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_TED, DIV_INS_TED}, - {} + DivChanDefFunc(simpleChanDef) ); sysDefs[DIV_SYSTEM_C140]=new DivSysDef( _("Namco C140"), NULL, 0xce, 0, 24, 24, 24, false, true, 0x161, false, (1U<), {} ); @@ -2264,11 +2558,7 @@ void DivEngine::registerSystems() { _("Namco C219"), NULL, 0xcf, 0, 16, 16, 16, false, true, 0x161, false, (1U<), {}, { {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Set noise mode")}}, @@ -2280,11 +2570,14 @@ void DivEngine::registerSystems() { _("ESS ES1xxx series (ESFM)"), NULL, 0xd1, 0, 18, 18, 18, true, false, 0, false, 0, 0, 0, _("a unique FM synth featured in PC sound cards.\nbased on the OPL3 design, but with lots of its features extended."), - {_("FM 1"), _("FM 2"), _("FM 3"), _("FM 4"), _("FM 5"), _("FM 6"), _("FM 7"), _("FM 8"), _("FM 9"), _("FM 10"), _("FM 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18")}, - {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"}, - {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM}, - {}, + DivChanDefFunc([](unsigned short ch) -> DivChanDef { + return DivChanDef( + fmt::sprintf(_("FM %d"),ch+1), + fmt::sprintf("%d",ch+1), + DIV_CH_FM, + DIV_INS_ESFM + ); + }), { {0x2e, {DIV_CMD_FM_HARD_RESET, _("2Exx: Toggle hard envelope reset on new notes")}}, }, @@ -2295,11 +2588,12 @@ void DivEngine::registerSystems() { _("PowerNoise"), NULL, 0xd4, 0, 4, 4, 4, false, false, 0, false, 0, 0, 0, _("a fantasy sound chip designed by jvsTSX and The Beesh-Spweesh!\nused in the Hexheld fantasy console."), - {_("Noise 1"), _("Noise 2"), _("Noise 3"), _("Slope")}, - {"N1", "N2", "N3", "SL"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_WAVE}, - {DIV_INS_POWERNOISE, DIV_INS_POWERNOISE, DIV_INS_POWERNOISE, DIV_INS_POWERNOISE_SLOPE}, - {}, + DivChanDefFunc({ + DivChanDef(_("Noise 1"), "N1", DIV_CH_NOISE, DIV_INS_POWERNOISE), + DivChanDef(_("Noise 2"), "N2", DIV_CH_NOISE, DIV_INS_POWERNOISE), + DivChanDef(_("Noise 3"), "N3", DIV_CH_NOISE, DIV_INS_POWERNOISE), + DivChanDef(_("Slope") , "SL", DIV_CH_WAVE , DIV_INS_POWERNOISE_SLOPE), + }), { {0x20, {DIV_CMD_POWERNOISE_COUNTER_LOAD, _("20xx: Load low byte of noise channel LFSR (00 to FF) or slope channel accumulator (00 to 7F)"), constVal<0>, effectVal}}, {0x21, {DIV_CMD_POWERNOISE_COUNTER_LOAD, _("21xx: Load high byte of noise channel LFSR (00 to FF)"), constVal<1>, effectVal}}, @@ -2313,11 +2607,14 @@ void DivEngine::registerSystems() { _("Dave"), NULL, 0xd5, 0, 6, 6, 6, false, true, 0, false, 1U<), {}, { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, @@ -2365,11 +2657,24 @@ void DivEngine::registerSystems() { _("Nintendo DS"), NULL, 0xd6, 0, 16, 16, 16, false, true, 0, false, (1U<), { {0x10, {DIV_CMD_BIFURCATOR_STATE_LOAD, _("10xx: Load low byte of channel sample state"), constVal<0>, effectVal}}, {0x11, {DIV_CMD_BIFURCATOR_STATE_LOAD, _("11xx: Load high byte of channel sample state"), constVal<1>, effectVal}}, @@ -2420,11 +2723,7 @@ void DivEngine::registerSystems() { _("SID2"), NULL, 0xf0, 0, 3, 3, 3, false, true, 0, false, 0, 0, 0, _("a fantasy sound chip created by LTVA. it is similar to the SID chip, but with many of its problems fixed."), - {_("Channel 1"), _("Channel 2"), _("Channel 3")}, - {"CH1", "CH2", "CH3"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_SID2, DIV_INS_SID2, DIV_INS_SID2}, - {}, + DivChanDefFunc(simpleChanDef), {}, SID2PostEffectHandlerMap ); @@ -2433,11 +2732,22 @@ void DivEngine::registerSystems() { _("SID3"), NULL, 0xf5, 0, 7, 7, 7, false, true, 0, false, (1U< DivChanDef { + if (ch==6) { + return DivChanDef( + _("Wave"), + "WA", + DIV_CH_WAVE, + DIV_INS_SID3 + ); + } + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf(_("CH%d"),ch+1), + DIV_CH_NOISE, + DIV_INS_SID3 + ); + }), {}, SID3PostEffectHandlerMap ); @@ -2446,11 +2756,22 @@ void DivEngine::registerSystems() { _("Commodore 64 (SID 6581) with software PCM"), NULL, 0xe2, 0, 4, 4, 4, false, true, 0, false, (1U< DivChanDef { + if (ch==3) { + return DivChanDef( + _("PCM"), + "P", + DIV_CH_PCM, + DIV_INS_AMIGA + ); + } + return DivChanDef( + fmt::sprintf(_("Channel %d"),ch+1), + fmt::sprintf(_("CH%d"),ch+1), + DIV_CH_NOISE, + DIV_INS_C64 + ); + }), {}, c64PostEffectHandlerMap ); @@ -2459,10 +2780,7 @@ void DivEngine::registerSystems() { _("Dummy System"), NULL, 0xfd, 0, 8, 1, 128, false, true, 0, false, 0, 0, 0, _("this is a system designed for testing purposes."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Channel 7"), _("Channel 8")}, - {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD} + DivChanDefFunc(stockChanDef) ); for (int i=0; i +#include + +typedef int EffectValConversion(unsigned char,unsigned char); + +struct EffectHandler { + DivDispatchCmds dispatchCmd; + const char* description; + EffectValConversion* val; + EffectValConversion* val2; + EffectHandler( + DivDispatchCmds dispatchCmd_, + const char* description_, + EffectValConversion val_=NULL, + EffectValConversion val2_=NULL + ): + dispatchCmd(dispatchCmd_), + description(description_), + val(val_), + val2(val2_) {} +}; + +struct DivDoNotHandleEffect { +}; + +typedef std::unordered_map EffectHandlerMap; + +enum DivChanTypes { + DIV_CH_FM=0, + DIV_CH_PULSE=1, + DIV_CH_NOISE=2, + DIV_CH_WAVE=3, + DIV_CH_PCM=4, + DIV_CH_OP=5 +}; + +struct DivChanDef { + String name; + String shortName; + int type; + // 0: primary + // 1: alternate (usually PCM) + DivInstrumentType insType[2]; + + DivChanDef(const String& n, const String& sn, int t, DivInstrumentType insT, DivInstrumentType insT2=DIV_INS_NULL): + name(n), + shortName(sn), + type(t), + insType{insT,insT2} {} + DivChanDef(): + name("??"), + shortName("??"), + type(DIV_CH_NOISE), + insType{DIV_INS_NULL,DIV_INS_NULL} {} +}; + +struct DivChanDefFunc { + std::vector list; + std::function func; + + DivChanDef operator()(int& ch) const { + if (ch<0) { + return DivChanDef("??","??",DIV_CH_NOISE,DIV_INS_NULL); + } + if (ch<(int)list.size()) return list[ch]; + if (func==NULL) { + return DivChanDef("??","??",DIV_CH_NOISE,DIV_INS_NULL); + } + return func(ch); + } + + DivChanDefFunc(std::initializer_list l): + list(l), func(NULL) {} + DivChanDefFunc(std::function f): + list(), func(f) {} + DivChanDefFunc(): + list(), func(NULL) {} +}; + +struct DivSysDef { + const char* name; + const char* nameJ; + const char* description; + unsigned char id; + unsigned char id_DMF; + int channels, minChans, maxChans; + bool isFM, isSTD, isCompound; + // width 0: variable + // height 0: no wavetable support + unsigned short waveWidth, waveHeight; + unsigned int vgmVersion; + unsigned int sampleFormatMask; + + DivChanDefFunc getChanDef; + + const EffectHandlerMap effectHandlers; + const EffectHandlerMap postEffectHandlers; + const EffectHandlerMap preEffectHandlers; + DivSysDef( + const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans, int minCh, int maxCh, + bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, unsigned int formatMask, unsigned short waveWid, unsigned short waveHei, + const char* desc, + DivChanDefFunc gcdFunc, + const EffectHandlerMap fxHandlers_={}, + const EffectHandlerMap postFxHandlers_={}, + const EffectHandlerMap preFxHandlers_={}): + name(sysName), + nameJ(sysNameJ), + description(desc), + id(fileID), + id_DMF(fileID_DMF), + channels(chans), + minChans(minCh), + maxChans(maxCh), + isFM(isFMChip), + isSTD(isSTDChip), + isCompound(compound), + waveWidth(waveWid), + waveHeight(waveHei), + vgmVersion(vgmVer), + sampleFormatMask(formatMask), + getChanDef(gcdFunc), + effectHandlers(fxHandlers_), + postEffectHandlers(postFxHandlers_), + preEffectHandlers(preFxHandlers_) { + } +}; + +enum DivSystem { + DIV_SYSTEM_NULL=0, + DIV_SYSTEM_YMU759, + DIV_SYSTEM_GENESIS, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_GENESIS_EXT, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_SMS, + DIV_SYSTEM_SMS_OPLL, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_GB, + DIV_SYSTEM_PCE, + DIV_SYSTEM_NES, + DIV_SYSTEM_NES_VRC7, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_NES_FDS, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_C64_6581, + DIV_SYSTEM_C64_8580, + DIV_SYSTEM_ARCADE, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_MSX2, // ** COMPOUND SYSTEM - DO NOT USE! ** + DIV_SYSTEM_YM2610, + DIV_SYSTEM_YM2610_EXT, + + DIV_SYSTEM_AY8910, + DIV_SYSTEM_AMIGA, + DIV_SYSTEM_YM2151, + DIV_SYSTEM_YM2612, + DIV_SYSTEM_TIA, + DIV_SYSTEM_SAA1099, + DIV_SYSTEM_AY8930, + DIV_SYSTEM_VIC20, + DIV_SYSTEM_PET, + DIV_SYSTEM_SNES, + DIV_SYSTEM_VRC6, + DIV_SYSTEM_OPLL, + DIV_SYSTEM_FDS, + DIV_SYSTEM_MMC5, + DIV_SYSTEM_N163, + DIV_SYSTEM_YM2203, + DIV_SYSTEM_YM2203_EXT, + DIV_SYSTEM_YM2608, + DIV_SYSTEM_YM2608_EXT, + DIV_SYSTEM_OPL, + DIV_SYSTEM_OPL2, + DIV_SYSTEM_OPL3, + DIV_SYSTEM_MULTIPCM, + DIV_SYSTEM_PCSPKR, + DIV_SYSTEM_POKEY, + DIV_SYSTEM_RF5C68, + DIV_SYSTEM_SWAN, + DIV_SYSTEM_OPZ, + DIV_SYSTEM_POKEMINI, + DIV_SYSTEM_SEGAPCM, + DIV_SYSTEM_VBOY, + DIV_SYSTEM_VRC7, + DIV_SYSTEM_YM2610B, + DIV_SYSTEM_SFX_BEEPER, + DIV_SYSTEM_SFX_BEEPER_QUADTONE, + DIV_SYSTEM_YM2612_EXT, + DIV_SYSTEM_SCC, + DIV_SYSTEM_OPL_DRUMS, + DIV_SYSTEM_OPL2_DRUMS, + DIV_SYSTEM_OPL3_DRUMS, + DIV_SYSTEM_YM2610_FULL, + DIV_SYSTEM_YM2610_FULL_EXT, + DIV_SYSTEM_OPLL_DRUMS, + DIV_SYSTEM_LYNX, + DIV_SYSTEM_QSOUND, + DIV_SYSTEM_VERA, + DIV_SYSTEM_YM2610B_EXT, + DIV_SYSTEM_SEGAPCM_COMPAT, + DIV_SYSTEM_X1_010, + DIV_SYSTEM_BUBSYS_WSG, + DIV_SYSTEM_OPL4, + DIV_SYSTEM_OPL4_DRUMS, + DIV_SYSTEM_ES5506, + DIV_SYSTEM_Y8950, + DIV_SYSTEM_Y8950_DRUMS, + DIV_SYSTEM_SCC_PLUS, + DIV_SYSTEM_SOUND_UNIT, + DIV_SYSTEM_MSM6295, + DIV_SYSTEM_MSM6258, + DIV_SYSTEM_YMZ280B, + DIV_SYSTEM_NAMCO, + DIV_SYSTEM_NAMCO_15XX, + DIV_SYSTEM_NAMCO_CUS30, + DIV_SYSTEM_YM2612_DUALPCM, + DIV_SYSTEM_YM2612_DUALPCM_EXT, + DIV_SYSTEM_MSM5232, + DIV_SYSTEM_T6W28, + DIV_SYSTEM_K007232, + DIV_SYSTEM_GA20, + DIV_SYSTEM_PCM_DAC, + DIV_SYSTEM_PONG, + DIV_SYSTEM_DUMMY, + DIV_SYSTEM_YM2612_CSM, + DIV_SYSTEM_YM2610_CSM, + DIV_SYSTEM_YM2610B_CSM, + DIV_SYSTEM_YM2203_CSM, + DIV_SYSTEM_YM2608_CSM, + DIV_SYSTEM_SM8521, + DIV_SYSTEM_PV1000, + DIV_SYSTEM_K053260, + DIV_SYSTEM_TED, + DIV_SYSTEM_C140, + DIV_SYSTEM_C219, + DIV_SYSTEM_ESFM, + DIV_SYSTEM_POWERNOISE, + DIV_SYSTEM_DAVE, + DIV_SYSTEM_NDS, + DIV_SYSTEM_GBA_DMA, + DIV_SYSTEM_GBA_MINMOD, + DIV_SYSTEM_5E01, + DIV_SYSTEM_BIFURCATOR, + DIV_SYSTEM_SID2, + DIV_SYSTEM_SUPERVISION, + DIV_SYSTEM_UPD1771C, + DIV_SYSTEM_SID3, + DIV_SYSTEM_C64_PCM, + + DIV_SYSTEM_MAX +}; + +#endif diff --git a/src/gui/sysMiscInfo.cpp b/src/gui/sysMiscInfo.cpp index fb1f0d8a6..0810113bf 100644 --- a/src/gui/sysMiscInfo.cpp +++ b/src/gui/sysMiscInfo.cpp @@ -312,12 +312,14 @@ float FurnaceGUI::drawSystemChannelInfo(const DivSysDef* whichDef, int keyHitOff if (ledSize.x<8.0f*dpiScale) ledSize.x=8.0f*dpiScale; float x=p.x, y=p.y; for (int i=0; igetChanDef(i); + if (x+ledSize.x-0.125>tooltipWidth+p.x) { x=p.x; y+=ledSize.y+sep.y; } ImVec4 color=uiColors[GUI_COLOR_CHANNEL_BG]; - if (ichannels) color=uiColors[whichDef->chanTypes[i]+GUI_COLOR_CHANNEL_FM]; + if (ichannels) color=uiColors[chanDef.type+GUI_COLOR_CHANNEL_FM]; if (keyHitOffset>=0) { if (e->isChannelMuted(keyHitOffset+i)) { color=uiColors[GUI_COLOR_CHANNEL_MUTED]; @@ -345,7 +347,8 @@ void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) { memset(chanCount,0,CHANNEL_TYPE_MAX); // count channel types for (int i=0; ichannels; i++) { - switch (whichDef->chanInsType[i][0]) { + DivChanDef chanDef=whichDef->getChanDef(i); + switch (chanDef.insType[0]) { case DIV_INS_STD: // square case DIV_INS_BEEPER: case DIV_INS_TED: @@ -360,17 +363,17 @@ void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) { chanCount[CHANNEL_TYPE_PULSE]++; break; } - if (whichDef->chanTypes[i]==DIV_CH_NOISE) { // sn/t6w noise + if (chanDef.type==DIV_CH_NOISE) { // sn/t6w noise chanCount[CHANNEL_TYPE_NOISE]++; } else { // DIV_CH_PULSE, any sqr chan chanCount[CHANNEL_TYPE_SQUARE]++; } break; case DIV_INS_NES: - if (whichDef->chanTypes[i]==DIV_CH_WAVE) { + if (chanDef.type==DIV_CH_WAVE) { chanCount[whichDef->id==0xf1?CHANNEL_TYPE_WAVE:CHANNEL_TYPE_TRIANGLE]++; // triangle, wave for 5E01 } else { - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; } break; case DIV_INS_AY: @@ -380,23 +383,23 @@ void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) { case DIV_INS_OPL_DRUMS: case DIV_INS_OPL: case DIV_INS_OPLL: - if (whichDef->chanTypes[i]==DIV_CH_OP) { + if (chanDef.type==DIV_CH_OP) { chanCount[CHANNEL_TYPE_FM]++; // opl3 4op break; } - if (whichDef->chanTypes[i]==DIV_CH_NOISE) { + if (chanDef.type==DIV_CH_NOISE) { chanCount[CHANNEL_TYPE_DRUMS]++; // drums } else { - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; } break; case DIV_INS_FM: - if (whichDef->chanTypes[i]==DIV_CH_OP) { + if (chanDef.type==DIV_CH_OP) { chanCount[CHANNEL_TYPE_OPERATOR]++; // ext. ops - } else if (whichDef->chanTypes[i]==DIV_CH_NOISE) { + } else if (chanDef.type==DIV_CH_NOISE) { break; // csm timer } else { - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; } break; case DIV_INS_ADPCMA: @@ -413,33 +416,33 @@ void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) { chanCount[CHANNEL_TYPE_SAMPLE]++; break; case DIV_INS_NDS: - if (whichDef->chanTypes[i]!=DIV_CH_PCM) { // the psg chans can also play samples?? + if (chanDef.type!=DIV_CH_PCM) { // the psg chans can also play samples?? chanCount[CHANNEL_TYPE_SAMPLE]++; } - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; break; case DIV_INS_VERA: - if (whichDef->chanTypes[i]==DIV_CH_PULSE) { + if (chanDef.type==DIV_CH_PULSE) { chanCount[CHANNEL_TYPE_WAVE]++; } else { // sample chan chanCount[CHANNEL_TYPE_SAMPLE]++; } break; case DIV_INS_DAVE: - if (whichDef->chanTypes[i]==DIV_CH_WAVE) { + if (chanDef.type==DIV_CH_WAVE) { chanCount[CHANNEL_TYPE_OTHER]++; } else { - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; } break; case DIV_INS_SWAN: - if (whichDef->chanTypes[i]!=DIV_CH_WAVE) { + if (chanDef.type!=DIV_CH_WAVE) { chanCount[CHANNEL_TYPE_WAVETABLE]++; } - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; break; case DIV_INS_SID3: - if (whichDef->chanTypes[i]!=DIV_CH_WAVE) { + if (chanDef.type!=DIV_CH_WAVE) { chanCount[CHANNEL_TYPE_OTHER]++; } else { chanCount[CHANNEL_TYPE_WAVE]++; @@ -456,7 +459,7 @@ void FurnaceGUI::drawSystemChannelInfoText(const DivSysDef* whichDef) { chanCount[CHANNEL_TYPE_OTHER]++; break; default: - chanCount[whichDef->chanTypes[i]]++; + chanCount[chanDef.type]++; break; } }