diff --git a/CMakeLists.txt b/CMakeLists.txt index b7bc35433..117265410 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -665,6 +665,8 @@ src/engine/platform/sound/sid2/wave8580_P_T.cc src/engine/platform/sound/sid2/wave8580__ST.cc src/engine/platform/sound/sid2/wave.cc +src/engine/platform/sound/sid3.c + src/engine/platform/oplAInterface.cpp src/engine/platform/ym2608Interface.cpp src/engine/platform/ym2610Interface.cpp @@ -783,6 +785,7 @@ src/engine/platform/gbaminmod.cpp src/engine/platform/nds.cpp src/engine/platform/bifurcator.cpp src/engine/platform/sid2.cpp +src/engine/platform/sid3.cpp src/engine/platform/pcmdac.cpp src/engine/platform/dummy.cpp diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 65ca2383d..f13258c86 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -90,6 +90,7 @@ #include "platform/nds.h" #include "platform/bifurcator.h" #include "platform/sid2.h" +#include "platform/sid3.h" #include "platform/dummy.h" #include "../ta-log.h" #include "song.h" @@ -760,6 +761,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do case DIV_SYSTEM_SID2: dispatch=new DivPlatformSID2; break; + case DIV_SYSTEM_SID3: + dispatch=new DivPlatformSID3; + break; case DIV_SYSTEM_DUMMY: dispatch=new DivPlatformDummy; break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 49b2991d4..c07667d8f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -94,6 +94,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_GBA_MINMOD=61, DIV_INS_BIFURCATOR=62, DIV_INS_SID2=63, // coincidence! + DIV_INS_SID3=64, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp new file mode 100644 index 000000000..455c18a58 --- /dev/null +++ b/src/engine/platform/sid3.cpp @@ -0,0 +1,414 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2024 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 "sid3.h" +#include "../engine.h" +#include "IconsFontAwesome4.h" +#include +#include "../../ta-log.h" + +#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } + +#define CHIP_FREQBASE 524288 + +const char* regCheatSheetSID3[]={ + "FreqL0", "00", + "FreqH0", "01", + "PWL0", "02", + "PWH0Vol", "03", + "Control0", "04", + "AtkDcy0", "05", + "StnRis0", "06", + "FreqL1", "07", + "FreqH1", "08", + "PWL1", "09", + "PWH1Vol", "0A", + "Control1", "0B", + "AtkDcy1", "0C", + "StnRis1", "0D", + "FreqL2", "0E", + "FreqH2", "0F", + "PWL2", "10", + "PWH2Vol", "11", + "Control2", "12", + "AtkDcy2", "13", + "StnRis2", "14", + + "FCL0Ctrl", "15", + "FCH0", "16", + "FilterRes0", "17", + + "FCL1Ctrl", "18", + "FCH1", "19", + "FilterRes1", "1A", + + "FCL2Ctrl", "1B", + "FCH2", "1C", + "FilterRes2", "1D", + + "NoiModeFrMSB01", "1E", + "WaveMixModeFrMSB2", "1F", + NULL +}; + +const char** DivPlatformSID3::getRegisterSheet() { + return regCheatSheetSID3; +} + +void DivPlatformSID3::acquire(short** buf, size_t len) +{ + for (size_t i=0; ioutput_l; + buf[1][i]=sid3->output_r; + + if (++writeOscBuf>=16) + { + writeOscBuf=0; + + for(int j = 0; j < SID3_NUM_CHANNELS; j++) + { + oscBuf[j]->data[oscBuf[j]->needle++] = sid3->channel_output[j] / 4; + } + } + } +} + +void DivPlatformSID3::updateFilter(int channel) +{ + rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7)); + rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4)); + rWrite(0x17 + 3 * channel,chan[channel].filtRes); +} + +void DivPlatformSID3::tick(bool sysTick) { + for (int i=0; iSID3_NUM_CHANNELS - 1) return 0; + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SID3); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + chan[c.chan].test=false; + + if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) { + chan[c.chan].duty=ins->c64.duty; + rWrite(c.chan*7+2,chan[c.chan].duty&0xff); + rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].outVol << 4)); + } + if (chan[c.chan].insChanged) { + /*chan[c.chan].wave = (ins->c64.noiseOn << 3) | (ins->c64.pulseOn << 2) | (ins->c64.sawOn << 1) | (int)(ins->c64.triOn); + chan[c.chan].attack=ins->c64.a; + chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d; + chan[c.chan].sustain=ins->c64.s; + chan[c.chan].release=ins->c64.r; + chan[c.chan].ring=ins->c64.ringMod; + chan[c.chan].sync=ins->c64.oscSync; + + chan[c.chan].noise_mode = ins->sid3.noiseMode; + chan[c.chan].mix_mode = ins->sid3.mixMode;*/ + } + if (chan[c.chan].insChanged || chan[c.chan].resetFilter) { + chan[c.chan].filter=ins->c64.toFilter; + if (ins->c64.initFilter) { + chan[c.chan].filtCut=ins->c64.cut; + chan[c.chan].filtRes=ins->c64.res; + chan[c.chan].filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2); + } + updateFilter(c.chan); + } + if (chan[c.chan].insChanged) { + chan[c.chan].insChanged=false; + } + chan[c.chan].macroInit(ins); + break; + } + case DIV_CMD_NOTE_OFF: + chan[c.chan].active=false; + chan[c.chan].keyOff=true; + chan[c.chan].keyOn=false; + //chan[c.chan].macroInit(NULL); + break; + case DIV_CMD_NOTE_OFF_ENV: + chan[c.chan].active=false; + chan[c.chan].keyOff=true; + chan[c.chan].keyOn=false; + chan[c.chan].std.release(); + break; + case DIV_CMD_ENV_RELEASE: + chan[c.chan].std.release(); + break; + case DIV_CMD_INSTRUMENT: + if (chan[c.chan].ins!=c.value || c.value2==1) { + chan[c.chan].insChanged=true; + chan[c.chan].ins=c.value; + } + break; + case DIV_CMD_VOLUME: + if (chan[c.chan].vol!=c.value) { + chan[c.chan].vol=c.value; + if (!chan[c.chan].std.vol.has) { + chan[c.chan].outVol=c.value; + chan[c.chan].vol=chan[c.chan].outVol; + rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].vol << 4)); + } + } + break; + case DIV_CMD_GET_VOLUME: + if (chan[c.chan].std.vol.has) { + return chan[c.chan].vol; + } + return chan[c.chan].outVol; + break; + case DIV_CMD_PITCH: + chan[c.chan].pitch=c.value; + chan[c.chan].freqChanged=true; + break; + case DIV_CMD_NOTE_PORTA: { + int destFreq=NOTE_FREQUENCY(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } + case DIV_CMD_LEGATO: + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + break; + case DIV_CMD_PRE_PORTA: + if (chan[c.chan].active && c.value2) { + if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) { + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SID3)); + chan[c.chan].keyOn=true; + } + } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); + chan[c.chan].inPorta=c.value; + break; + case DIV_CMD_GET_VOLMAX: + return SID3_MAX_VOL; + break; + case DIV_CMD_MACRO_OFF: + chan[c.chan].std.mask(c.value,true); + break; + case DIV_CMD_MACRO_ON: + chan[c.chan].std.mask(c.value,false); + break; + case DIV_CMD_MACRO_RESTART: + chan[c.chan].std.restart(c.value); + break; + default: + break; + } + return 1; +} + +void DivPlatformSID3::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + sid3_set_is_muted(sid3,ch,mute); +} + +void DivPlatformSID3::forceIns() { + for (int i=0; i& wlist) { + for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); +} + +void DivPlatformSID3::setFlags(const DivConfig& flags) { + switch (flags.getInt("clockSel",0)) { + case 0x0: // NTSC C64 + chipClock=COLOR_NTSC*2.0/7.0; + break; + case 0x1: // PAL C64 + chipClock=COLOR_PAL*2.0/9.0; + break; + case 0x2: // SSI 2001 + default: + chipClock=14318180.0/16.0; + break; + } + CHECK_CUSTOM_CLOCK; + rate=chipClock; + for (int i=0; irate=rate/16; + } +} + +int DivPlatformSID3::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + writeOscBuf=0; + + for (int i=0; i { + int prevFreq; + unsigned char wave, attack, decay, sustain, release; + short duty; + bool filter; + bool resetMask, resetFilter, resetDuty, gate, ring, sync, test; + unsigned char vol; + unsigned char filtControl, filtRes; + unsigned char noise_mode; + unsigned char mix_mode; + int filtCut; + Channel(): + SharedChannel(SID3_MAX_VOL), + prevFreq(0x1ffff), + wave(0), + attack(0), + decay(0), + sustain(0), + release(0), + duty(0), + filter(false), + resetMask(false), + resetFilter(false), + resetDuty(false), + gate(true), + ring(false), + sync(false), + test(false), + vol(SID3_MAX_VOL), + filtControl(0), + filtRes(0), + noise_mode(0), + mix_mode(0), + filtCut(0) {} + }; + Channel chan[SID3_NUM_CHANNELS]; + DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS]; + struct QueuedWrite { + unsigned char addr; + unsigned char val; + QueuedWrite(): addr(0), val(0) {} + QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} + }; + FixedQueue writes; + + unsigned char writeOscBuf; + + SID3* sid3; + unsigned char regPool[SID3_NUM_REGISTERS]; + + bool isMuted[SID3_NUM_CHANNELS]; + + friend void putDispatchChip(void*,int); + friend void putDispatchChan(void*,int,int); + + void updateFilter(int channel); + public: + void acquire(short** buf, size_t len); + int dispatch(DivCommand c); + void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); + unsigned char* getRegisterPool(); + int getRegisterPoolSize(); + void reset(); + void forceIns(); + void tick(bool sysTick=true); + void muteChannel(int ch, bool mute); + void setFlags(const DivConfig& flags); + void notifyInsChange(int ins); + float getPostAmp(); + DivMacroInt* getChanMacroInt(int ch); + DivChannelModeHints getModeHints(int chan); + void notifyInsDeletion(void* ins); + void poke(unsigned int addr, unsigned short val); + void poke(std::vector& wlist); + const char** getRegisterSheet(); + int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + int getOutputCount(); + void quit(); + ~DivPlatformSID3(); +}; + +#endif diff --git a/src/engine/platform/sound/sid3.c b/src/engine/platform/sound/sid3.c new file mode 100644 index 000000000..4617c8cd5 --- /dev/null +++ b/src/engine/platform/sound/sid3.c @@ -0,0 +1,38 @@ +#include "sid3.h" + +#define SAFETY_HEADER if(sid3 == NULL) return; + +SID3* sid3_create() +{ + SID3* sid3 = (SID3*)malloc(sizeof(SID3)); + return sid3; +} + +void sid3_reset(SID3* sid3) +{ + SAFETY_HEADER + + memset(sid3, 0, sizeof(SID3)); +} + +void sid3_write(SID3* sid3, uint8_t address, uint8_t data) +{ + SAFETY_HEADER +} + +void sid3_clock(SID3* sid3) +{ + SAFETY_HEADER +} + +void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute) +{ + SAFETY_HEADER +} + +void sid3_free(SID3* sid3) +{ + SAFETY_HEADER + + free(sid3); +} \ No newline at end of file diff --git a/src/engine/platform/sound/sid3.h b/src/engine/platform/sound/sid3.h new file mode 100644 index 000000000..b81d44fa1 --- /dev/null +++ b/src/engine/platform/sound/sid3.h @@ -0,0 +1,86 @@ +#ifndef SID3_H +#define SID3_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define SID3_NUM_CHANNELS 7 +#define SID3_NUM_FILTERS 4 +#define SID3_NUM_REGISTERS 256 +#define SID3_MAX_VOL 255 + +#define SID3_WAVETABLE_LENGTH 512 + +typedef struct +{ + int input; + int output; + + // State of filter. + float Vhp; // highpass + float Vbp; // bandpass + float Vlp; // lowpass + + // Cutoff frequency, resonance. + float w0, w0_ceil_1; + float _1024_div_Q; +} sid3_filter; + +typedef struct +{ + sid3_filter filt[SID3_NUM_FILTERS]; + uint32_t connection_matrix; +} sid3_filters_block; + +typedef struct +{ + uint32_t accumulator; + uint32_t frequency; + + sid3_filters_block filt; + + uint8_t panning; +} sid3_channel; + +typedef struct +{ + uint32_t accumulator; + uint32_t frequency; + + uint16_t streamed_sample; + uint8_t wavetable[SID3_WAVETABLE_LENGTH]; + + sid3_filters_block filt; + + uint8_t panning; +} sid3_wavetable_chan; + +typedef struct +{ + sid3_channel chan[SID3_NUM_CHANNELS - 1]; + sid3_wavetable_chan wave_chan; + + int output_l, output_r; + + //emulation-only helpers + int channel_output[SID3_NUM_CHANNELS]; + bool muted[SID3_NUM_CHANNELS]; +} SID3; + +SID3* sid3_create(); +void sid3_reset(SID3* sid3); +void sid3_write(SID3* sid3, uint8_t address, uint8_t data); +void sid3_clock(SID3* sid3); +void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute); +void sid3_free(SID3* sid3); + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/src/engine/song.h b/src/engine/song.h index 8912ec4a1..b6ed13acd 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -141,6 +141,7 @@ enum DivSystem { DIV_SYSTEM_5E01, DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_SID2, + DIV_SYSTEM_SID3, }; enum DivEffectType: unsigned short { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 20e8461d5..dfc9528b7 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -690,6 +690,20 @@ void DivEngine::registerSystems() { for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x30+i,SID2FineDutyHandler); for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID2FineCutoffHandler); + EffectHandlerMap SID3PostEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)")}}, + {0x11, {DIV_CMD_C64_RESONANCE, _("11xx: Set resonance (0 to FF)")}}, + {0x12, {DIV_CMD_C64_FILTER_MODE, _("12xx: Set filter mode (bit 0: low pass; bit 1: band pass; bit 2: high pass)")}}, + {0x13, {DIV_CMD_C64_RESET_MASK, _("13xx: Disable envelope reset for this channel (1 disables; 0 enables)")}}, + {0x14, {DIV_CMD_C64_FILTER_RESET, _("14xy: Reset cutoff (x: on new note; y: now)")}}, + {0x15, {DIV_CMD_C64_DUTY_RESET, _("15xy: Reset pulse width (x: on new note; y: now)")}}, + {0x16, {DIV_CMD_C64_EXTENDED, _("16xy: Change other parameters")}}, + }; + const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("3xxx: Set pulse width (0 to FFF)"), effectValLong<12>); + const EffectHandler SID3FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, _("4xxx: Set cutoff (0 to FFF)"), effectValLong<11>); + for (int i=0; i<16; i++) SID3PostEffectHandlerMap.emplace(0x30+i,SID3FineDutyHandler); + for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID3FineCutoffHandler); + // SysDefs // this chip uses YMZ ADPCM, but the emulator uses ADPCM-B because I got it wrong back then. @@ -2144,6 +2158,18 @@ void DivEngine::registerSystems() { SID2PostEffectHandlerMap ); + sysDefs[DIV_SYSTEM_SID3]=new DivSysDef( + _("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, 0, 0, 0, + _("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too much features added on top."), + {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")}, + {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"}, + {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, + {DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3}, + {}, + {}, + SID3PostEffectHandlerMap + ); + sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef( _("Dummy System"), NULL, 0xfd, 0, 8, false, true, 0, false, 0, 0, 0, _("this is a system designed for testing purposes."), diff --git a/src/gui/about.cpp b/src/gui/about.cpp index fc9775368..52c98d469 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -294,6 +294,8 @@ const char* aboutLine[]={ _N("PowerNoise emulator by scratchminer"), _N("ep128emu by Istvan Varga"), _N("NDS sound emulator by cam900"), + _N("SID2 emulator by LTVA (modification of reSID emulator)"), + _N("SID3 emulator by LTVA"), "", _N("greetings to:"), "NEOART Costa Rica", diff --git a/src/gui/gui.h b/src/gui/gui.h index 515d77fc8..38e329d5a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -351,6 +351,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_GBA_MINMOD, GUI_COLOR_INSTR_BIFURCATOR, GUI_COLOR_INSTR_SID2, + GUI_COLOR_INSTR_SID3, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_BG, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 09d0fefbb..fea86adfd 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -184,6 +184,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={ {"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD}, {"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR}, {"SID2",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2}, + {"SID3",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID3}, {NULL,ICON_FA_QUESTION,ICON_FA_QUESTION} }; @@ -1015,6 +1016,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_GBA_MINMOD,"",ImVec4(0.5f,0.45f,0.7f,1.0f)), D(GUI_COLOR_INSTR_BIFURCATOR,"",ImVec4(0.8925f,0.8925f,0.8925f,1.0f)), D(GUI_COLOR_INSTR_SID2,"",ImVec4(0.6f,0.75f,1.0f,1.0f)), + D(GUI_COLOR_INSTR_SID3,"",ImVec4(0.6f,0.75f,0.6f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), @@ -1263,6 +1265,7 @@ const int availableSystems[]={ DIV_SYSTEM_5E01, DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_SID2, + DIV_SYSTEM_SID3, 0 // don't remove this last one! }; @@ -1358,6 +1361,7 @@ const int chipsSpecial[]={ DIV_SYSTEM_5E01, DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_SID2, + DIV_SYSTEM_SID3, 0 // don't remove this last one! }; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 87133ffc8..a9457e7d6 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -3085,6 +3085,11 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_SID2, 1.0f, 0, "") } ); + ENTRY( + "SID3", { + CH(DIV_SYSTEM_SID3, 1.0f, 0, "") + } + ); CATEGORY_END; CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index b6c244430..a84cff3e7 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -4113,6 +4113,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID2,_("SID2")); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID3,_("SID3")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,_("Other/Unknown")); ImGui::TreePop(); } diff --git a/src/icon/furIcons.h b/src/icon/furIcons.h index 9712f5582..0384354ce 100644 --- a/src/icon/furIcons.h +++ b/src/icon/furIcons.h @@ -75,6 +75,7 @@ #define ICON_FUR_INS_GBA_MINMOD u8"\ue15f" #define ICON_FUR_INS_BIFURCATOR u8"\ue160" #define ICON_FUR_INS_SID2 u8"\ue161" +#define ICON_FUR_INS_SID3 u8"\ue162" // sample editor #define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136" diff --git a/src/main.cpp b/src/main.cpp index 9c3dc6a9e..137ec29eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -333,6 +333,8 @@ TAParamResult pVersion(String) { printf("- PowerNoise emulator by scratchminer (MIT)\n"); printf("- ep128emu by Istvan Varga (GPLv2)\n"); printf("- NDS sound emulator by cam900 (zlib license)\n"); + printf("- SID2 emulator by LTVA (GPLv2, modification of reSID emulator)\n"); + printf("- SID3 emulator by LTVA (MIT)\n"); return TA_PARAM_QUIT; }