diff --git a/CMakeLists.txt b/CMakeLists.txt index a5e91fb00..8fb2aa919 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -455,6 +455,8 @@ src/engine/platform/sound/c64_fp/WaveformCalculator.cpp src/engine/platform/sound/c64_fp/WaveformGenerator.cpp src/engine/platform/sound/c64_fp/resample/SincResampler.cpp +src/engine/platform/sound/c64_d/dsid.c + src/engine/platform/sound/tia/AudioChannel.cpp src/engine/platform/sound/tia/Audio.cpp @@ -860,7 +862,7 @@ endif() string(REPLACE ";" " " WARNING_FLAGS_STRING "${WARNING_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_STRING}") if (WARNINGS_ARE_ERRORS) - message(WARNING + message(STATUS "Treating all warnings in furnace's C++ code as errors! " "Please report any errors you encounter on the bug tracker." ) diff --git a/doc/7-systems/vera.md b/doc/7-systems/vera.md index 8f50e0e74..e89744a9d 100644 --- a/doc/7-systems/vera.md +++ b/doc/7-systems/vera.md @@ -13,3 +13,5 @@ currently Furnace does not support the PCM channel's stereo mode, though (except - `2`: triangle - `3`: noise - `22xx`: **set duty cycle.** range is `0` to `3F`. +- `EExx`: **ZSM synchronization event.** + - Where `xx` is the event payload. This has no effect in how the music is played in Furnace, but the ZSMKit library for the Commander X16 interprets these events inside ZSM files and optionally triggers a callback routine. This can be used, for instance, to cause game code to respond to beats or at certain points in the music. diff --git a/papers/zsm-format.md b/papers/zsm-format.md index 5957e3c69..e0fd2c02d 100644 --- a/papers/zsm-format.md +++ b/papers/zsm-format.md @@ -99,7 +99,7 @@ Any offset values contained in the PCM data header block are relative to the beg ### PCM Sample Data -This is blob of PCM data with no internal formatting. Offsets into this blob are provided via the PCM header. The end of this blob will be the end of the ZSM file. +This is a blob of PCM data with no internal formatting. Offsets into this blob are provided via the PCM header. The end of this blob will be the end of the ZSM file. ## EXTCMD Channel Scifications @@ -149,7 +149,7 @@ Players implementing this channel should implement detection routines during ini An expansion HW write will contain the following data: -Chip ID|Nuber of writes (`N`)| `N` tuples of data +Chip ID|Number of writes (`N`)| `N` tuples of data --|--|-- one byte|one byte|N * tuple_size bytes @@ -162,7 +162,14 @@ There are currently no supported expansion HW IDs assigned. The purpose of this channel is to provide for music synchronization cues that applications may use to perform operations in sync with the music (such as when the Goombas jump in New Super Mario Bros in time with the BOP! BOP! notes in the music). It is intended for the reference player to provide a sync channel callback, passing the data bytes to the callback function, and then to proceed with playback. -The data structure within this channel is not yet defined. It is our intention to work with the community in order to collaborate on a useful structure. +The synchronization format currently defines this one event type: + +Event Type|Description|Message Format +--|--|-- +`0x00`|Generic sync message|`xx` (any value from `0x00`-`0xff`) + +An example of an EXTCMD containing one sync event might look as follows: `0x40 0x82 0x00 0x05` + #### 3: Custom diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index c19e7d955..c458cf9c4 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -236,6 +236,8 @@ enum DivDispatchCmds { DIV_CMD_NES_LINEAR_LENGTH, + DIV_CMD_EXTERNAL, // (value) + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index c30d7f231..6a532548b 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -172,6 +172,7 @@ void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) if (bbIn[i]==NULL) continue; if (bb[i]==NULL) continue; for (size_t j=0; jsetFP(eng->getConfInt("c64Core",1)==1); + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); ((DivPlatformC64*)dispatch)->setChipModel(true); break; case DIV_SYSTEM_C64_8580: dispatch=new DivPlatformC64; - ((DivPlatformC64*)dispatch)->setFP(eng->getConfInt("c64Core",1)==1); + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); ((DivPlatformC64*)dispatch)->setChipModel(false); break; case DIV_SYSTEM_YM2151: diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 6d03ba2f4..b41a52d5e 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -65,34 +65,45 @@ const char** DivPlatformC64::getRegisterSheet() { } void DivPlatformC64::acquire(short** buf, size_t len) { - int dcOff=isFP?0:sid.get_dc(0); + int dcOff=(sidCore)?0:sid->get_dc(0); for (size_t i=0; iwrite(w.addr,w.val); } else { - sid.write(w.addr,w.val); - }; + sid->write(w.addr,w.val); + } regPool[w.addr&0x1f]=w.val; writes.pop(); } - if (isFP) { - sid_fp.clock(4,&buf[0][i]); + if (sidCore==2) { + double o=dSID_render(sid_d); + buf[0][i]=32767*CLAMP(o,-1.0,1.0); if (++writeOscBuf>=4) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=(sid_fp.lastChanOut[0]-dcOff)>>5; - oscBuf[1]->data[oscBuf[1]->needle++]=(sid_fp.lastChanOut[1]-dcOff)>>5; - oscBuf[2]->data[oscBuf[2]->needle++]=(sid_fp.lastChanOut[2]-dcOff)>>5; + oscBuf[0]->data[oscBuf[0]->needle++]=sid_d->lastOut[0]; + oscBuf[1]->data[oscBuf[1]->needle++]=sid_d->lastOut[1]; + oscBuf[2]->data[oscBuf[2]->needle++]=sid_d->lastOut[2]; + } + } else if (sidCore==1) { + sid_fp->clock(4,&buf[0][i]); + if (++writeOscBuf>=4) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=(sid_fp->lastChanOut[0]-dcOff)>>5; + oscBuf[1]->data[oscBuf[1]->needle++]=(sid_fp->lastChanOut[1]-dcOff)>>5; + oscBuf[2]->data[oscBuf[2]->needle++]=(sid_fp->lastChanOut[2]-dcOff)>>5; } } else { - sid.clock(); - buf[0][i]=sid.output(); + sid->clock(); + buf[0][i]=sid->output(); if (++writeOscBuf>=16) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=(sid.last_chan_out[0]-dcOff)>>5; - oscBuf[1]->data[oscBuf[1]->needle++]=(sid.last_chan_out[1]-dcOff)>>5; - oscBuf[2]->data[oscBuf[2]->needle++]=(sid.last_chan_out[2]-dcOff)>>5; + oscBuf[0]->data[oscBuf[0]->needle++]=(sid->last_chan_out[0]-dcOff)>>5; + oscBuf[1]->data[oscBuf[1]->needle++]=(sid->last_chan_out[1]-dcOff)>>5; + oscBuf[2]->data[oscBuf[2]->needle++]=(sid->last_chan_out[2]-dcOff)>>5; } } } @@ -366,7 +377,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_C64_CUTOFF: if (c.value>100) c.value=100; - filtCut=c.value*2047/100; + filtCut=(c.value+2)*2047/102; updateFilter(); break; case DIV_CMD_C64_FINE_CUTOFF: @@ -452,10 +463,17 @@ int DivPlatformC64::dispatch(DivCommand c) { void DivPlatformC64::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (isFP) { - sid_fp.mute(ch,mute); + if (sidCore==2) { + dSID_setMuteMask( + sid_d, + (isMuted[0]?0:1)| + (isMuted[1]?0:2)| + (isMuted[2]?0:4) + ); + } else if (sidCore==1) { + sid_fp->mute(ch,mute); } else { - sid.set_is_muted(ch,mute); + sid->set_is_muted(ch,mute); } } @@ -514,7 +532,7 @@ bool DivPlatformC64::getWantPreNote() { } float DivPlatformC64::getPostAmp() { - return isFP?3.0f:1.0f; + return (sidCore==1)?3.0f:1.0f; } void DivPlatformC64::reset() { @@ -524,11 +542,20 @@ void DivPlatformC64::reset() { chan[i].std.setEngine(parent); } - if (isFP) { - sid_fp.reset(); - sid_fp.clockSilent(16000); + if (sidCore==2) { + dSID_init(sid_d,chipClock,rate,sidIs6581?6581:8580,needInitTables); + dSID_setMuteMask( + sid_d, + (isMuted[0]?0:1)| + (isMuted[1]?0:2)| + (isMuted[2]?0:4) + ); + needInitTables=false; + } else if (sidCore==1) { + sid_fp->reset(); + sid_fp->clockSilent(16000); } else { - sid.reset(); + sid->reset(); } memset(regPool,0,32); @@ -554,23 +581,11 @@ void DivPlatformC64::poke(std::vector& wlist) { } void DivPlatformC64::setChipModel(bool is6581) { - if (is6581) { - if (isFP) { - sid_fp.setChipModel(reSIDfp::MOS6581); - } else { - sid.set_chip_model(MOS6581); - } - } else { - if (isFP) { - sid_fp.setChipModel(reSIDfp::MOS8580); - } else { - sid.set_chip_model(MOS8580); - } - } + sidIs6581=is6581; } -void DivPlatformC64::setFP(bool fp) { - isFP=fp; +void DivPlatformC64::setCore(unsigned char which) { + sidCore=which; } void DivPlatformC64::setFlags(const DivConfig& flags) { @@ -591,9 +606,9 @@ void DivPlatformC64::setFlags(const DivConfig& flags) { for (int i=0; i<3; i++) { oscBuf[i]->rate=rate/16; } - if (isFP) { + if (sidCore>0) { rate/=4; - sid_fp.setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0); + if (sidCore==1) sid_fp->setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0); } keyPriority=flags.getBool("keyPriority",true); testAD=((flags.getInt("testAttack",0)&15)<<4)|(flags.getInt("testDecay",0)&15); @@ -604,11 +619,45 @@ int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, const DivConfi parent=p; dumpWrites=false; skipRegisterWrites=false; + needInitTables=true; writeOscBuf=0; for (int i=0; i<3; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } + + if (sidCore==2) { + sid=NULL; + sid_fp=NULL; + sid_d=new struct SID_chip; + } else if (sidCore==1) { + sid=NULL; + sid_fp=new reSIDfp::SID; + sid_d=NULL; + } else { + sid=new SID; + sid_fp=NULL; + sid_d=NULL; + } + + if (sidIs6581) { + if (sidCore==2) { + // do nothing + } else if (sidCore==1) { + sid_fp->setChipModel(reSIDfp::MOS6581); + } else { + sid->set_chip_model(MOS6581); + } + } else { + if (sidCore==2) { + // do nothing + } else if (sidCore==1) { + sid_fp->setChipModel(reSIDfp::MOS8580); + } else { + sid->set_chip_model(MOS8580); + } + } + setFlags(flags); reset(); @@ -620,6 +669,9 @@ void DivPlatformC64::quit() { for (int i=0; i<3; i++) { delete oscBuf[i]; } + if (sid!=NULL) delete sid; + if (sid_fp!=NULL) delete sid_fp; + if (sid_d!=NULL) delete sid_d; } DivPlatformC64::~DivPlatformC64() { diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index b9b30b6ec..26b39c804 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -24,6 +24,7 @@ #include #include "sound/c64/sid.h" #include "sound/c64_fp/SID.h" +#include "sound/c64_d/dsid.h" class DivPlatformC64: public DivDispatch { struct Channel: public SharedChannel { @@ -64,15 +65,16 @@ class DivPlatformC64: public DivDispatch { unsigned char filtControl, filtRes, vol; unsigned char writeOscBuf; + unsigned char sidCore; int filtCut, resetTime; - bool isFP; - bool keyPriority; + bool keyPriority, sidIs6581, needInitTables; unsigned char chanOrder[3]; unsigned char testAD, testSR; - SID sid; - reSIDfp::SID sid_fp; + SID* sid; + reSIDfp::SID* sid_fp; + struct SID_chip* sid_d; unsigned char regPool[32]; friend void putDispatchChip(void*,int); @@ -105,7 +107,7 @@ class DivPlatformC64: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void setChipModel(bool is6581); - void setFP(bool fp); + void setCore(unsigned char which); void quit(); ~DivPlatformC64(); }; diff --git a/src/engine/platform/sound/c64_d/LICENSE b/src/engine/platform/sound/c64_d/LICENSE new file mode 100644 index 000000000..2127f8a3b --- /dev/null +++ b/src/engine/platform/sound/c64_d/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 DefleMask Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/engine/platform/sound/c64_d/README.md b/src/engine/platform/sound/c64_d/README.md new file mode 100644 index 000000000..63b7fa533 --- /dev/null +++ b/src/engine/platform/sound/c64_d/README.md @@ -0,0 +1,11 @@ +dSID +=== + +This is the SID core used in DefleMask. + +The project started as a very careful port from jsSID, comparing the wave +output from both, ensuring they were exactly the same. + +## License + +MIT License diff --git a/src/engine/platform/sound/c64_d/dsid.c b/src/engine/platform/sound/c64_d/dsid.c new file mode 100644 index 000000000..d01dc7ad7 --- /dev/null +++ b/src/engine/platform/sound/c64_d/dsid.c @@ -0,0 +1,367 @@ +#include "dsid.h" +#include +#include // INFINITY +#include +#include // memset, memcpy + +#define SID_OUT_SCALE (0x10000 * 3 * 16) + +// CONTROL +#define GAT 0x01 +#define SYN 0x02 +#define RNG 0x04 +#define TST 0x08 +#define TRI 0x10 +#define SAW 0x20 +#define PUL 0x40 +#define NOI 0x80 + +#define _HZ 0x10 +#define DECSUS 0x40 +#define ATK 0x80 + +// filter mode (high) +#define LP 0x10 +#define BP 0x20 +#define HP 0x40 +#define OFF3 0x80 + +#define waveforms_add_sample(_id,_s) \ + sid->lastOut[_id]=(_s); + +const int Aexp[256] = { + 1, 30, 30, 30, 30, 30, 30, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + +double cmbWF(int chn, int *wfa, int index, int differ6581, struct SID_globals *g) { + if (differ6581 && g->model == 6581) + index &= 0x7FF; + + return wfa[index]; +} + +void cCmbWF(int *wfa, double bitmul, double bstr, double trh) { + for (int i = 0; i < 4096; i++) { + wfa[i] = 0; + for (int j = 0; j < 12; j++) { + double blvl = 0; + for (int k = 0; k < 12; k++) { + blvl += (bitmul / pow(bstr, abs(k - j))) * (((i >> k) & 1) - 0.5); + } + wfa[i] += (blvl >= trh) ? pow(2, j) : 0; + } + wfa[i] *= 12; + } +} + +void dSID_init(struct SID_chip* sid, double clockRate, double samplingRate, int model, unsigned char init_wf) { + if (model == 6581) { + sid->g.model = 6581; + } else { + sid->g.model = 8580; + } + + memset(sid->M,0,MemLen); + memset(sid->SIDct, 0, sizeof(sid->SIDct)); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + sid->SIDct[i].ch[j].Ast = _HZ; + sid->SIDct[i].ch[j].nLFSR = 0x7FFFF8; + sid->SIDct[i].ch[j].prevwfout = 0; + } + sid->SIDct[i].ch[0].FSW = 1; + sid->SIDct[i].ch[1].FSW = 2; + sid->SIDct[i].ch[2].FSW = 4; + } + + sid->g.ctfr = -2.0 * 3.14 * (12500.0 / 256.0) / samplingRate, + sid->g.ctf_ratio_6581 = -2.0 * 3.14 * (samplingRate / 44100.0) * (20000.0 / 256.0) / samplingRate; + sid->g.ckr = clockRate / samplingRate; + + const double bAprd[16] = {9, 32 * 1, 63 * 1, 95 * 1, 149 * 1, 220 * 1, + 267 * 1, 313 * 1, 392 * 1, 977 * 1, 1954 * 1, 3126 * 1, + 3907 * 1, 11720 * 1, 19532 * 1, 31251 * 1}; + const int bAstp[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + memcpy(&sid->g.Aprd, &bAprd, sizeof(bAprd)); + memcpy(&sid->g.Astp, &bAstp, sizeof(bAstp)); + if (init_wf) { + cCmbWF(sid->g.trsaw, 0.8, 2.4, 0.64); + cCmbWF(sid->g.pusaw, 1.4, 1.9, 0.68); + cCmbWF(sid->g.Pulsetrsaw, 0.8, 2.5, 0.64); + + for (int i = 0; i < 2048; i++) { + double ctf = (double) i / 8.0 + 0.2; + if (model == 8580) { + ctf = 1 - exp(ctf * sid->g.ctfr); + } else { + if (ctf < 24) { + ctf = 2.0 * sin(771.78 / samplingRate); + } else { + ctf = (44100.0 / samplingRate) - 1.263 * (44100.0 / samplingRate) * exp(ctf * sid->g.ctf_ratio_6581); + } + } + sid->g.ctf_table[i] = ctf; + } + } + + double prd0 = sid->g.ckr > 9 ? sid->g.ckr : 9; + sid->g.Aprd[0] = prd0; + sid->g.Astp[0] = ceil(prd0 / 9); +} + +double dSID_render(struct SID_chip* sid) { + double flin = 0, output = 0; + double wfout = 0; + for (int chn = 0; chn < 3; chn++) { + struct SIDVOICE *voic = &((struct SIDMEM *) (sid->M))->v[chn]; + double pgt = (sid->SIDct->ch[chn].Ast & GAT); + uint8_t ctrl = voic->control; + uint8_t wf = ctrl & 0xF0; + uint8_t test = ctrl & TST; + uint8_t SR = voic->susres; + double tmp = 0; + if (pgt != (ctrl & GAT)) { + if (pgt) { + sid->SIDct->ch[chn].Ast &= 0xFF - (GAT | ATK | DECSUS); + } else { + sid->SIDct->ch[chn].Ast = (GAT | ATK | DECSUS); + if ((SR & 0xF) > (sid->SIDct->ch[chn].pSR & 0xF)) + tmp = 1; + } + } + sid->SIDct->ch[chn].pSR = SR; + sid->SIDct->ch[chn].rcnt += sid->g.ckr; + if (sid->SIDct->ch[chn].rcnt >= 0x8000) + sid->SIDct->ch[chn].rcnt -= 0x8000; + + static double step; + double prd; + + if (sid->SIDct->ch[chn].Ast & ATK) { + step = voic->attack; + prd = sid->g.Aprd[(int) step]; + } else if (sid->SIDct->ch[chn].Ast & DECSUS) { + step = voic->decay; + prd = sid->g.Aprd[(int) step]; + } else { + step = SR & 0xF; + prd = sid->g.Aprd[(int) step]; + } + step = sid->g.Astp[(int) step]; + if (sid->SIDct->ch[chn].rcnt >= prd && sid->SIDct->ch[chn].rcnt < prd + sid->g.ckr && + tmp == 0) { + sid->SIDct->ch[chn].rcnt -= prd; + if ((sid->SIDct->ch[chn].Ast & ATK) || + ++sid->SIDct->ch[chn].expcnt == Aexp[(int) sid->SIDct->ch[chn].envcnt]) { + if (!(sid->SIDct->ch[chn].Ast & _HZ)) { + if (sid->SIDct->ch[chn].Ast & ATK) { + sid->SIDct->ch[chn].envcnt += step; + if (sid->SIDct->ch[chn].envcnt >= 0xFF) { + sid->SIDct->ch[chn].envcnt = 0xFF; + sid->SIDct->ch[chn].Ast &= 0xFF - ATK; + } + } else if (!(sid->SIDct->ch[chn].Ast & DECSUS) || + sid->SIDct->ch[chn].envcnt > (SR >> 4) + (SR & 0xF0)) { + sid->SIDct->ch[chn].envcnt -= step; + if (sid->SIDct->ch[chn].envcnt <= 0 && + sid->SIDct->ch[chn].envcnt + step != 0) { + sid->SIDct->ch[chn].envcnt = 0; + sid->SIDct->ch[chn].Ast |= _HZ; + } + } + } + sid->SIDct->ch[chn].expcnt = 0; + } else { + } + } + sid->SIDct->ch[chn].envcnt = (int) sid->SIDct->ch[chn].envcnt & 0xFF; + double aAdd = (voic->freq_low + voic->freq_high * 256) * sid->g.ckr; + if (test || ((ctrl & SYN) && sid->SIDct->sMSBrise)) { + sid->SIDct->ch[chn].pacc = 0; + } else { + sid->SIDct->ch[chn].pacc += aAdd; + if (sid->SIDct->ch[chn].pacc > 0xFFFFFF) + sid->SIDct->ch[chn].pacc -= 0x1000000; + } + double MSB = (int) sid->SIDct->ch[chn].pacc & 0x800000; + sid->SIDct->sMSBrise = (MSB > ((int) sid->SIDct->ch[chn].pracc & 0x800000)) ? 1 : 0; + + if (wf & NOI) { + tmp = sid->SIDct->ch[chn].nLFSR; + if ((((int) sid->SIDct->ch[chn].pacc & 0x100000) != + ((int) sid->SIDct->ch[chn].pracc & 0x100000)) || + aAdd >= 0x100000) { + step = ((int) tmp & 0x400000) ^ (((int) tmp & 0x20000) << 5); + tmp = (((int) tmp << 1) + (step > 0 || test)) & 0x7FFFFF; + sid->SIDct->ch[chn].nLFSR = tmp; + } + wfout = (wf & 0x70) ? 0 + : (((int) tmp & 0x100000) >> 5) + (((int) tmp & 0x40000) >> 4) + + (((int) tmp & 0x4000) >> 1) + (((int) tmp & 0x800) << 1) + + (((int) tmp & 0x200) << 2) + (((int) tmp & 0x20) << 5) + + (((int) tmp & 0x04) << 7) + (((int) tmp & 0x01) << 8); + } else if (wf & PUL) { + double pw = (voic->pw_low + (voic->pw_high) * 256) * 16; + tmp = (int) aAdd >> 9; + if (0 < pw && pw < tmp) + pw = tmp; + tmp = (int) tmp ^ 0xFFFF; + if (pw > tmp) + pw = tmp; + tmp = (int) sid->SIDct->ch[chn].pacc >> 8; + if (wf == PUL) { + int lel = ((int) aAdd >> 16); + if (lel > 0) { + step = 256.0 / (double) lel; + } else { + step = INFINITY; + } + if (test) + wfout = 0xFFFF; + else if (tmp < pw) { + double lim = (0xFFFF - pw) * step; + if (lim > 0xFFFF) + lim = 0xFFFF; + wfout = lim - (pw - tmp) * step; + if (wfout < 0) + wfout = 0; + } else { + double lim = pw * step; + if (lim > 0xFFFF) + lim = 0xFFFF; + wfout = (0xFFFF - tmp) * step - lim; + if (wfout >= 0) + wfout = 0xFFFF; + wfout = (int) wfout & 0xFFFF; + } + } else { + wfout = (tmp >= pw || test) ? 0xFFFF : 0; + if (wf & TRI) { + if (wf & SAW) { + wfout = + (wfout) ? cmbWF(chn, sid->g.Pulsetrsaw, (int) tmp >> 4, 1, &sid->g) : 0; + } else { + tmp = (int) sid->SIDct->ch[chn].pacc ^ (ctrl & RNG ? sid->SIDct->sMSB : 0); + wfout = + (wfout) + ? cmbWF(chn, sid->g.pusaw, + ((int) tmp ^ ((int) tmp & 0x800000 ? 0xFFFFFF : 0)) >> 11, + 0, &sid->g) + : 0; + } + } else if (wf & SAW) + wfout = (wfout) ? cmbWF(chn, sid->g.pusaw, (int) tmp >> 4, 1, &sid->g) : 0; + } + } else if (wf & SAW) { + wfout = (int) sid->SIDct->ch[chn].pacc >> 8; + if (wf & TRI) + wfout = cmbWF(chn, sid->g.trsaw, (int) wfout >> 4, 1, &sid->g); + else { + step = aAdd / 0x1200000; + wfout += wfout * step; + if (wfout > 0xFFFF) + wfout = 0xFFFF - (wfout - 0x10000) / step; + } + } else if (wf & TRI) { + tmp = (int) sid->SIDct->ch[chn].pacc ^ (ctrl & RNG ? sid->SIDct->sMSB : 0); + wfout = ((int) tmp ^ ((int) tmp & 0x800000 ? 0xFFFFFF : 0)) >> 7; + } + if (wf) + sid->SIDct->ch[chn].prevwfout = wfout; + else { + wfout = sid->SIDct->ch[chn].prevwfout; + } + sid->SIDct->ch[chn].pracc = sid->SIDct->ch[chn].pacc; + sid->SIDct->sMSB = MSB; + // double preflin = flin; + if ((sid->mute_mask & (1 << chn))) { + if (sid->M[0x17] & sid->SIDct->ch[chn].FSW) { + double chnout = (wfout - 0x8000) * (sid->SIDct->ch[chn].envcnt / 256); + flin += chnout; + + // fake filter for solo waveform ahead + // mostly copypasted from below + double fakeflin = chnout; + double fakeflout = 0; + static double fakeplp[3] = {0}; + static double fakepbp[3] = {0}; + double ctf = sid->g.ctf_table[((sid->M[0x15]&7)|(sid->M[0x16]<<3))&0x7ff]; + double reso; + if (sid->g.model == 8580) { + reso = pow(2, ((double) (4 - (double) (sid->M[0x17] >> 4)) / 8)); + } else { + reso = (sid->M[0x17] > 0x5F) ? 8.0 / (double) (sid->M[0x17] >> 4) : 1.41; + } + double tmp = fakeflin + fakepbp[chn] * reso + fakeplp[chn]; + if (sid->M[0x18] & HP) + fakeflout -= tmp; + tmp = fakepbp[chn] - tmp * ctf; + fakepbp[chn] = tmp; + if (sid->M[0x18] & BP) + fakeflout -= tmp; + tmp = fakeplp[chn] + tmp * ctf; + fakeplp[chn] = tmp; + if (sid->M[0x18] & LP) + fakeflout += tmp; + + double wf_out = (fakeflout / SID_OUT_SCALE) * (sid->M[0x18] & 0xF) * 65535; + waveforms_add_sample(chn, wf_out); + } else if ((chn % 3) != 2 || !(sid->M[0x18] & OFF3)) { + double chnout = (wfout - 0x8000) * (sid->SIDct->ch[chn].envcnt / 256); + output += chnout; + + double wf_out = (chnout / SID_OUT_SCALE) * (sid->M[0x18] & 0xF) * 65535; + waveforms_add_sample(chn, wf_out); + } + } else { + waveforms_add_sample(chn, 0); + } + } + int M1 = 0; + if (M1 & 3) + sid->M[0x1B] = (int) wfout >> 8; + sid->M[0x1C] = sid->SIDct->ch[2].envcnt; + + double ctf = sid->g.ctf_table[((sid->M[0x15]&7)|(sid->M[0x16]<<3))&0x7ff]; + double reso; + if (sid->g.model == 8580) { + reso = pow(2, ((double) (4 - (double) (sid->M[0x17] >> 4)) / 8)); + } else { + reso = (sid->M[0x17] > 0x5F) ? 8.0 / (double) (sid->M[0x17] >> 4) : 1.41; + } + + double tmp = flin + sid->SIDct->pbp * reso + sid->SIDct->plp; + if (sid->M[0x18] & HP) + output -= tmp; + tmp = sid->SIDct->pbp - tmp * ctf; + sid->SIDct->pbp = tmp; + if (sid->M[0x18] & BP) + output -= tmp; + tmp = sid->SIDct->plp + tmp * ctf; + sid->SIDct->plp = tmp; + if (sid->M[0x18] & LP) + output += tmp; + return (output / SID_OUT_SCALE) * (sid->M[0x18] & 0xF); +} + +void dSID_setMuteMask(struct SID_chip* sid, int mute_mask) { + sid->mute_mask = mute_mask; +} + +float dSID_getVolume(struct SID_chip* sid, int channel) { + if ((sid->M[0x18] & 0xF) == 0) + return 0; + return sid->SIDct[0].ch[channel].envcnt / 256.0f; +} + +void dSID_write(struct SID_chip* sid, unsigned char addr, unsigned char val) { + sid->M[addr&0x1f]=val; +} diff --git a/src/engine/platform/sound/c64_d/dsid.h b/src/engine/platform/sound/c64_d/dsid.h new file mode 100644 index 000000000..b02d1870e --- /dev/null +++ b/src/engine/platform/sound/c64_d/dsid.h @@ -0,0 +1,97 @@ +#ifndef DSID_H +#define DSID_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct SID_ctx_chan { + double rcnt; + double envcnt; + double expcnt; + double pacc; + double pracc; + int FSW; + int nLFSR; + double prevwfout; + uint8_t pSR; + int Ast; +}; + +struct SID_ctx { + int sMSBrise; + int sMSB; + double plp; + double pbp; + struct SID_ctx_chan ch[3]; +}; + +struct SIDVOICE { + uint8_t freq_low; + uint8_t freq_high; + uint8_t pw_low; + uint8_t pw_high : 4; + uint8_t UNUSED : 4; + uint8_t control; + uint8_t decay : 4; + uint8_t attack : 4; + uint8_t susres; + // uint8_t release : 4; + // uint8_t sustain : 4; +}; + +struct SIDMEM { + struct SIDVOICE v[3]; + uint8_t UNUSED : 4; + uint8_t cutoff_low : 4; + uint8_t cutoff_high; + uint8_t reso_rt : 4; + uint8_t reso : 4; + uint8_t volume : 4; + uint8_t filter_mode : 4; + uint8_t paddlex; + uint8_t paddley; + uint8_t osc3; + uint8_t env3; +}; + +struct SID_globals { + double ckr; + double ctfr; + double ctf_ratio_6581; + + double ctf_table[2048]; + + int trsaw[4096]; + int pusaw[4096]; + int Pulsetrsaw[4096]; + + double Aprd[16]; + int Astp[16]; + int model; +}; + +#define MemLen 65536 + +struct SID_chip { + struct SID_globals g; + struct SID_ctx SIDct[3]; + uint8_t M[MemLen]; + int16_t lastOut[3]; + int mute_mask; +}; + +double dSID_render(struct SID_chip* sid); +void dSID_init(struct SID_chip* sid, double clockRate, double samplingRate, int model, unsigned char init_wf); +float dSID_getVolume(struct SID_chip* sid, int channel); +void dSID_setMuteMask(struct SID_chip* sid, int mute_mask); + +void dSID_write(struct SID_chip* sid, unsigned char addr, unsigned char val); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 3e3ac42c2..fe34b8bc4 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -37,6 +37,7 @@ extern "C" { #define rWritePCMRate(d) {regPool[65]=(d); pcm_write_rate(pcm,d);if (dumpWrites) addWrite(65,(d));} #define rWritePCMData(d) {regPool[66]=(d); pcm_write_fifo(pcm,d);} #define rWritePCMVol(d) rWritePCMCtrl((regPool[64]&(~0x8f))|((d)&15)) +#define rWriteZSMSync(d) {if (dumpWrites) addWrite(68,(d));} const char* regCheatSheetVERA[]={ "CHxFreq", "00+x*4", @@ -46,6 +47,7 @@ const char* regCheatSheetVERA[]={ "AUDIO_CTRL", "40", "AUDIO_RATE", "41", "AUDIO_DATA", "42", + "ZSM_SYNC", "44", NULL }; @@ -414,6 +416,9 @@ int DivPlatformVERA::dispatch(DivCommand c) { case DIV_CMD_MACRO_ON: chan[c.chan].std.mask(c.value,false); break; + case DIV_CMD_EXTERNAL: + rWriteZSMSync(c.value); + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 7476a316a..227512a73 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -51,7 +51,7 @@ class DivPlatformVERA: public DivDispatch { Channel chan[17]; DivDispatchOscBuffer* oscBuf[17]; bool isMuted[17]; - unsigned char regPool[67]; + unsigned char regPool[69]; struct VERA_PSG* psg; struct VERA_PCM* pcm; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ce94b883b..798de87b2 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -236,6 +236,8 @@ const char* cmdName[]={ "NES_LINEAR_LENGTH", + "EXTERNAL", + "ALWAYS_SET_VOLUME" }; @@ -913,6 +915,7 @@ void DivEngine::processRow(int i, bool afterDelay) { //printf("\x1b[1;36m%d: extern command %d\x1b[m\n",i,effectVal); extValue=effectVal; extValuePresent=true; + dispatchCmd(DivCommand(DIV_CMD_EXTERNAL,effectVal)); break; case 0xef: // global pitch globalPitch+=(signed char)(effectVal-0x80); @@ -1980,14 +1983,10 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else { // 3. run MIDI clock int midiTotal=MIN(cycles,runLeftG); - for (int i=0; i=67) { - logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); + if (a>=69) { + logD("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); return; + } else if (a==68) { + // Sync event + numWrites++; + return syncCache.push_back(v); } else if (a>=64) { return writePCM(a-64,v); } @@ -259,7 +263,7 @@ SafeWriter* DivZSM::finish() { } void DivZSM::flushWrites() { - logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d pcmMeta=%d pcmCache=%d pcmData=%d",numWrites,ticks,ymwrites.size(),pcmMeta.size(),pcmCache.size(),pcmData.size()); + logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d pcmMeta=%d pcmCache=%d pcmData=%d syncCache=%d",numWrites,ticks,ymwrites.size(),pcmMeta.size(),pcmCache.size(),pcmData.size(),syncCache.size()); if (numWrites==0) return; flushTicks(); // only flush ticks if there are writes pending. for (unsigned char i=0; i<64; i++) { @@ -287,43 +291,43 @@ void DivZSM::flushWrites() { unsigned int pcmInst=0; int pcmOff=0; int pcmLen=0; - int extCmdLen=pcmMeta.size()*2; + int extCmd0Len=pcmMeta.size()*2; if (pcmCache.size()) { // collapse stereo data to mono if both channels are fully identical // which cuts PCM data size in half for center-panned PCM events - if (pcmCtrlDCCache & 0x10) { // stereo bit is on + if (pcmCtrlDCCache&0x10) { // stereo bit is on unsigned int e; - if (pcmCtrlDCCache & 0x20) { // 16-bit + if (pcmCtrlDCCache&0x20) { // 16-bit // for 16-bit PCM data, the size must be a multiple of 4 if (pcmCache.size()%4==0) { // check for identical L+R channels - for (e=0;e>1;e+=2) { + for (e=0; e>1; e+=2) { pcmCache[e]=pcmCache[e<<1]; pcmCache[e+1]=pcmCache[(e<<1)+1]; } pcmCache.resize(pcmCache.size()>>1); - pcmCtrlDCCache &= ~0x10; // clear stereo bit + pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit } } } else { // 8-bit // for 8-bit PCM data, the size must be a multiple of 2 if (pcmCache.size()%2==0) { // check for identical L+R channels - for (e=0;e>1;e++) { + for (e=0; e>1; e++) { pcmCache[e]=pcmCache[e<<1]; } pcmCache.resize(pcmCache.size()>>1); - pcmCtrlDCCache &= ~0x10; // clear stereo bit + pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit } } } @@ -340,7 +344,7 @@ void DivZSM::flushWrites() { pcmData.insert(pcmData.end(),pcmCache.begin(),pcmCache.end()); } pcmCache.clear(); - extCmdLen+=2; + extCmd0Len+=2; // search for a matching PCM instrument definition for (S_pcmInst& inst: pcmInsts) { if (inst.offset==pcmOff && inst.length==pcmLen && inst.geometry==pcmCtrlDCCache) @@ -355,14 +359,14 @@ void DivZSM::flushWrites() { pcmInsts.push_back(inst); } } - if (extCmdLen>63) { // this would be bad, but will almost certainly never happen - logE("ZSM: extCmd exceeded maximum length of 63: %d",extCmdLen); - extCmdLen=0; + if (extCmd0Len>63) { // this would be bad, but will almost certainly never happen + logE("ZSM: extCmd 0 exceeded maximum length of 63: %d",extCmd0Len); + extCmd0Len=0; pcmMeta.clear(); } - if (extCmdLen) { // we have some PCM events to write - w->writeC(0x40); - w->writeC((unsigned char)extCmdLen); // the high two bits are guaranteed to be zero, meaning this is a PCM command + if (extCmd0Len) { // we have some PCM events to write + w->writeC(ZSM_EXT); + w->writeC(ZSM_EXT_PCM|(unsigned char)extCmd0Len); for (DivRegWrite& write: pcmMeta) { w->writeC(write.addr); w->writeC(write.val); @@ -373,6 +377,18 @@ void DivZSM::flushWrites() { w->writeC((unsigned char)pcmInst&0xff); } } + n=0; + while (n<(long)syncCache.size()) { // we have one or more sync events to write + int writes=syncCache.size()-n; + w->writeC(ZSM_EXT); + if (writes>ZSM_SYNC_MAX_WRITES) writes=ZSM_SYNC_MAX_WRITES; + w->writeC(ZSM_EXT_SYNC|(writes<<1)); + for (; writes>0; writes--) { + w->writeC(0x00); // 0x00 = Arbitrary sync message + w->writeC(syncCache[n++]); + } + } + syncCache.clear(); numWrites=0; } diff --git a/src/engine/zsm.h b/src/engine/zsm.h index 17a1fd063..42300cf70 100644 --- a/src/engine/zsm.h +++ b/src/engine/zsm.h @@ -30,9 +30,16 @@ #define ZSM_YM_CMD 0x40 #define ZSM_DELAY_CMD 0x80 #define ZSM_YM_MAX_WRITES 63 +#define ZSM_SYNC_MAX_WRITES 31 #define ZSM_DELAY_MAX 127 #define ZSM_EOF ZSM_DELAY_CMD +#define ZSM_EXT ZSM_YM_CMD +#define ZSM_EXT_PCM 0x00 +#define ZSM_EXT_CHIP 0x40 +#define ZSM_EXT_SYNC 0x80 +#define ZSM_EXT_CUSTOM 0xC0 + enum YM_STATE { ym_PREV, ym_NEW, ym_STATES }; enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; @@ -52,6 +59,7 @@ class DivZSM { std::vector pcmData; std::vector pcmCache; std::vector pcmInsts; + std::vector syncCache; int loopOffset; int numWrites; int ticks; diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp index c59efeae2..85ddb5d47 100644 --- a/src/engine/zsmOps.cpp +++ b/src/engine/zsmOps.cpp @@ -151,7 +151,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { for (DivRegWrite& write: writes) { if (i==YM) zsm.writeYM(write.addr&0xff,write.val); if (i==VERA) { - if (done && write.addr >= 64) continue; // don't process any PCM events on the loop lookahead + if (done && write.addr>=64) continue; // don't process any PCM or sync events on the loop lookahead zsm.writePSG(write.addr&0xff,write.val); } } diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 8131d3c30..2aef20b9e 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -173,6 +173,7 @@ const char* aboutLine[]={ "reSID by Dag Lem", "reSIDfp by Dag Lem, Antti Lankila", "and Leandro Nini", + "dSID by DefleMask Team based on jsSID", "Stella by Stella Team", "QSound emulator by superctr and Valley Bell", "VICE VIC-20 sound core by Rami Rasanen and viznut", diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 49d568b3c..60806bde1 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -356,7 +356,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text("- filtCut: %d",ch->filtCut); ImGui::Text("- resetTime: %d",ch->resetTime); COMMON_CHIP_DEBUG_BOOL; - ImGui::TextColored(ch->isFP?colorOn:colorOff,">> IsFP"); break; } case DIV_SYSTEM_ARCADE: diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 62608960b..a1a5cb842 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -6347,8 +6347,8 @@ bool FurnaceGUI::init() { logD("starting render backend..."); if (!rend->init(sdlWin)) { - if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) { - settings.renderBackend=""; + if (settings.renderBackend!="SDL") { + settings.renderBackend="SDL"; //e->setConf("renderBackend",""); //e->saveConf(); //lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); diff --git a/src/gui/gui.h b/src/gui/gui.h index a8befff29..267e34a0f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -75,16 +75,20 @@ enum FurnaceGUIRenderBackend { GUI_BACKEND_DX11 }; -#ifdef HAVE_RENDER_SDL -#define GUI_BACKEND_DEFAULT GUI_BACKEND_SDL -#define GUI_BACKEND_DEFAULT_NAME "SDL" -#else #ifdef HAVE_RENDER_DX11 #define GUI_BACKEND_DEFAULT GUI_BACKEND_DX11 #define GUI_BACKEND_DEFAULT_NAME "DirectX 11" #else +#ifdef HAVE_RENDER_GL #define GUI_BACKEND_DEFAULT GUI_BACKEND_GL #define GUI_BACKEND_DEFAULT_NAME "OpenGL" +#else +#ifdef HAVE_RENDER_SDL +#define GUI_BACKEND_DEFAULT GUI_BACKEND_SDL +#define GUI_BACKEND_DEFAULT_NAME "SDL" +#else +#error how did you manage to do that? +#endif #endif #endif @@ -1544,7 +1548,7 @@ class FurnaceGUI { snCore(0), nesCore(0), fdsCore(0), - c64Core(1), + c64Core(0), pokeyCore(1), opnCore(1), pcSpeakerOutMethod(0), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 882bc8075..ab06d74f0 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -116,7 +116,8 @@ const char* nesCores[]={ const char* c64Cores[]={ "reSID", - "reSIDfp" + "reSIDfp", + "dSID" }; const char* pokeyCores[]={ @@ -1254,7 +1255,7 @@ void FurnaceGUI::drawSettings() { ImGui::Text("SID core"); ImGui::SameLine(); - ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,2); + ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,3); ImGui::Text("POKEY core"); ImGui::SameLine(); @@ -2645,7 +2646,7 @@ void FurnaceGUI::syncSettings() { settings.snCore=e->getConfInt("snCore",0); settings.nesCore=e->getConfInt("nesCore",0); settings.fdsCore=e->getConfInt("fdsCore",0); - settings.c64Core=e->getConfInt("c64Core",1); + settings.c64Core=e->getConfInt("c64Core",0); settings.pokeyCore=e->getConfInt("pokeyCore",1); settings.opnCore=e->getConfInt("opnCore",1); settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0); @@ -2771,7 +2772,7 @@ void FurnaceGUI::syncSettings() { settings.orderButtonPos=e->getConfInt("orderButtonPos",2); settings.compress=e->getConfInt("compress",1); settings.newPatternFormat=e->getConfInt("newPatternFormat",1); - settings.renderBackend=e->getConfString("renderBackend","SDL"); + settings.renderBackend=e->getConfString("renderBackend",GUI_BACKEND_DEFAULT_NAME); settings.renderClearPos=e->getConfInt("renderClearPos",0); settings.insertBehavior=e->getConfInt("insertBehavior",1); settings.pullDeleteRow=e->getConfInt("pullDeleteRow",1); @@ -2791,7 +2792,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.snCore,0,1); clampSetting(settings.nesCore,0,1); clampSetting(settings.fdsCore,0,1); - clampSetting(settings.c64Core,0,1); + clampSetting(settings.c64Core,0,2); clampSetting(settings.pokeyCore,0,1); clampSetting(settings.opnCore,0,1); clampSetting(settings.pcSpeakerOutMethod,0,4); @@ -2971,7 +2972,7 @@ void FurnaceGUI::commitSettings() { settings.snCore!=e->getConfInt("snCore",0) || settings.nesCore!=e->getConfInt("nesCore",0) || settings.fdsCore!=e->getConfInt("fdsCore",0) || - settings.c64Core!=e->getConfInt("c64Core",1) || + settings.c64Core!=e->getConfInt("c64Core",0) || settings.pokeyCore!=e->getConfInt("pokeyCore",1) || settings.opnCore!=e->getConfInt("opnCore",1) ); diff --git a/src/main.cpp b/src/main.cpp index 574c1dd7a..e58a455ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -198,6 +198,7 @@ TAParamResult pVersion(String) { printf("- NSFPlay by Brad Smith and Brezza (unknown open-source license)\n"); printf("- reSID by Dag Lem (GPLv2)\n"); printf("- reSIDfp by Dag Lem, Antti Lankila and Leandro Nini (GPLv2)\n"); + printf("- dSID by DefleMask Team (based on jsSID by Hermit) (MIT)\n"); printf("- Stella by Stella Team (GPLv2)\n"); printf("- vgsound_emu (second version, modified version) by cam900 (zlib license)\n"); printf("- MAME GA20 core by Acho A. Tang, R. Belmont, Valley Bell (BSD 3-clause)\n");