From 78cb4b4afdc041a8177bb296a4f132ff353200dc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 7 Nov 2025 04:03:34 -0500 Subject: [PATCH 01/25] get the new flags working --- src/main.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 74daa9777..28706699e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -484,14 +484,53 @@ TAParamResult pOutFormat(String val) { } TAParamResult pBitRate(String val) { + try { + int br=std::stoi(val); + if (br<0) { + logE("bit rate shall be positive."); + return TA_PARAM_ERROR; + } + if (br<1000) { + // let's assume the user meant kilobits. + br*=1000; + } + exportOptions.bitRate=br; + } catch (std::exception& e) { + logE("bit rate shall be a number."); + return TA_PARAM_ERROR; + } return TA_PARAM_SUCCESS; } TAParamResult pRateMode(String val) { + if (val=="constant") { + exportOptions.bitRateMode=DIV_EXPORT_BITRATE_CONSTANT; + } else if (val=="variable") { + exportOptions.bitRateMode=DIV_EXPORT_BITRATE_VARIABLE; + } else if (val=="average") { + exportOptions.bitRateMode=DIV_EXPORT_BITRATE_AVERAGE; + } else { + logE("invalid value for ratemode! valid values are: constant, variable and average."); + return TA_PARAM_ERROR; + } return TA_PARAM_SUCCESS; } TAParamResult pCompression(String val) { + try { + float qual=std::stof(val); + if (qual<0) { + logE("quality/compression level shall be positive."); + return TA_PARAM_ERROR; + } + if (qual>10) { + qual=10; + } + exportOptions.vbrQuality=qual; + } catch (std::exception& e) { + logE("quality/compression level shall be a number."); + return TA_PARAM_ERROR; + } return TA_PARAM_SUCCESS; } @@ -591,7 +630,7 @@ void initParams() { params.push_back(TAParam("f","outformat",true,pOutFormat,"u8|s16|f32|opus|flac|vorbis|mp3","set audio output format")); params.push_back(TAParam("b","bitrate",true,pBitRate,"","set output file bit rate (lossy compression only)")); params.push_back(TAParam("M","ratemode",true,pRateMode,"constant|variable|average","set output bit rate mode (MP3 only)")); - params.push_back(TAParam("Q","compression",true,pCompression,"","set output quality/compression level (Vorbis, FLAC and MP3 VBR only)")); + params.push_back(TAParam("Q","compression",true,pCompression,"","set output quality/compression level from 0-10 (Vorbis, FLAC and MP3 VBR only)")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"","output .vgm data")); From e11cde755cf0a14084fa74a1248256491be54a38 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 7 Nov 2025 05:02:59 -0500 Subject: [PATCH 02/25] GUI: fix a couple pattern refactor bugs effect description in status bar *still* being wrong randomize resulting in invalid notes --- src/gui/editing.cpp | 7 +++++-- src/gui/gui.cpp | 2 +- src/gui/settings.cpp | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index b05152b86..3999b4911 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -1582,8 +1582,11 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa value=MIN(absoluteTop,bottom); value2=MIN(absoluteTop,bottom); } else { - value=MIN(absoluteTop,bottom+(rand()%(top-bottom+1))); - value2=MIN(absoluteTop,bottom+(rand()%(top-bottom+1))); + // HACK: MIN will call rand() twice.... + int randVal=rand(); + value=MIN(absoluteTop,bottom+(randVal%(top-bottom+1))); + randVal=rand(); + value2=MIN(absoluteTop,bottom+(randVal%(top-bottom+1))); } if (mode) { value&=15; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6976eadb9..eee4b1c70 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5001,7 +5001,7 @@ bool FurnaceGUI::loop() { break; default: // effect if (cursor.xFinenewData[cursor.y][cursor.xFine]>-1) { + if (p->newData[cursor.y][(cursor.xFine-1)|1]>-1) { info=e->getEffectDesc(p->newData[cursor.y][(cursor.xFine-1)|1],cursor.xCoarse,true); hasInfo=true; } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 6fedfbf23..136640a2a 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -4703,9 +4703,9 @@ void FurnaceGUI::drawSettings() { // "Debug" - toggles mobile UI // "Nice Amiga cover of the song!" - enables hidden systems (YMU759/Dummy) // "42 63" - enables all instrument types - // "4-bit FDS" - enables partial pitch linearity option // "Power of the Chip" - enables options for multi-threaded audio // "btcdbcb" - use modern UI padding + // "6-7" - OH PLEASE NO // "????" - enables stuff CONFIG_SECTION(_("Cheat Codes")) { // SUBSECTION ENTER CODE: @@ -4748,6 +4748,22 @@ void FurnaceGUI::drawSettings() { sty.ItemInnerSpacing=ImVec2(10.0f*dpiScale,10.0f*dpiScale); settingsOpen=false; } + if (checker==0x2222225c && checker1==0x2d2) { + mmlString[30]=_("Oh my god... Kill me now so I don't have to go through that again!"); + for (int i=0; igetTotalChannelCount(); i++) { + for (int j=0; jcurSubSong->pat[i].data[j]!=NULL) { + DivPattern* p=e->curSubSong->pat[i].data[j]; + for (int k=0; knewData[k][DIV_PAT_NOTE]>=0 && p->newData[k][DIV_PAT_NOTE]<180) { + int newNote=p->newData[k][DIV_PAT_NOTE]+(rand()%40)-18; + p->newData[k][DIV_PAT_NOTE]=CLAMP(newNote,60,179); + } + } + } + } + } + } mmlString[31]=""; } From 012782f2ad69205231710c18515209c2f2cd064b Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Fri, 7 Nov 2025 14:47:05 +0400 Subject: [PATCH 03/25] wip documentation for the new features --- doc/2-interface/README.md | 4 ++++ doc/8-advanced/README.md | 4 ++++ doc/8-advanced/mixer.md | 13 +++++++++++-- doc/8-advanced/refPlayer.md | 6 ++++++ doc/8-advanced/spectrum.md | 23 +++++++++++++++++++++++ doc/8-advanced/tuner.md | 6 ++++++ 6 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 doc/8-advanced/refPlayer.md create mode 100644 doc/8-advanced/spectrum.md create mode 100644 doc/8-advanced/tuner.md diff --git a/doc/2-interface/README.md b/doc/2-interface/README.md index 7d4300adf..5ad0cd036 100644 --- a/doc/2-interface/README.md +++ b/doc/2-interface/README.md @@ -35,6 +35,8 @@ the default layout of Furnace is depicted below. - [oscilloscope](../8-advanced/osc.md) - [oscilloscope (per channel)](../8-advanced/chanosc.md) - [oscilloscope (X-Y)](../8-advanced/xyosc.md) +- [tuner](../8-advanced/tuner.md) +- [spectrum](../8-advanced/spectrum.md) - [clock](../8-advanced/clock.md) - [grooves](../8-advanced/grooves.md) - [log viewer](../8-advanced/log-viewer.md) @@ -45,4 +47,6 @@ the default layout of Furnace is depicted below. ## other topics - [piano/input pad](../8-advanced/piano.md) +- [reference music player](../8-advanced/refPlayer.md) +- [multi-ins setup](../8-advanced/multi-ins.md) - [settings](settings.md) diff --git a/doc/8-advanced/README.md b/doc/8-advanced/README.md index 759737e0e..e4641bbbd 100644 --- a/doc/8-advanced/README.md +++ b/doc/8-advanced/README.md @@ -19,6 +19,8 @@ as listed in the "Window" menu: - [oscilloscope](../8-advanced/osc.md) - [oscilloscope (per-channel)](../8-advanced/chanosc.md) - [oscilloscope (X-Y)](../8-advanced/xyosc.md) + - [tuner](../8-advanced/tuner.md) + - [spectrum](../8-advanced/spectrum.md) - volume meter - tempo - [clock](../8-advanced/clock.md) @@ -29,6 +31,8 @@ as listed in the "Window" menu: - [statistics](../8-advanced/stats.md) - [memory composition](../8-advanced/memory-composition.md) - [piano/input pad](../8-advanced/piano.md) +- [reference music player](../8-advanced/refPlayer.md) +- [multi-ins setup](../8-advanced/multi-ins.md) other: diff --git a/doc/8-advanced/mixer.md b/doc/8-advanced/mixer.md index 55beca2a1..03883e6ad 100644 --- a/doc/8-advanced/mixer.md +++ b/doc/8-advanced/mixer.md @@ -4,9 +4,9 @@ the "Mixer" dialog provides options for overall sound mixing. ## "Mixer" tab -![mixer dialog on mixer tab](mixer-mixer.png) +![mixer dialog on mixer tab](mixer-mixer.png) -"Master Volume" controls the overall mix. +**Master Volume** controls the overall mix. each chip has several options: - **Invert**: flips the output wave. @@ -14,6 +14,15 @@ each chip has several options: - **Panning**: left-right sound control. - **Front/Rear**: front-read sound control. only useful for setups with four or more speakers. +### Mixer-specific settings +- **Mixer layout**: how the mixer is shown. + - **Horizontal**: arranges the "chips" horizontally, with vertical volume sliders. + - **Vertical**: arranges the "chips" vertically, with horizontal volume sliders. +- **Mixer style**: + - **No volume meters**: does not show per-chip volume meters. + - **Volume meters separate**: shows per-chip volume meters below or to the right (depending on the layout) of the volume slider. + - **Volume meters in volume sliders**: shows per-chip volume meters inside the volume sliders. + ## "Patchbay" tab ![mixer dialog on patchbay tab](mixer-patchbay.png) diff --git a/doc/8-advanced/refPlayer.md b/doc/8-advanced/refPlayer.md new file mode 100644 index 000000000..6677a3d8a --- /dev/null +++ b/doc/8-advanced/refPlayer.md @@ -0,0 +1,6 @@ +# reference music player + +the Music Player window is a small audio player that can synchronize with the tracker playback. + + diff --git a/doc/8-advanced/spectrum.md b/doc/8-advanced/spectrum.md new file mode 100644 index 000000000..8a315d8dd --- /dev/null +++ b/doc/8-advanced/spectrum.md @@ -0,0 +1,23 @@ +# spectrum + +the Spectrum window shows the frequency spectrum of the audio output. + + + + +the X scale is in Hertz, and the Y scale is in decibels. + +clicking the threeline button in the top left corner open its configuration. +- **Mono**: whether to mix all the output for a single graph. +- **Bins**: number of bins for the FFT calculation. +--- +- **X Zoom**: how much to zoom the X axis. +- **X Offset**: how much to move the X axis. +--- +- **Y Offset**: how much to move the Y axis down. +--- +- **Show X Grid**: whether to show the X axis grid lines. +- **Show Y Grid**: whether to show the Y axis grid lines. +- **Show X Scale**: whether to show the X axis scale. +- **Show Y Scale**: whether to show the Y axis scale. \ No newline at end of file diff --git a/doc/8-advanced/tuner.md b/doc/8-advanced/tuner.md new file mode 100644 index 000000000..233a09dd0 --- /dev/null +++ b/doc/8-advanced/tuner.md @@ -0,0 +1,6 @@ +# tuner + +the Tuner window shows the approximate frequency and note of the audio output. + + From 999266070851f1c497cbca739c36a1063fcd9e5b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 7 Nov 2025 19:18:56 -0500 Subject: [PATCH 04/25] prepare for nuking legacy sample mode --- src/engine/engine.cpp | 2 -- src/engine/sysDef.cpp | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0f1c30822..6d47bd628 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -130,8 +130,6 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul return _("E9xy: Quick legato down (x: time; y: semitones)"); case 0xea: return _("EAxx: Legato"); - case 0xeb: - return _("EBxx: Set LEGACY sample mode bank"); case 0xec: return _("ECxx: Note cut"); case 0xed: diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index b85026d4d..9f00cb7cf 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -465,7 +465,6 @@ void DivEngine::registerSystems() { EffectHandlerMap fmOPN2EffectHandlerMap(fmEffectHandlerMap); fmOPN2EffectHandlerMap.insert({ - {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Toggle PCM mode (LEGACY)")}}, {0xdf, {DIV_CMD_SAMPLE_DIR, _("DFxx: Set sample playback direction (0: normal; 1: reverse)")}}, }); @@ -884,7 +883,6 @@ void DivEngine::registerSystems() { {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Toggle noise mode")}}, {0x12, {DIV_CMD_PCE_LFO_MODE, _("12xx: Setup LFO (0: disabled; 1: 1x depth; 2: 16x depth; 3: 256x depth)")}}, {0x13, {DIV_CMD_PCE_LFO_SPEED, _("13xx: Set LFO speed")}}, - {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Toggle PCM mode (LEGACY)")}} } ); @@ -1149,7 +1147,6 @@ void DivEngine::registerSystems() { {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_NULL}, { {0x12, {DIV_CMD_STD_NOISE_MODE, _("12xx: Set duty cycle (pulse: 0 to 7)")}}, - {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Toggle PCM mode (LEGACY)")}}, } ); @@ -1403,7 +1400,6 @@ void DivEngine::registerSystems() { {0x11, {DIV_CMD_STD_NOISE_MODE, _("11xx: Setup noise mode (0: disabled; 1-8: enabled/tap)")}}, {0x12, {DIV_CMD_WS_SWEEP_TIME, _("12xx: Setup sweep period (0: disabled; 1-20: enabled/period)")}}, {0x13, {DIV_CMD_WS_SWEEP_AMOUNT, _("13xx: Set sweep amount")}}, - {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Toggle PCM mode (LEGACY)")}}, }, { {0x20, {DIV_CMD_WS_GLOBAL_SPEAKER_VOLUME, _("20xx: Set internal speaker loudness (0-1: 100%, 2-3: 200%, 4-7: 400%, 8: 800%)")}}, @@ -1728,7 +1724,6 @@ void DivEngine::registerSystems() { {0x10, {DIV_CMD_WAVE, _("10xx: Set waveform")}}, {0x11, {DIV_CMD_X1_010_ENVELOPE_SHAPE, _("11xx: Set envelope shape")}}, {0x12, {DIV_CMD_X1_010_SAMPLE_BANK_SLOT, _("12xx: Set sample bank slot (0 to 7)")}}, - {0x17, {DIV_CMD_SAMPLE_MODE, _("17xx: Toggle PCM mode (LEGACY)")}}, }, { {0x20, {DIV_CMD_SAMPLE_FREQ, _("20xx: Set PCM frequency (1 to FF)")}}, From 08e21a6298558a7f19baf1875a3b7a827e2628f3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 7 Nov 2025 19:27:05 -0500 Subject: [PATCH 05/25] remove all references to legacy sample mode in doc --- doc/3-pattern/effects.md | 2 -- doc/6-sample/README.md | 9 --------- doc/7-systems/pce.md | 2 -- doc/7-systems/vrc6.md | 2 -- doc/7-systems/x1-010.md | 2 -- doc/7-systems/ym2612.md | 3 --- 6 files changed, 20 deletions(-) diff --git a/doc/3-pattern/effects.md b/doc/3-pattern/effects.md index 4edcbbc0d..dacf4e1cc 100644 --- a/doc/3-pattern/effects.md +++ b/doc/3-pattern/effects.md @@ -135,8 +135,6 @@ in previous versions of Furnace a `9xxx` effect existed which set the sample pos ## other -- `EBxx`: **Set LEGACY sample mode bank.** selects sample bank. used only for compatibility. - - does not apply on Amiga. - `EExx`: **Send external command.** - this effect is currently incomplete. - `F5xx`: **Disable macro.** diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 1882a3f0e..cd2f5ddbd 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -50,15 +50,6 @@ the simplest path to using a sample is: - click the "Create instrument from sample" button (upload icon, to the left of "Zoom"). - use the created instrument in the track. -## compatible sample mode (LEGACY) - -**use of this mode is discouraged in favor of Sample type instruments.** - -effect `17xx` enables/disables compatible sample mode where supported (e.g. on Sega Genesis or PC Engine). - -in this mode, samples are mapped to notes in an octave from C to B, allowing you to use up to 12 samples. -if you need to use more samples, you may change the sample bank using effect `EBxx`. - ## notes due to limitations in some of those sound chips, some restrictions exist: diff --git a/doc/7-systems/pce.md b/doc/7-systems/pce.md index be065da5f..26820c169 100644 --- a/doc/7-systems/pce.md +++ b/doc/7-systems/pce.md @@ -18,8 +18,6 @@ furthermore, it has some PCM and LFO! - `03`: LFO enabled, shift 8. - when LFO is enabled, channel 2 is muted and its output is passed to channel 1's frequency. - `13xx`: **set LFO speed.** -- `17xx`: **toggle LEGACY sample mode.** - - **this effect exists only for compatibility reasons! its use is NOT recommended. use Sample type instruments instead.** ## info diff --git a/doc/7-systems/vrc6.md b/doc/7-systems/vrc6.md index cdfca3ee8..a7577a348 100644 --- a/doc/7-systems/vrc6.md +++ b/doc/7-systems/vrc6.md @@ -15,8 +15,6 @@ Furnace supports this routine for PCM playback, but it consumes a lot of CPU tim these effects only are effective in the pulse channels. - `12xx`: **set duty cycle.** range is `0` to `7`. -- `17xx`: **toggle LEGACY sample mode.** - - **this effect exists only for compatibility reasons! its use is NOT recommended. use Sample type instruments instead.** ## info diff --git a/doc/7-systems/x1-010.md b/doc/7-systems/x1-010.md index d824647db..004785f09 100644 --- a/doc/7-systems/x1-010.md +++ b/doc/7-systems/x1-010.md @@ -17,8 +17,6 @@ this chip was the inspiration for Organya/PxTone (the former being used in a wel - `10xx`: **change wave.** - `11xx`: **change envelope shape.** also wavetable. -- `17xx`: **toggle LEGACY sample mode.** - - **this effect exists only for compatibility reasons! its use is NOT recommended. use Sample type instruments instead.** - `20xx`: **set PCM frequency.** range is `1` to `FF`. - PCM frequency formula: `step * (clock / 8192)`. - range is 1.95KHz to 498KHz if the chip clock is 16MHz. diff --git a/doc/7-systems/ym2612.md b/doc/7-systems/ym2612.md index bda9f0fd2..0785666b1 100644 --- a/doc/7-systems/ym2612.md +++ b/doc/7-systems/ym2612.md @@ -16,9 +16,6 @@ Furnace also offers DualPCM, a Z80 driver that splits channel 6 into two individ - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - `y` is the new MULT value. -- `17xx`: **toggle LEGACY sample mode.** - - this only works on channel 6. - - **this effect exists only for compatibility reasons! its use is NOT recommended. use Sample type instruments instead.** - `18xx`: **toggle extended channel 3 mode.** - 0 disables it and 1 enables it. - only in extended channel 3 chip. From 91a9f5de15878390ced70c00caa874c0bb69c142 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Sat, 8 Nov 2025 12:36:24 +0400 Subject: [PATCH 06/25] fix regview address clipping --- src/gui/regView.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/gui/regView.cpp b/src/gui/regView.cpp index 6c545234b..913d8ffd1 100644 --- a/src/gui/regView.cpp +++ b/src/gui/regView.cpp @@ -39,7 +39,14 @@ void FurnaceGUI::drawRegView() { } else { ImGui::PushFont(patFont); if (ImGui::BeginTable("Memory",17)) { - ImGui::TableSetupColumn("addr",ImGuiTableColumnFlags_WidthFixed); + float widthOne=ImGui::CalcTextSize("0").x; + if (size>0xfff) { // no im got gonna put some clamped log formula instead + ImGui::TableSetupColumn("addr",ImGuiTableColumnFlags_WidthFixed, widthOne*4.0f); + } else if (size>0xff) { + ImGui::TableSetupColumn("addr",ImGuiTableColumnFlags_WidthFixed, widthOne*3.0f); + } else { + ImGui::TableSetupColumn("addr",ImGuiTableColumnFlags_WidthFixed, widthOne*2.0f); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); From 416148bd62121b534a485912b9078373ef4bf0c7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 14:37:51 -0500 Subject: [PATCH 07/25] total extinction of legacy sample mode, part 1 --- src/engine/engine.h | 4 +-- src/engine/fileOps/dmf.cpp | 9 +++---- src/engine/fileOps/ftm.cpp | 1 - src/engine/fileOps/mod.cpp | 3 +-- src/engine/fileOps/p.cpp | 3 +-- src/engine/fileOps/p86.cpp | 3 +-- src/engine/fileOps/pdx.cpp | 3 +-- src/engine/fileOps/ppc.cpp | 3 +-- src/engine/fileOps/pps.cpp | 1 - src/engine/fileOps/pvi.cpp | 3 +-- src/engine/fileOps/pzi.cpp | 1 - src/engine/fileOps/text.cpp | 1 - src/engine/fileOpsSample.cpp | 6 ----- src/engine/platform/ay.cpp | 24 +----------------- src/engine/platform/ay8930.cpp | 24 +----------------- src/engine/platform/genesis.cpp | 20 +-------------- src/engine/platform/mmc5.cpp | 21 +--------------- src/engine/platform/nes.cpp | 44 +-------------------------------- src/engine/platform/opl.cpp | 29 +--------------------- src/engine/platform/pce.cpp | 27 +------------------- src/engine/platform/segapcm.cpp | 15 +---------- src/engine/platform/swan.cpp | 19 +------------- src/engine/platform/vrc6.cpp | 27 +------------------- src/engine/platform/x1_010.cpp | 34 +++---------------------- src/engine/platform/ym2608.cpp | 31 +---------------------- src/engine/platform/ym2610.cpp | 30 +--------------------- src/engine/platform/ym2610b.cpp | 30 +--------------------- src/engine/sample.cpp | 11 ++++----- src/engine/sample.h | 11 +++------ src/gui/debugWindow.cpp | 1 - src/gui/doAction.cpp | 2 -- src/gui/gui.cpp | 1 - src/gui/gui.h | 2 +- src/gui/sampleEdit.cpp | 37 +++++---------------------- 34 files changed, 44 insertions(+), 437 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 21414afbc..f84dcdbd8 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -55,8 +55,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "dev238" -#define DIV_ENGINE_VERSION 238 +#define DIV_VERSION "dev239" +#define DIV_ENGINE_VERSION 239 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 8593993ef..52e6e9079 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -934,10 +934,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { sample->name=""; } logD("%d name %s (%d)",i,sample->name.c_str(),length); - sample->rate=22050; + sample->centerRate=22050; if (ds.version>=0x0b) { - sample->rate=fileToDivRate(reader.readC()); - sample->centerRate=sample->rate; + sample->centerRate=fileToDivRate(reader.readC()); pitch=reader.readC(); vol=reader.readC(); @@ -947,7 +946,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } if (ds.version<=0x08) { - sample->rate=ymuSampleRate*400; + sample->centerRate=ymuSampleRate*400; } if (ds.version>0x15) { sample->depth=(DivSampleDepth)reader.readC(); @@ -1680,7 +1679,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { for (DivSample* i: song.sample) { w->writeI(i->samples); w->writeString(i->name,true); - w->writeC(divToFileRate(i->rate)); + w->writeC(divToFileRate(i->centerRate)); w->writeC(5); w->writeC(50); // i'm too lazy to deal with .dmf's weird way of storing 8-bit samples diff --git a/src/engine/fileOps/ftm.cpp b/src/engine/fileOps/ftm.cpp index 0895bcb98..791269891 100644 --- a/src/engine/fileOps/ftm.cpp +++ b/src/engine/fileOps/ftm.cpp @@ -1986,7 +1986,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si DivSample* sample = ds.sample[index]; - sample->rate = 33144; sample->centerRate = 33144; sample->depth = DIV_SAMPLE_DEPTH_1BIT_DPCM; diff --git a/src/engine/fileOps/mod.cpp b/src/engine/fileOps/mod.cpp index 6672a0242..5a8e3d3aa 100644 --- a/src/engine/fileOps/mod.cpp +++ b/src/engine/fileOps/mod.cpp @@ -112,8 +112,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { if (slen==2) slen=0; signed char fineTune=reader.readC()&0x0f; if (fineTune>=8) fineTune-=16; - sample->rate=(int)(pow(2.0,(double)fineTune/96.0)*8363.0); - sample->centerRate=sample->rate; + sample->centerRate=(int)(pow(2.0,(double)fineTune/96.0)*8363.0); defaultVols[i]=reader.readC(); int loopStart=reader.readS_BE()*2; int loopLen=reader.readS_BE()*2; diff --git a/src/engine/fileOps/p.cpp b/src/engine/fileOps/p.cpp index 07f588ec8..049aa6b9a 100644 --- a/src/engine/fileOps/p.cpp +++ b/src/engine/fileOps/p.cpp @@ -75,7 +75,6 @@ void DivEngine::loadP(SafeReader& reader, std::vector& ret, String& { DivSample* s = new DivSample; - s->rate = P_SAMPLE_RATE; s->centerRate = P_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_VOX; @@ -121,4 +120,4 @@ void DivEngine::loadP(SafeReader& reader, std::vector& ret, String& lastError=_("premature end of file"); logE("premature end of file"); } -} \ No newline at end of file +} diff --git a/src/engine/fileOps/p86.cpp b/src/engine/fileOps/p86.cpp index ae32b0acd..93f56600d 100644 --- a/src/engine/fileOps/p86.cpp +++ b/src/engine/fileOps/p86.cpp @@ -110,7 +110,6 @@ void DivEngine::loadP86(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = P86_SAMPLE_RATE; s->centerRate = P86_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_8BIT; s->init(headers[i].sample_length); //byte per sample @@ -139,4 +138,4 @@ void DivEngine::loadP86(SafeReader& reader, std::vector& ret, String lastError=_("premature end of file"); logE("premature end of file"); } -} \ No newline at end of file +} diff --git a/src/engine/fileOps/pdx.cpp b/src/engine/fileOps/pdx.cpp index 4607775be..fda8b35dd 100644 --- a/src/engine/fileOps/pdx.cpp +++ b/src/engine/fileOps/pdx.cpp @@ -69,7 +69,6 @@ void DivEngine::loadPDX(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = PDX_SAMPLE_RATE; s->centerRate = PDX_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_VOX; s->init(headers[i].sample_length * 2); @@ -98,4 +97,4 @@ void DivEngine::loadPDX(SafeReader& reader, std::vector& ret, String lastError=_("premature end of file"); logE("premature end of file"); } -} \ No newline at end of file +} diff --git a/src/engine/fileOps/ppc.cpp b/src/engine/fileOps/ppc.cpp index 57725c0a0..62c287d8f 100644 --- a/src/engine/fileOps/ppc.cpp +++ b/src/engine/fileOps/ppc.cpp @@ -109,7 +109,6 @@ void DivEngine::loadPPC(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = PPC_SAMPLE_RATE; s->centerRate = PPC_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_ADPCM_B; s->init((headers[i].end_pointer - headers[i].start_pointer) * 32 * 2); @@ -139,4 +138,4 @@ void DivEngine::loadPPC(SafeReader& reader, std::vector& ret, String lastError=_("premature end of file"); logE("premature end of file"); } -} \ No newline at end of file +} diff --git a/src/engine/fileOps/pps.cpp b/src/engine/fileOps/pps.cpp index b69ff3eb6..de8fd6f80 100644 --- a/src/engine/fileOps/pps.cpp +++ b/src/engine/fileOps/pps.cpp @@ -90,7 +90,6 @@ void DivEngine::loadPPS(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = PPS_SAMPLE_RATE; s->centerRate = PPS_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_4BIT; s->init(headers[i].sample_length*2); // bytes->samples diff --git a/src/engine/fileOps/pvi.cpp b/src/engine/fileOps/pvi.cpp index 4bc316064..a26dd6c62 100644 --- a/src/engine/fileOps/pvi.cpp +++ b/src/engine/fileOps/pvi.cpp @@ -125,7 +125,6 @@ void DivEngine::loadPVI(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = PVI_SAMPLE_RATE; s->centerRate = PVI_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_ADPCM_B; s->init((headers[i].end_pointer - headers[i].start_pointer) * 32 * 2); @@ -155,4 +154,4 @@ void DivEngine::loadPVI(SafeReader& reader, std::vector& ret, String lastError=_("premature end of file"); logE("premature end of file"); } -} \ No newline at end of file +} diff --git a/src/engine/fileOps/pzi.cpp b/src/engine/fileOps/pzi.cpp index 3efde759d..f8b6656a6 100644 --- a/src/engine/fileOps/pzi.cpp +++ b/src/engine/fileOps/pzi.cpp @@ -113,7 +113,6 @@ void DivEngine::loadPZI(SafeReader& reader, std::vector& ret, String { DivSample* s = new DivSample; - s->rate = headers[i].sample_rate; s->centerRate = headers[i].sample_rate; s->depth = DIV_SAMPLE_DEPTH_8BIT; s->init(headers[i].sample_length); //byte per sample diff --git a/src/engine/fileOps/text.cpp b/src/engine/fileOps/text.cpp index 83b4b9ae6..3dbc598d3 100644 --- a/src/engine/fileOps/text.cpp +++ b/src/engine/fileOps/text.cpp @@ -262,7 +262,6 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) { w->writeText(fmt::sprintf("- data length: %d\n",sample->getCurBufLen())); w->writeText(fmt::sprintf("- samples: %d\n",sample->samples)); w->writeText(fmt::sprintf("- rate: %d\n",sample->centerRate)); - w->writeText(fmt::sprintf("- compat rate: %d\n",sample->rate)); w->writeText(fmt::sprintf("- loop: %s\n",trueFalse[sample->loop?1:0])); if (sample->loop) { w->writeText(fmt::sprintf(" - start: %d\n",sample->loopStart)); diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index 1fbaa032e..8104bdc58 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -213,12 +213,10 @@ std::vector DivEngine::sampleFromFile(const char* path) { } if (extS==".dmc") { - sample->rate=33144; sample->centerRate=33144; sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM; sample->init(len*8); } else if (extS==".brr") { - sample->rate=32000; sample->centerRate=32000; sample->depth=DIV_SAMPLE_DEPTH_BRR; sample->init(16*(len/9)); @@ -400,9 +398,6 @@ std::vector DivEngine::sampleFromFile(const char* path) { delete[] (float*)buf; } - sample->rate=si.samplerate; - if (sample->rate<4000) sample->rate=4000; - if (sample->rate>96000) sample->rate=96000; sample->centerRate=si.samplerate; SF_INSTRUMENT inst; @@ -563,7 +558,6 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, return NULL; } - sample->rate=rate; sample->centerRate=rate; sample->depth=depth; sample->init(samples); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 00e02905b..5506278a0 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -723,29 +723,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { //chan[c.chan].keyOn=true; chan[c.chan].dac.furnaceDAC=true; } else { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; - if (chan[c.chan].dac.sample>=parent->song.sampleLen) { - chan[c.chan].dac.sample=-1; - //if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - //if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); - } - if (chan[c.chan].dac.setPos) { - chan[c.chan].dac.setPos=false; - } else { - chan[c.chan].dac.pos=0; - } - chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*2048; - if (dumpWrites) { - rWrite(0x08+c.chan,0); - //addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); - } - chan[c.chan].dac.furnaceDAC=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } chan[c.chan].curPSGMode.val&=~8; chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 2190202e9..aea1899fa 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -551,29 +551,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { //chan[c.chan].keyOn=true; chan[c.chan].dac.furnaceDAC=true; } else { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; - if (chan[c.chan].dac.sample>=parent->song.sampleLen) { - chan[c.chan].dac.sample=-1; - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); - } - if (chan[c.chan].dac.setPos) { - chan[c.chan].dac.setPos=false; - } else { - chan[c.chan].dac.pos=0; - } - chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*4096; - if (dumpWrites) { - rWrite(0x08+c.chan,0); - addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); - } - chan[c.chan].dac.furnaceDAC=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } chan[c.chan].curPSGMode.val&=~8; chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index d163daec5..10994ac0d 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -1108,25 +1108,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { //chan[c.chan].keyOn=true; chan[c.chan].active=true; } else { // compatible mode - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - chan[c.chan].dacSample=12*chan[c.chan].sampleBank+chan[c.chan].note%12; - if (chan[c.chan].dacSample>=parent->song.sampleLen) { - chan[c.chan].dacSample=-1; - if (dumpWrites) addWrite(0xffff0002,0); - break; - } else { - rWrite(0x2b,1<<7); - if (dumpWrites) addWrite(0xffff0000,chan[c.chan].dacSample); - } - chan[c.chan].dacPos=0; - chan[c.chan].dacPeriod=0; - chan[c.chan].dacRate=MAX(1,parent->getSample(chan[c.chan].dacSample)->rate); - if (dumpWrites) addWrite(0xffff0001,parent->getSample(chan[c.chan].dacSample)->rate); - chan[c.chan].furnaceDac=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index fcb8dbdc6..39fc57655 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -221,26 +221,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { chan[c.chan].keyOn=true; chan[c.chan].furnaceDac=true; } else { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - dacSample=12*sampleBank+chan[c.chan].note%12; - if (dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) addWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) addWrite(0xffff0000,dacSample); - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - dacPos=0; - } - dacPeriod=0; - dacRate=parent->getSample(dacSample)->rate; - if (dumpWrites) addWrite(0xffff0001,dacRate); - chan[c.chan].furnaceDac=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } else { diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 7ef5db9f6..d570020fc 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -565,49 +565,7 @@ int DivPlatformNES::dispatch(DivCommand c) { chan[c.chan].keyOn=true; chan[c.chan].furnaceDac=true; } else { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - dacSample=12*sampleBank+chan[c.chan].note%12; - if (dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites && !dpcmMode) addWrite(0xffff0002,0); - break; - } else { - if (dumpWrites && !dpcmMode) addWrite(0xffff0000,dacSample); - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - dacPos=0; - } - dacPeriod=0; - dacRate=parent->getSample(dacSample)->rate; - if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate); - chan[c.chan].furnaceDac=false; - if (dpcmMode && !skipRegisterWrites) { - unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3); - int dpcmLen=(parent->getSample(dacSample)->lengthDPCM-(dacPos>>3))>>4; - if (dpcmLen<0) dpcmLen=0; - if (dpcmLen>255) dpcmLen=255; - goingToLoop=parent->getSample(dacSample)->isLoopable(); - // write DPCM - rWrite(0x4015,15); - if (nextDPCMFreq>=0) { - rWrite(0x4010,nextDPCMFreq|(goingToLoop?0x40:0)); - nextDPCMFreq=-1; - } else { - rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); - } - rWrite(0x4012,(dpcmAddr>>6)&0xff); - rWrite(0x4013,dpcmLen&0xff); - rWrite(0x4015,31); - if (dpcmBank!=(dpcmAddr>>14)) { - dpcmBank=dpcmAddr>>14; - logV("switching bank to %d",dpcmBank); - if (dumpWrites) addWrite(0xffff0004,dpcmBank); - } - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } else if (c.chan==3) { // noise diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 4b7268f13..dd879260d 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1879,34 +1879,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(8,0); - immWrite(9,(sampleOffB[chan[c.chan].sample]>>2)&0xff); - immWrite(10,(sampleOffB[chan[c.chan].sample]>>10)&0xff); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(11,(end>>2)&0xff); - immWrite(12,(end>>10)&0xff); - int freq=(65536.0*(double)s->rate)/(double)chipRateBase; - chan[c.chan].fixedFreq=freq; - immWrite(16,freq&0xff); - immWrite(17,(freq>>8)&0xff); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(7,0x01); // reset - immWrite(9,0); - immWrite(10,0); - immWrite(11,0); - immWrite(12,0); - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 1a84a2504..46f1b9ac7 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -348,32 +348,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { } //chan[c.chan].keyOn=true; } else { - chan[c.chan].furnaceDac=false; - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - if (skipRegisterWrites) break; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].dacSample=12*sampleBank+chan[c.chan].note%12; - if (chan[c.chan].dacSample>=parent->song.sampleLen) { - chan[c.chan].dacSample=-1; - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - chan[c.chan].dacPos=0; - } - chan[c.chan].dacPeriod=0; - chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; - if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); - addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index eaebf022e..5522b4b63 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -233,20 +233,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; } else { - chan[c.chan].macroInit(NULL); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].pcm.sample=12*sampleBank+chan[c.chan].note%12; - if (chan[c.chan].pcm.sample>=parent->song.sampleLen) { - chan[c.chan].pcm.sample=-1; - rWrite(0x86+(c.chan<<3),3); - break; - } - chan[c.chan].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/rate); - chan[c.chan].furnacePCM=false; - chan[c.chan].active=true; - chan[c.chan].keyOn=true; + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index e7430096e..9d434101c 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -397,24 +397,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { chan[1].macroInit(ins); furnaceDac=true; } else { - if (c.value!=DIV_NOTE_NULL) { - chan[1].note=c.value; - } - dacSample=12*sampleBank+chan[1].note%12; - if (dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) postWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) postWrite(0xffff0000,dacSample); - } - dacRate=parent->getSample(dacSample)->rate; - if (dumpWrites) { - postWrite(0xffff0001,dacRate); - } - chan[1].active=true; - chan[1].keyOn=true; - furnaceDac=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index a7ae0d3da..ee6a95b4d 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -303,32 +303,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { //chan[c.chan].keyOn=true; chan[c.chan].furnaceDac=true; } else { - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].dacSample=12*sampleBank+chan[c.chan].note%12; - if (chan[c.chan].dacSample>=parent->song.sampleLen) { - chan[c.chan].dacSample=-1; - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - chan[c.chan].dacPos=0; - } - chan[c.chan].dacPeriod=0; - chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; - if (dumpWrites) { - chWrite(c.chan,2,0x80); - chWrite(c.chan,0,isMuted[c.chan]?0:0x80); - addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); - } - chan[c.chan].furnaceDac=false; + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 9599b06b4..00683f56d 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -592,43 +592,15 @@ int DivPlatformX1_010::dispatch(DivCommand c) { } else { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; - // huh? - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - chWrite(c.chan,0,0); // reset - chWrite(c.chan,1,0); - chWrite(c.chan,2,0); - chWrite(c.chan,4,0); - chWrite(c.chan,5,0); - break; - } - } - } else { - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { + // TODO: there was a check for legacy sample bank here. why? chWrite(c.chan,0,0); // reset chWrite(c.chan,1,0); chWrite(c.chan,2,0); chWrite(c.chan,4,0); chWrite(c.chan,5,0); - break; } - DivSample* s=parent->getSample(chan[c.chan].sample); - if (isBanked) { - bankSlot[chan[c.chan].bankSlot]=sampleOffX1[chan[c.chan].sample]>>17; - unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(sampleOffX1[chan[c.chan].sample]&0x1ffff); - chWrite(c.chan,4,(bankedOffs>>12)&0xff); - int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); - } else { - chWrite(c.chan,4,(sampleOffX1[chan[c.chan].sample]>>12)&0xff); - int end=(sampleOffX1[chan[c.chan].sample]+s->length8+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); - } - // ???? - chan[c.chan].fixedFreq=(((unsigned int)s->rate)<<4)/(chipClock/512); - chan[c.chan].freqChanged=true; + } else { + assert(false && "LEGACY SAMPLE MODE!!!"); } } else if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 11a1b72c2..71d7d5b71 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1196,36 +1196,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x100,0x01); // reset - immWrite(0x102,(sampleOffB[chan[c.chan].sample]>>5)&0xff); - immWrite(0x103,(sampleOffB[chan[c.chan].sample]>>13)&0xff); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x104,(end>>5)&0xff); - immWrite(0x105,(end>>13)&0xff); - immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|memConfig); - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x109,freq&0xff); - immWrite(0x10a,(freq>>8)&0xff); - immWrite(0x10b,chan[c.chan].outVol); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x100,0x01); // reset - immWrite(0x102,0); - immWrite(0x103,0); - immWrite(0x104,0); - immWrite(0x105,0); - break; - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 5a92212c3..fa0b4e3c3 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -1113,35 +1113,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); - immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); - immWrite(0x1b,chan[c.chan].outVol); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); - break; - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 78bed5eda..71eb8a100 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -1182,35 +1182,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); - immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); - immWrite(0x1b,chan[c.chan].outVol); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); - break; - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index e506321d1..03a6d1089 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -51,7 +51,7 @@ void DivSample::putSampleData(SafeWriter* w) { w->writeString(name,false); w->writeI(samples); - w->writeI(rate); + w->writeI(centerRate); w->writeI(centerRate); w->writeC(depth); w->writeC(loopMode); @@ -116,7 +116,8 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) { if (!isNewSample) { loopEnd=samples; } - rate=reader.readI(); + // just in case it's not new sample, it's a very old version and we gotta read a rate. + centerRate=reader.readI(); if (isNewSample) { centerRate=reader.readI(); @@ -916,7 +917,6 @@ void DivSample::convert(DivSampleDepth newDepth, unsigned int formatMask) { if (loopStart>=0) loopStart=(double)loopStart*(tRate/sRate); \ if (loopEnd>=0) loopEnd=(double)loopEnd*(tRate/sRate); \ centerRate=(int)((double)centerRate*(tRate/sRate)); \ - rate=(int)((double)rate*(tRate/sRate)); \ samples=finalCount; \ if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ delete[] oldData16; \ @@ -1665,9 +1665,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { duplicate=new unsigned char[getCurBufLen()]; memcpy(duplicate,getCurBuf(),getCurBufLen()); } - h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode); + h=new DivSampleHistory(depth,centerRate,loopStart,loopEnd,loop,brrEmphasis,brrNoFilter,dither,loopMode); } if (!doNotPush) { while (!redoHist.empty()) { @@ -1695,7 +1695,6 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { memcpy(buf,h->data,h->length); \ } \ } \ - rate=h->rate; \ centerRate=h->centerRate; \ loopStart=h->loopStart; \ loopEnd=h->loopEnd; \ diff --git a/src/engine/sample.h b/src/engine/sample.h index 609520c7e..9f30c44af 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -66,16 +66,15 @@ struct DivSampleHistory { unsigned char* data; unsigned int length, samples; DivSampleDepth depth; - int rate, centerRate, loopStart, loopEnd; + int centerRate, loopStart, loopEnd; bool loop, brrEmphasis, brrNoFilter, dither; DivSampleLoopMode loopMode; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, bool bf, bool di, DivSampleLoopMode lm): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int cr, int ls, int le, bool lp, bool be, bool bf, bool di, DivSampleLoopMode lm): data((unsigned char*)d), length(l), samples(s), depth(de), - rate(r), centerRate(cr), loopStart(ls), loopEnd(le), @@ -85,12 +84,11 @@ struct DivSampleHistory { dither(di), loopMode(lm), hasSample(true) {} - DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, bool be, bool bf, bool di, DivSampleLoopMode lm): + DivSampleHistory(DivSampleDepth de, int cr, int ls, int le, bool lp, bool be, bool bf, bool di, DivSampleLoopMode lm): data(NULL), length(0), samples(0), depth(de), - rate(r), centerRate(cr), loopStart(ls), loopEnd(le), @@ -105,7 +103,7 @@ struct DivSampleHistory { struct DivSample { String name; - int rate, centerRate, loopStart, loopEnd; + int centerRate, loopStart, loopEnd; // valid values are: // - 0: ZX Spectrum overlay drum (1-bit) // - 1: 1-bit NES DPCM (1-bit) @@ -337,7 +335,6 @@ struct DivSample { int redo(); DivSample(): name(""), - rate(32000), centerRate(8363), loopStart(-1), loopEnd(-1), diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 1b3ba9259..7a4750d50 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -243,7 +243,6 @@ void FurnaceGUI::drawDebug() { continue; } if (ImGui::TreeNode(fmt::sprintf("%d: %s",i,sample->name).c_str())) { - ImGui::Text("rate: %d",sample->rate); ImGui::Text("centerRate: %d",sample->centerRate); ImGui::Text("loopStart: %d",sample->loopStart); ImGui::Text("loopEnd: %d", sample->loopEnd); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 99b29b1f8..ff47ac0f3 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -956,7 +956,6 @@ void FurnaceGUI::doAction(int what) { if (sample!=NULL) { DivWavetable* wave=e->song.wave[curWave]; unsigned int waveLen=wave->len; - sample->rate=(int)round(261.625565301*waveLen); // c3 sample->centerRate=(int)round(261.625565301*waveLen); // c3 sample->loopStart=0; sample->loopEnd=waveLen; @@ -1045,7 +1044,6 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,prevSample]() { DivSample* sample=e->getSample(curSample); if (sample!=NULL) { - sample->rate=prevSample->rate; sample->centerRate=prevSample->centerRate; sample->name=prevSample->name; sample->loopStart=prevSample->loopStart; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index eee4b1c70..3a1592c79 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -9134,7 +9134,6 @@ FurnaceGUI::FurnaceGUI(): sampleSelStart(-1), sampleSelEnd(-1), sampleInfo(true), - sampleCompatRate(false), sampleDragActive(false), sampleDragMode(false), sampleDrag16(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 2f2f46115..ec2cb5766 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2657,7 +2657,7 @@ class FurnaceGUI { int resampleStrat; float amplifyVol, amplifyOff; int sampleSelStart, sampleSelEnd; - bool sampleInfo, sampleCompatRate; + bool sampleInfo; bool sampleDragActive, sampleDragMode, sampleDrag16, sampleZoomAuto; bool sampleCheckLoopStart, sampleCheckLoopEnd; // 0: start diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index bf2152aa2..6fcc0dca2 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -611,7 +611,7 @@ void FurnaceGUI::drawSampleEdit() { if (isChipVisible[i]) selColumns++; } - int targetRate=sampleCompatRate?sample->rate:sample->centerRate; + int targetRate=sample->centerRate; if (ImGui::BeginTable("SampleProps",(selColumns>1)?4:3,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersV|ImGuiTableFlags_BordersOuterH)) { ImGui::TableNextRow(ImGuiTableRowFlags_Headers); @@ -622,20 +622,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::Text(_("Info")); ImGui::TableNextColumn(); - pushToggleColors(!sampleCompatRate); - if (ImGui::Button(_("Rate"))) { - sampleCompatRate=false; - } - popToggleColors(); - ImGui::SameLine(); - pushToggleColors(sampleCompatRate); - if (ImGui::Button(_("Compat Rate"))) { - sampleCompatRate=true; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip(_("used in DefleMask-compatible sample mode (17xx), in where samples are mapped to an octave.")); - } - popToggleColors(); + ImGui::Text(_("Rate")); ImGui::TableNextColumn(); bool doLoop=(sample->loop); pushWarningColor(!warnLoop.empty()); @@ -774,11 +761,7 @@ void FurnaceGUI::drawSampleEdit() { if (targetRate<100) targetRate=100; if (targetRate>384000) targetRate=384000; - if (sampleCompatRate) { - sample->rate=targetRate; - } else { - sample->centerRate=targetRate; - } + sample->centerRate=targetRate; } ImGui::AlignTextToFramePadding(); @@ -818,11 +801,7 @@ void FurnaceGUI::drawSampleEdit() { if (targetRate<100) targetRate=100; if (targetRate>384000) targetRate=384000; - if (sampleCompatRate) { - sample->rate=targetRate; - } else { - sample->centerRate=targetRate; - } + sample->centerRate=targetRate; } ImGui::AlignTextToFramePadding(); @@ -852,11 +831,7 @@ void FurnaceGUI::drawSampleEdit() { if (targetRate<100) targetRate=100; if (targetRate>384000) targetRate=384000; - if (sampleCompatRate) { - sample->rate=targetRate; - } else { - sample->centerRate=targetRate; - } + sample->centerRate=targetRate; } ImGui::TableNextColumn(); @@ -1662,7 +1637,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("SETime"))) { - int targetRate=sampleCompatRate?sample->rate:sample->centerRate; + int targetRate=sample->centerRate; int curDivisorSel=0; int curMultiplierSel=0; double divisor=1000.0; From 0602a2f811f7273e4fcb7eb515e1e162de91f840 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 15:17:56 -0500 Subject: [PATCH 08/25] total extinction of legacy sample mode, part 2 remove legacy sample bank completely --- src/engine/platform/ay.cpp | 7 - src/engine/platform/ay.h | 1 - src/engine/platform/ay8930.cpp | 7 - src/engine/platform/ay8930.h | 2 - src/engine/platform/genesis.cpp | 7 - src/engine/platform/genesis.h | 2 - src/engine/platform/genesisext.cpp | 8 - src/engine/platform/mmc5.cpp | 7 - src/engine/platform/mmc5.h | 1 - src/engine/platform/msm6258.cpp | 19 - src/engine/platform/msm6258.h | 2 +- src/engine/platform/msm6295.cpp | 19 - src/engine/platform/msm6295.h | 1 - src/engine/platform/nes.cpp | 7 - src/engine/platform/nes.h | 1 - src/engine/platform/opl.cpp | 11 - src/engine/platform/opl.h | 5 +- src/engine/platform/pce.cpp | 7 - src/engine/platform/pce.h | 2 +- src/engine/platform/saa.cpp | 6 - src/engine/platform/saa.h | 7 - src/engine/platform/segapcm.cpp | 7 - src/engine/platform/segapcm.h | 1 - src/engine/platform/su.cpp | 1 - src/engine/platform/su.h | 2 +- src/engine/platform/swan.cpp | 7 - src/engine/platform/swan.h | 2 +- src/engine/platform/swan_before.cpp | 670 ---------------------------- src/engine/platform/swan_before.h | 90 ---- src/engine/platform/vrc6.cpp | 7 - src/engine/platform/vrc6.h | 1 - src/engine/platform/x1_010.cpp | 7 - src/engine/platform/x1_010.h | 1 - src/engine/platform/ym2203.cpp | 1 - src/engine/platform/ym2203.h | 1 - src/engine/platform/ym2608.cpp | 9 - src/engine/platform/ym2608.h | 4 +- src/engine/platform/ym2610.cpp | 34 +- src/engine/platform/ym2610b.cpp | 34 +- src/engine/platform/ym2610shared.h | 7 +- src/gui/debug.cpp | 11 - 41 files changed, 10 insertions(+), 1016 deletions(-) delete mode 100644 src/engine/platform/swan_before.cpp delete mode 100644 src/engine/platform/swan_before.h diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5506278a0..001989d34 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -928,12 +928,6 @@ int DivPlatformAY8910::dispatch(DivCommand c) { chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; } break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: chan[c.chan].dac.pos=c.value; chan[c.chan].dac.setPos=true; @@ -1064,7 +1058,6 @@ void DivPlatformAY8910::reset() { pendingWrites[i]=-1; } - sampleBank=0; ayEnvPeriod=0; ayEnvMode=0; ayEnvSlide=0; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index b488616d5..23f68e8dc 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -121,7 +121,6 @@ class DivPlatformAY8910: public DivDispatch { unsigned char regPool[16]; unsigned char lastBusy; - unsigned char sampleBank; unsigned char stereoSep; unsigned char selCore; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index aea1899fa..99f6f4b4e 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -750,12 +750,6 @@ int DivPlatformAY8930::dispatch(DivCommand c) { chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; } break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: chan[c.chan].dac.pos=c.value; chan[c.chan].dac.setPos=true; @@ -873,7 +867,6 @@ void DivPlatformAY8930::reset() { pendingWrites[i]=-1; } - sampleBank=0; ayNoiseAnd=2; ayNoiseOr=0; delay=0; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index a6ecc546a..230f63f84 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -111,8 +111,6 @@ class DivPlatformAY8930: public DivDispatch { unsigned char stereoSep; bool bank; - unsigned char sampleBank; - int delay; int lastOut[2]; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 10994ac0d..276b710e6 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -1283,13 +1283,6 @@ int DivPlatformGenesis::dispatch(DivCommand c) { rWrite(0x2b,c.value<<7); break; } - case DIV_CMD_SAMPLE_BANK: - if (c.chan<5) c.chan=5; - chan[c.chan].sampleBank=c.value; - if (chan[c.chan].sampleBank>(parent->song.sample.size()/12)) { - chan[c.chan].sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_DIR: { if (c.chan<5) c.chan=5; chan[c.chan].dacDirection=c.value; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 82495bdef..5293ef4df 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -46,7 +46,6 @@ class DivPlatformGenesis: public DivPlatformOPN { int dacDelay; bool dacDirection; bool setPos; - unsigned char sampleBank; signed char dacOutput; Channel(): FMChannelStereo(), @@ -59,7 +58,6 @@ class DivPlatformGenesis: public DivPlatformOPN { dacDelay(0), dacDirection(false), setPos(false), - sampleBank(0), dacOutput(0) {} }; Channel chan[10]; diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index c7c3e287b..02fa2be79 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -203,14 +203,6 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } break; } - case DIV_CMD_SAMPLE_BANK: - if (!parent->song.ignoreDACModeOutsideIntendedChannel) { - chan[5].sampleBank=c.value; - if (chan[5].sampleBank>(parent->song.sample.size()/12)) { - chan[5].sampleBank=parent->song.sample.size()/12; - } - } - break; case DIV_CMD_LEGATO: { if (opChan[ch].insChanged) { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 39fc57655..3b28c2ee7 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -304,12 +304,6 @@ int DivPlatformMMC5::dispatch(DivCommand c) { chan[c.chan].duty=c.value; rWrite(0x5000+c.chan*4,0x30|(chan[c.chan].active?chan[c.chan].outVol:0)|((chan[c.chan].duty&3)<<6)); break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: if (c.chan!=2) break; dacPos=c.value; @@ -403,7 +397,6 @@ void DivPlatformMMC5::reset() { dacPos=0; dacRate=0; dacSample=-1; - sampleBank=0; map_init_MMC5(mmc5); memset(regPool,0,128); diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 57e396c06..574f0684c 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -49,7 +49,6 @@ class DivPlatformMMC5: public DivDispatch { int dacPeriod, dacRate; unsigned int dacPos; int dacSample; - unsigned char sampleBank; unsigned char writeOscBuf; struct _mmc5* mmc5; unsigned char regPool[128]; diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index b78ce52d5..f54104144 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -185,18 +185,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { } else { break; } - } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)<0 || (12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - //DivSample* s=parent->getSample(12*sampleBank+c.value%12); - sample=12*sampleBank+c.value%12; - samplePos=0; - chan[c.chan].active=true; - chan[c.chan].keyOn=true; } break; } @@ -238,12 +226,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { case DIV_CMD_NOTE_PORTA: { return 2; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_FREQ: rateSel=c.value&3; rWrite(12,rateSel); @@ -360,7 +342,6 @@ void DivPlatformMSM6258::reset() { chan[i].outVol=8; } - sampleBank=0; sample=-1; samplePos=0; diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index de7191919..dde975d72 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -48,7 +48,7 @@ class DivPlatformMSM6258: public DivDispatch { FixedQueue writes; okim6258_device* msm; - unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel; + unsigned char msmPan, msmDivider, rateSel, msmClock, clockSel; signed char msmDividerCount, msmClockCount; bool updateSampleFreq; bool variableRate; diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 67e3390da..c2d4ef70b 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -186,18 +186,6 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { } else { break; } - } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)<0 || (12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - //DivSample* s=parent->getSample(12*sampleBank+c.value%12); - chan[c.chan].sample=12*sampleBank+c.value%12; - rWriteDelay(0,(8<(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_LEGATO: { break; } @@ -335,7 +317,6 @@ void DivPlatformMSM6295::reset() { chan[i].outVol=8; } - sampleBank=0; rateSel=rateSelInit; rWrite(12,!rateSelInit); if (isBanked) { diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index 5975e1216..3277a2f15 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -53,7 +53,6 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { unsigned char* adpcmMem; size_t adpcmMemLen; bool* sampleLoaded; - unsigned char sampleBank; int delay, updateOsc; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index d570020fc..bf035e7bc 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -737,12 +737,6 @@ int DivPlatformNES::dispatch(DivCommand c) { } break; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: if (c.chan!=4) break; dacPos=c.value; @@ -858,7 +852,6 @@ void DivPlatformNES::reset() { dpcmPos=0; dacRate=0; dacSample=-1; - sampleBank=0; dpcmBank=0; dpcmMode=dpcmModeDefault; goingToLoop=false; diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 51413d1a4..72ef7aa34 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -59,7 +59,6 @@ class DivPlatformNES: public DivDispatch { size_t dpcmMemLen; bool* sampleLoaded; unsigned char dpcmBank; - unsigned char sampleBank; unsigned char writeOscBuf; unsigned char apuType; unsigned char linearCount; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index dd879260d..3d01bb1bd 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -2128,14 +2128,6 @@ int DivPlatformOPL::dispatch(DivCommand c) { } break; } - case DIV_CMD_SAMPLE_BANK: - if (adpcmChan<0) break; - sampleBank=c.value; - if (sampleBank>(int)(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - iface.sampleBank=sampleBank; - break; case DIV_CMD_LEGATO: { // TODO: OPL4 PCM if (chan[c.chan].insChanged) { @@ -2908,7 +2900,6 @@ void DivPlatformOPL::reset() { lastBusy=60; lfoValue=8; drumState=0; - sampleBank=0; drumVol[0]=0; drumVol[1]=0; @@ -3471,7 +3462,6 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi adpcmBMem=new unsigned char[262144]; adpcmBMemLen=0; iface.adpcmBMem=adpcmBMem; - iface.sampleBank=0; adpcmB=new ymfm::adpcm_b_engine(iface,2); } @@ -3479,7 +3469,6 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi pcmMem=new unsigned char[4194304]; pcmMemLen=0; iface.pcmMem=pcmMem; - iface.sampleBank=0; pcmMemory.memory=pcmMem; } diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 9ba5dd3fe..adf9a6709 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -36,10 +36,9 @@ class DivOPLAInterface: public ymfm::ymfm_interface { public: unsigned char* adpcmBMem; unsigned char* pcmMem; - int sampleBank; uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); - DivOPLAInterface(): adpcmBMem(NULL), pcmMem(NULL), sampleBank(0) {} + DivOPLAInterface(): adpcmBMem(NULL), pcmMem(NULL) {} }; class DivYMF278MemoryInterface: public MemoryInterface { @@ -134,7 +133,7 @@ class DivPlatformOPL: public DivDispatch { const unsigned short* chanMap; const unsigned char* outChanMap; int chipFreqBase, chipRateBase; - int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan=-1, pcmChanOffs=-1, sampleBank, totalOutputs, ramSize; + int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan=-1, pcmChanOffs=-1, totalOutputs, ramSize; int fmMixL=7, fmMixR=7, pcmMixL=7, pcmMixR=7; unsigned char lastBusy; unsigned char drumState; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 46f1b9ac7..874e45457 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -466,12 +466,6 @@ int DivPlatformPCE::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_MODE: chan[c.chan].pcm=c.value; break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: chan[c.chan].dacPos=c.value; chan[c.chan].setPos=true; @@ -605,7 +599,6 @@ void DivPlatformPCE::reset() { pce->Power(0); lastPan=0xff; curChan=-1; - sampleBank=0; lfoMode=0; lfoSpeed=255; // set global volume diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 9f97beeca..5edbd371e 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -70,7 +70,7 @@ class DivPlatformPCE: public DivDispatch { unsigned char lastPan; int curChan; - unsigned char sampleBank, lfoMode, lfoSpeed; + unsigned char lfoMode, lfoSpeed; PCE_PSG* pce; unsigned char regPool[128]; void updateWave(int ch); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 01e98a882..624bde5bf 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -389,12 +389,6 @@ void DivPlatformSAA1099::reset() { } lastBusy=60; - dacMode=0; - dacPeriod=0; - dacPos=0; - dacRate=0; - dacSample=-1; - sampleBank=0; saaEnv[0]=0; saaEnv[1]=0; saaNoise[0]=0; diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 7f5c1565c..056e9a278 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -52,13 +52,6 @@ class DivPlatformSAA1099: public DivDispatch { CSAASound* saa_saaSound; unsigned char regPool[32]; unsigned char lastBusy; - - bool dacMode; - int dacPeriod; - int dacRate; - int dacPos; - int dacSample; - unsigned char sampleBank; int delay; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 5522b4b63..984765ea7 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -330,12 +330,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: chan[c.chan].pcm.pos=c.value; chan[c.chan].setPos=true; @@ -475,7 +469,6 @@ void DivPlatformSegaPCM::reset() { pcmCycles=0; pcmL=0; pcmR=0; - sampleBank=0; delay=0; pcm.device_start(); diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 068644a96..3eb0c8475 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -68,7 +68,6 @@ class DivPlatformSegaPCM: public DivDispatch { int delay; int pcmL, pcmR, pcmCycles; bool oldSlides; - unsigned char sampleBank; unsigned char lastBusy; unsigned char regPool[256]; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index d672995e7..84c84f6d1 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -612,7 +612,6 @@ void DivPlatformSoundUnit::reset() { lastPan=0xff; cycles=0; curChan=-1; - sampleBank=0; lfoMode=0; lfoSpeed=255; delay=500; diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 4e8bcc691..0ccfb4774 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -100,7 +100,7 @@ class DivPlatformSoundUnit: public DivDispatch { int cycles, curChan, delay, sysIDCache; short tempL; short tempR; - unsigned char sampleBank, lfoMode, lfoSpeed; + unsigned char lfoMode, lfoSpeed; SoundUnit* su; unsigned char* sampleMem; size_t sampleMemLen; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 9d434101c..03d285ff5 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -527,12 +527,6 @@ int DivPlatformSwan::dispatch(DivCommand c) { } } break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: dacPos=c.value; setPos=true; @@ -665,7 +659,6 @@ void DivPlatformSwan::reset() { dacRate=0; dacPos=0; dacSample=-1; - sampleBank=0; rWrite(0x0f,0x00); // wave table at 0x0000 rWrite(0x11,0x0f); // enable speakers, minimum headphone volume } diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index e3ea745f9..6b8773e94 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -42,7 +42,7 @@ class DivPlatformSwan: public DivDispatch { bool stereo; bool useMdfn; bool pcm, sweep, furnaceDac, setPos; - unsigned char sampleBank, noise; + unsigned char noise; int dacPeriod, dacRate; unsigned int dacPos; int dacSample; diff --git a/src/engine/platform/swan_before.cpp b/src/engine/platform/swan_before.cpp deleted file mode 100644 index 79cfbd695..000000000 --- a/src/engine/platform/swan_before.cpp +++ /dev/null @@ -1,670 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2025 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 "swan_before.h" -#include "../engine.h" -#include "furIcons.h" -#include "IconsFontAwesome4.h" -#include - -#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);}} -#define postWrite(a,v) postDACWrites.push(DivRegWrite(a,v)); - -#define CHIP_DIVIDER 32 - -const char* regCheatSheetWS[]={ - "CH1_Pitch", "00", - "CH2_Pitch", "02", - "CH3_Pitch", "04", - "CH4_Pitch", "06", - "CH1_Vol", "08", - "CH2_Vol", "09", - "CH3_Vol", "0A", - "CH4_Vol", "0B", - "Sweep_Value", "0C", - "Sweep_Time", "0D", - "Noise", "0E", - "Wave_Base", "0F", - "Ctrl", "10", - "Output", "11", - "Random", "12", - "Voice_Ctrl", "14", - "Wave_Mem", "40", - NULL -}; - -const char** DivPlatformSwan::getRegisterSheet() { - return regCheatSheetWS; -} - -void DivPlatformSwan::acquireDirect(blip_buffer_t** bb, size_t len) { - for (int i=0; i<4; i++) { - oscBuf[i]->begin(len); - ws_mdfn->oscBuf[i]=oscBuf[i]; - } - - ws_mdfn->sbuf[0]=bb[0]; - ws_mdfn->sbuf[1]=bb[1]; - - for (size_t h=0; hv30mz_timestamp=h; - // heuristic - int pcmAdvance=1; - if (writes.empty()) { - if (!pcm || dacSample==-1) { - break; - } else { - pcmAdvance=len-h; - if (dacRate>0) { - int remainTime=(rate-dacPeriod+dacRate-1)/dacRate; - if (remainTime=rate) { - DivSample* s=parent->getSample(dacSample); - if (s->samples<=0 || dacPos>=s->samples) { - dacSample=-1; - dacPeriod=0; - break; - } - rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { - dacPos=s->loopStart; - } else if (dacPos>=s->samples) { - dacSample=-1; - } - dacPeriod-=rate; - } - } - - h+=pcmAdvance-1; - - // the rest - while (!writes.empty()) { - QueuedWrite w=writes.front(); - regPool[w.addr]=w.val; - if (w.addr<0x40) { - ws_mdfn->SoundWrite(w.addr|0x80,w.val); - } else { - ws_mdfn->SoundCheckRAMWrite(w.addr&0x3f); - ws_mdfn->RAMWrite(w.addr&0x3f,w.val); - } - writes.pop(); - } - } - - ws_mdfn->v30mz_timestamp=len; - ws_mdfn->SoundUpdate(); - ws_mdfn->SoundFlush(NULL,0); - - for (int i=0; i<4; i++) { - oscBuf[i]->end(len); - } -} - -void DivPlatformSwan::updateWave(int ch) { - unsigned char addr=0x40+ch*16; - for (int i=0; i<16; i++) { - int nibble1=chan[ch].ws.output[i<<1]; - int nibble2=chan[ch].ws.output[1+(i<<1)]; - rWrite(addr+i,nibble1|(nibble2<<4)); - } -} - -void DivPlatformSwan::calcAndWriteOutVol(int ch, int env) { - int vl=chan[ch].vol*((chan[ch].pan>>4)&0x0f)*env/225; - int vr=chan[ch].vol*(chan[ch].pan&0x0f)*env/225; - if (ch==1&&pcm) { - vl=(vl>0)?((vl>7)?3:2):0; - vr=(vr>0)?((vr>7)?3:2):0; - chan[1].outVol=vr|(vl<<2); - } else { - chan[ch].outVol=vr|(vl<<4); - } - writeOutVol(ch); -} - -void DivPlatformSwan::writeOutVol(int ch) { - unsigned char val=isMuted[ch]?0:chan[ch].outVol; - if (ch==1&&pcm) { - rWrite(0x14,val) - } else { - rWrite(0x08+ch,val); - } -} - -void DivPlatformSwan::tick(bool sysTick) { - unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0); - for (int i=0; i<4; i++) { - chan[i].std.next(); - if (chan[i].std.vol.had) { - int env=chan[i].std.vol.val; - if(parent->getIns(chan[i].ins,DIV_INS_SWAN)->type==DIV_INS_AMIGA) { - env=MIN(env/4,15); - } - calcAndWriteOutVol(i,env); - } - if (NEW_ARP_STRAT) { - chan[i].handleArp(); - } else if (chan[i].std.arp.had) { - if (!chan[i].inPorta) { - chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val)); - } - chan[i].freqChanged=true; - } - if (chan[i].std.wave.had && !(i==1 && pcm)) { - if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { - chan[i].wave=chan[i].std.wave.val; - chan[i].ws.changeWave1(chan[i].wave); - } - } - if (chan[i].std.panL.had) { - chan[i].pan&=0x0f; - chan[i].pan|=(chan[i].std.panL.val&15)<<4; - } - if (chan[i].std.panR.had) { - chan[i].pan&=0xf0; - chan[i].pan|=chan[i].std.panR.val&15; - } - if (chan[i].std.panL.had || chan[i].std.panR.had) { - calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15); - } - if (chan[i].std.pitch.had) { - if (chan[i].std.pitch.mode) { - chan[i].pitch2+=chan[i].std.pitch.val; - CLAMP_VAR(chan[i].pitch2,-32768,32767); - } else { - chan[i].pitch2=chan[i].std.pitch.val; - } - chan[i].freqChanged=true; - } - if (chan[i].active) { - sndCtrl|=(1<calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (i==1 && pcm && furnaceDac) { - double off=1.0; - if (dacSample>=0 && dacSamplesong.sampleLen) { - DivSample* s=parent->getSample(dacSample); - if (s->centerRate<1) { - off=1.0; - } else { - off=parent->getCenterRate()/(double)s->centerRate; - } - } - dacRate=((double)chipClock/2)/MAX(1,off*chan[i].freq); - if (dumpWrites) postWrite(0xffff0001,dacRate); - } - if (chan[i].freq>2048) chan[i].freq=2048; - if (chan[i].freq<1) chan[i].freq=1; - int rVal=2048-chan[i].freq; - rWrite(i*2,rVal&0xff); - rWrite(i*2+1,rVal>>8); - if (chan[i].keyOn) { - if (!chan[i].std.vol.will) { - calcAndWriteOutVol(i,15); - } - chan[i].keyOn=false; - } - if (chan[i].keyOff) { - chan[i].keyOff=false; - } - chan[i].freqChanged=false; - } - } - if (chan[3].std.duty.had) { - if (noise!=chan[3].std.duty.val) { - noise=chan[3].std.duty.val; - if (noise>0) { - rWrite(0x0e,((noise-1)&0x07)|0x18); - sndCtrl|=0x80; - } else { - sndCtrl&=~0x80; - } - } - } - if (chan[3].std.phaseReset.had) { - if (noise>0) { - rWrite(0x0e,((noise-1)&0x07)|0x18); - sndCtrl|=0x80; - } else { - sndCtrl&=~0x80; - } - } - unsigned char origSndCtrl=sndCtrl; - bool phaseResetHappens=false; - for (int i=0; i<4; i++) { - if (chan[i].std.phaseReset.had) { - phaseResetHappens=true; - sndCtrl&=~(1<getIns(chan[c.chan].ins,DIV_INS_SWAN); - if (c.chan==1) { - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - pcm=true; - } else if (furnaceDac) { - pcm=false; - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - } - if (pcm) { - if (skipRegisterWrites) break; - if (setPos) { - setPos=false; - } else { - dacPos=0; - } - dacPeriod=0; - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - if (c.value!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (dacSample<0 || dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) postWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) { - postWrite(0xffff0000,dacSample); - } - } - if (c.value!=DIV_NOTE_NULL) { - chan[1].baseFreq=NOTE_PERIODIC(c.value); - chan[1].freqChanged=true; - chan[1].note=c.value; - } - chan[1].active=true; - chan[1].keyOn=true; - chan[1].macroInit(ins); - furnaceDac=true; - } else { - if (c.value!=DIV_NOTE_NULL) { - chan[1].note=c.value; - } - dacSample=12*sampleBank+chan[1].note%12; - if (dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) postWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) postWrite(0xffff0000,dacSample); - } - dacRate=parent->getSample(dacSample)->rate; - if (dumpWrites) { - postWrite(0xffff0001,dacRate); - } - chan[1].active=true; - chan[1].keyOn=true; - furnaceDac=false; - } - break; - } - } - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_PERIODIC(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].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - if (chan[c.chan].wave<0) { - chan[c.chan].wave=0; - chan[c.chan].ws.changeWave1(chan[c.chan].wave); - } - chan[c.chan].ws.init(ins,32,15,chan[c.chan].insChanged); - chan[c.chan].insChanged=false; - break; - } - case DIV_CMD_NOTE_OFF: - if (c.chan==1&&pcm) { - dacSample=-1; - if (dumpWrites) postWrite(0xffff0002,0); - pcm=false; - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - } - chan[c.chan].active=false; - chan[c.chan].keyOff=true; - chan[c.chan].macroInit(NULL); - break; - case DIV_CMD_NOTE_OFF_ENV: - 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].ins=c.value; - chan[c.chan].insChanged=true; - } - 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) { - calcAndWriteOutVol(c.chan,15); - } - } - break; - case DIV_CMD_GET_VOLUME: - return chan[c.chan].vol; - break; - case DIV_CMD_PITCH: - chan[c.chan].pitch=c.value; - chan[c.chan].freqChanged=true; - break; - case DIV_CMD_WAVE: - chan[c.chan].wave=c.value; - chan[c.chan].ws.changeWave1(chan[c.chan].wave); - chan[c.chan].keyOn=true; - break; - case DIV_CMD_WS_SWEEP_TIME: - if (c.chan==2) { - if (c.value==0) { - sweep=false; - } else { - sweep=true; - rWrite(0x0d,(c.value-1)&0xff); - } - } - break; - case DIV_CMD_WS_SWEEP_AMOUNT: - if (c.chan==2) { - rWrite(0x0c,c.value&0xff); - } - break; - case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta); - 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_STD_NOISE_MODE: - if (c.chan==3) { - noise=c.value&0xff; - if (noise>0) rWrite(0x0e,((noise-1)&0x07)|0x18); - } - break; - case DIV_CMD_SAMPLE_MODE: - if (c.chan==1) { - pcm=c.value; - if (!pcm) { - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; - } - } - break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; - case DIV_CMD_SAMPLE_POS: - dacPos=c.value; - setPos=true; - break; - case DIV_CMD_PANNING: { - chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4); - calcAndWriteOutVol(c.chan,chan[c.chan].std.vol.will?chan[c.chan].std.vol.val:15); - break; - } - case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((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) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); - } - if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); - chan[c.chan].inPorta=c.value; - break; - case DIV_CMD_GET_VOLMAX: - return 15; - 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 DivPlatformSwan::muteChannel(int ch, bool mute) { - isMuted[ch]=mute; - writeOutVol(ch); -} - -void DivPlatformSwan::forceIns() { - noise=0; - for (int i=0; i<4; i++) { - chan[i].insChanged=true; - chan[i].freqChanged=true; - updateWave(i); - writeOutVol(i); - } -} - -void* DivPlatformSwan::getChanState(int ch) { - return &chan[ch]; -} - -DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) { - return &chan[ch].std; -} - -unsigned short DivPlatformSwan::getPan(int ch) { - return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); -} - -DivChannelModeHints DivPlatformSwan::getModeHints(int ch) { - DivChannelModeHints ret; - - switch (ch) { - case 1: // PCM - ret.count=1; - ret.hint[0]=ICON_FA_VOLUME_UP; - ret.type[0]=pcm?4:0; - break; - case 2: // sweep - ret.count=1; - ret.hint[0]=ICON_FUR_SAW; - ret.type[0]=sweep?2:0; - break; - case 3: // noise - ret.count=1; - ret.hint[0]=ICON_FUR_NOISE; - ret.type[0]=noise?4:0; - break; - } - - return ret; -} - -DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) { - return oscBuf[ch]; -} - -unsigned char* DivPlatformSwan::getRegisterPool() { - // get Random from emulator - regPool[0x12]=ws_mdfn->SoundRead(0x92); - regPool[0x13]=ws_mdfn->SoundRead(0x93); - return regPool; -} - -int DivPlatformSwan::getRegisterPoolSize() { - return 128; -} - -void DivPlatformSwan::reset() { - while (!writes.empty()) writes.pop(); - while (!postDACWrites.empty()) postDACWrites.pop(); - memset(regPool,0,128); - for (int i=0; i<4; i++) { - chan[i]=Channel(); - chan[i].vol=15; - chan[i].pan=0xff; - chan[i].std.setEngine(parent); - chan[i].ws.setEngine(parent); - chan[i].ws.init(NULL,32,15,false); - rWrite(0x08+i,0xff); - } - if (dumpWrites) { - addWrite(0xffffffff,0); - } - ws_mdfn->SoundReset(); - pcm=false; - sweep=false; - furnaceDac=false; - setPos=false; - noise=0; - dacPeriod=0; - dacRate=0; - dacPos=0; - dacSample=-1; - sampleBank=0; - rWrite(0x0f,0x00); // wave table at 0x0000 - rWrite(0x11,0x09); // enable speakers -} - -int DivPlatformSwan::getOutputCount() { - return 2; -} - -bool DivPlatformSwan::hasAcquireDirect() { - return true; -} - -void DivPlatformSwan::notifyWaveChange(int wave) { - for (int i=0; i<4; i++) { - if (chan[i].wave==wave) { - chan[i].ws.changeWave1(wave); - updateWave(i); - } - } -} - -void DivPlatformSwan::notifyInsDeletion(void* ins) { - for (int i=0; i<4; i++) { - chan[i].std.notifyInsDeletion((DivInstrument*)ins); - } -} - -void DivPlatformSwan::poke(unsigned int addr, unsigned short val) { - rWrite(addr,val); -} - -void DivPlatformSwan::poke(std::vector& wlist) { - for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); -} - -void DivPlatformSwan::setFlags(const DivConfig& flags) { - chipClock=3072000; - CHECK_CUSTOM_CLOCK; - rate=chipClock; - for (int i=0; i<4; i++) { - oscBuf[i]->setRate(rate); - } -} - -int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { - parent=p; - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<4; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - ws_mdfn=new WSwan(); - setFlags(flags); - reset(); - return 4; -} - -void DivPlatformSwan::quit() { - for (int i=0; i<4; i++) { - delete oscBuf[i]; - } - delete ws_mdfn; -} - -DivPlatformSwan::~DivPlatformSwan() { -} diff --git a/src/engine/platform/swan_before.h b/src/engine/platform/swan_before.h deleted file mode 100644 index 63508f163..000000000 --- a/src/engine/platform/swan_before.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2025 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _SWAN_H -#define _SWAN_H - -#include "../dispatch.h" -#include "../waveSynth.h" -#include "sound/swan_mdfn.h" -#include "../../fixedQueue.h" - -class DivPlatformSwan: public DivDispatch { - struct Channel: public SharedChannel { - unsigned char pan; - int wave; - DivWaveSynth ws; - Channel(): - SharedChannel(15), - pan(255), - wave(-1) {} - }; - Channel chan[4]; - DivDispatchOscBuffer* oscBuf[4]; - bool isMuted[4]; - bool pcm, sweep, furnaceDac, setPos; - unsigned char sampleBank, noise; - int dacPeriod, dacRate; - unsigned int dacPos; - int dacSample; - - unsigned char regPool[0x80]; - 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; - FixedQueue postDACWrites; - WSwan* ws_mdfn; - void updateWave(int ch); - friend void putDispatchChip(void*,int); - friend void putDispatchChan(void*,int,int); - public: - void acquireDirect(blip_buffer_t** bb, size_t len); - int dispatch(DivCommand c); - void* getChanState(int chan); - DivMacroInt* getChanMacroInt(int ch); - unsigned short getPan(int chan); - DivChannelModeHints getModeHints(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 notifyWaveChange(int wave); - void notifyInsDeletion(void* ins); - int getOutputCount(); - bool hasAcquireDirect(); - 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); - void quit(); - ~DivPlatformSwan(); - private: - void calcAndWriteOutVol(int ch, int env); - void writeOutVol(int ch); -}; - -#endif diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index ee6a95b4d..18a7be76a 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -407,12 +407,6 @@ int DivPlatformVRC6::dispatch(DivCommand c) { } } break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_SAMPLE_POS: chan[c.chan].dacPos=c.value; chan[c.chan].setPos=true; @@ -510,7 +504,6 @@ void DivPlatformVRC6::reset() { addWrite(0xffffffff,0); } - sampleBank=0; prevSample=0; vrc6.reset(); diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 6751e9389..eb4a6eecc 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -54,7 +54,6 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {} }; FixedQueue writes; - unsigned char sampleBank; vrcvi_core vrc6; int prevSample; unsigned char regPool[13]; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 00683f56d..36f0d26ee 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -711,12 +711,6 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].envChanged=true; } break; - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_PANNING: { if (!stereo) break; unsigned char newPan=(c.value&0xf0)|(c.value2>>4); @@ -891,7 +885,6 @@ void DivPlatformX1_010::reset() { chan[i].ws.init(NULL,128,255,false); } x1_010.reset(); - sampleBank=0; // set per-channel initial panning for (int i=0; i<16; i++) { chWrite(i,0,0); diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 7800dbc47..e16f51f3f 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -112,7 +112,6 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf { bool stereo=false; unsigned char* sampleMem; size_t sampleMemLen; - unsigned char sampleBank; x1_010_core x1_010; bool isBanked=false; diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 1d1f240c2..98fd77a36 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -1328,7 +1328,6 @@ void DivPlatformYM2203::reset() { } lastBusy=60; - sampleBank=0; delay=0; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 0166d7a85..123c371ba 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -55,7 +55,6 @@ class DivPlatformYM2203: public DivPlatformOPN { bool lastS; DivPlatformAY8910* ay; - unsigned char sampleBank; bool extMode, noExtMacros; unsigned char prescale, nukedMult; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 71d7d5b71..3897e9cc5 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1392,13 +1392,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) { PLEASE_HELP_ME(chan[c.chan],chan[c.chan].state.block); break; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - iface.sampleBank=sampleBank; - break; case DIV_CMD_LEGATO: { if (c.chan==csmChan) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); @@ -1884,7 +1877,6 @@ void DivPlatformYM2608::reset() { lastBusy=60; lfoValue=8; - sampleBank=0; writeRSSOff=0; writeRSSOn=0; globalRSSVolume=0x3f; @@ -2087,7 +2079,6 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, const DivCo adpcmBMem=new unsigned char[getSampleMemCapacity(0)]; adpcmBMemLen=0; iface.adpcmBMem=adpcmBMem; - iface.sampleBank=0; dumpWrites=false; skipRegisterWrites=false; for (int i=0; i<17; i++) { diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 3bc09fa5d..46908e881 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -31,10 +31,9 @@ extern "C" { class DivYM2608Interface: public DivOPNInterface { public: unsigned char* adpcmBMem; - int sampleBank; uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); - DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {} + DivYM2608Interface(): adpcmBMem(NULL) {} }; class DivPlatformYM2608: public DivPlatformOPN { @@ -71,7 +70,6 @@ class DivPlatformYM2608: public DivPlatformOPN { bool* sampleLoaded; DivPlatformAY8910* ay; - unsigned char sampleBank; unsigned char writeRSSOff, writeRSSOn; int globalRSSVolume; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index fa0b4e3c3..1a050d1ac 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -1156,31 +1156,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); - immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); - int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; - immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); - immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); - immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); - immWrite(0x110+c.chan-adpcmAChanOffs,0); - immWrite(0x118+c.chan-adpcmAChanOffs,0); - immWrite(0x120+c.chan-adpcmAChanOffs,0); - immWrite(0x128+c.chan-adpcmAChanOffs,0); - break; - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } @@ -1352,13 +1328,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) { PLEASE_HELP_ME(chan[c.chan],chan[c.chan].state.block); break; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - iface.sampleBank=sampleBank; - break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; if (c.chan==csmChan) { @@ -1792,7 +1761,6 @@ void DivPlatformYM2610::reset() { lastBusy=60; lfoValue=8; - sampleBank=0; DivPlatformYM2610Base::reset(); delay=0; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 71eb8a100..8fe8b61dc 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -1225,31 +1225,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); - chan[c.chan].outVol=chan[c.chan].vol; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; - } - chan[c.chan].sample=12*sampleBank+c.value%12; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); - immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); - int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; - immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); - immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); - immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); - immWrite(0x110+c.chan-adpcmAChanOffs,0); - immWrite(0x118+c.chan-adpcmAChanOffs,0); - immWrite(0x120+c.chan-adpcmAChanOffs,0); - immWrite(0x128+c.chan-adpcmAChanOffs,0); - break; - } + assert(false && "LEGACY SAMPLE MODE!!!"); } break; } @@ -1421,13 +1397,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { PLEASE_HELP_ME(chan[c.chan],chan[c.chan].state.block); break; } - case DIV_CMD_SAMPLE_BANK: - sampleBank=c.value; - if (sampleBank>(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - iface.sampleBank=sampleBank; - break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; if (c.chan==csmChan) { @@ -1861,7 +1830,6 @@ void DivPlatformYM2610B::reset() { lastBusy=60; lfoValue=8; - sampleBank=0; DivPlatformYM2610Base::reset(); delay=0; diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 9db752d6a..d3add1723 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -38,13 +38,11 @@ class DivYM2610Interface: public DivOPNInterface { public: unsigned char* adpcmAMem; unsigned char* adpcmBMem; - int sampleBank; uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); DivYM2610Interface(): adpcmAMem(NULL), - adpcmBMem(NULL), - sampleBank(0) {} + adpcmBMem(NULL) {} }; class DivPlatformYM2610Base: public DivPlatformOPN { @@ -78,8 +76,6 @@ class DivPlatformYM2610Base: public DivPlatformOPN { unsigned int* sampleOffA; unsigned int* sampleOffB; - unsigned char sampleBank; - bool extMode, noExtMacros; bool* sampleLoaded[2]; @@ -343,7 +339,6 @@ class DivPlatformYM2610Base: public DivPlatformOPN { adpcmBMemLen=0; iface.adpcmAMem=adpcmAMem; iface.adpcmBMem=adpcmBMem; - iface.sampleBank=0; fm=new ymfm::ym2610b(iface); fm->set_fidelity(ymfm::OPN_FIDELITY_MED); setFlags(flags); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 9097c2dcf..40cfb5dc1 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -103,7 +103,6 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ ImGui::Text("- globalADPCMAVolume: %d",ch->globalADPCMAVolume); \ @@ -164,7 +163,6 @@ ImGui::Text(" - output: %d",ch->dacOutput); \ ImGui::Text("- pan: %x",ch->pan); \ ImGui::Text("- opMask: %x",ch->opMask); \ - ImGui::Text("- sampleBank: %d",ch->sampleBank); \ COMMON_CHAN_DEBUG_BOOL; \ ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \ ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ @@ -265,7 +263,6 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2203* ch=(DivPlatformYM2203*)data; ImGui::Text("> YM2203"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- prescale: %d",ch->prescale); FM_OPN_CHIP_DEBUG_BOOL; ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); @@ -276,7 +273,6 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); ImGui::Text("- globalRSSVolume: %d",ch->globalRSSVolume); @@ -318,7 +314,6 @@ void putDispatchChip(void* data, int type) { COMMON_CHIP_DEBUG; ImGui::Text("- lastPan: %d",ch->lastPan); ImGui::Text("- curChan: %d",ch->curChan); - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- lfoMode: %d",ch->lfoMode); ImGui::Text("- lfoSpeed: %d",ch->lfoSpeed); COMMON_CHIP_DEBUG_BOOL; @@ -336,7 +331,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); ImGui::Text("- apuType: %d",ch->apuType); COMMON_CHIP_DEBUG_BOOL; @@ -380,7 +374,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text("- pcmL: %d",ch->pcmL); ImGui::Text("- pcmR: %d",ch->pcmR); ImGui::Text("- pcmCycles: %d",ch->pcmCycles); - ImGui::Text("- sampleBank: %d",ch->sampleBank); COMMON_CHIP_DEBUG_BOOL; break; } @@ -388,7 +381,6 @@ void putDispatchChip(void* data, int type) { DivPlatformAY8910* ch=(DivPlatformAY8910*)data; ImGui::Text("> AY-3-8910"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- stereoSep: %d",ch->stereoSep); ImGui::Text("- delay: %d",ch->delay); ImGui::Text("- extClock: %d",ch->extClock); @@ -417,7 +409,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* noise:"); ImGui::Text(" - and: %d",ch->ayNoiseAnd); ImGui::Text(" - or: %d",ch->ayNoiseOr); - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- stereoSep: %d",ch->stereoSep); ImGui::Text("- delay: %d",ch->delay); ImGui::Text("- portAVal: %d",ch->portAVal); @@ -445,7 +436,6 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); @@ -468,7 +458,6 @@ void putDispatchChip(void* data, int type) { DivPlatformVRC6* ch=(DivPlatformVRC6*)data; ImGui::Text("> VRC6"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleBank: %.2x",ch->sampleBank); COMMON_CHIP_DEBUG_BOOL; break; } From 4b1605f2c2bd3c63db62f449646d996d71f23bde Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 16:11:03 -0500 Subject: [PATCH 09/25] horrible build failure --- src/engine/platform/ay.h | 3 +-- src/engine/platform/ay8930.h | 3 +-- src/engine/platform/fmshared_OPN.h | 2 -- src/engine/platform/genesis.h | 2 -- src/engine/platform/mmc5.h | 3 +-- src/gui/newFilePicker.cpp | 2 +- 6 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 23f68e8dc..04fff3d71 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -65,7 +65,7 @@ class DivPlatformAY8910: public DivDispatch { struct DAC { int sample, rate, period, pos, out; - bool furnaceDAC, setPos; + bool setPos; DAC(): sample(-1), @@ -73,7 +73,6 @@ class DivPlatformAY8910: public DivDispatch { period(0), pos(0), out(0), - furnaceDAC(false), setPos(false) {} } dac; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 230f63f84..6e8fc61fc 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -65,7 +65,7 @@ class DivPlatformAY8930: public DivDispatch { struct DAC { int sample, rate, period, pos, out; - bool furnaceDAC, setPos; + bool setPos; DAC(): sample(-1), @@ -73,7 +73,6 @@ class DivPlatformAY8930: public DivDispatch { period(0), pos(0), out(0), - furnaceDAC(false), setPos(false) {} } dac; diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 2b301dd6a..ca3542b40 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -120,7 +120,6 @@ class DivPlatformOPN: public DivPlatformFMBase { struct OPNChannel: public FMChannel { unsigned char psgMode, autoEnvNum, autoEnvDen; - bool furnacePCM; int sample, macroVolMul; OPNChannel(): @@ -128,7 +127,6 @@ class DivPlatformOPN: public DivPlatformFMBase { psgMode(1), autoEnvNum(0), autoEnvDen(0), - furnacePCM(false), sample(-1), macroVolMul(255) {} }; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 5293ef4df..ffb5186fb 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -37,7 +37,6 @@ class DivPlatformGenesis: public DivPlatformOPN { }; struct Channel: public FMChannelStereo { - bool furnaceDac; bool dacMode; int dacPeriod; int dacRate; @@ -49,7 +48,6 @@ class DivPlatformGenesis: public DivPlatformOPN { signed char dacOutput; Channel(): FMChannelStereo(), - furnaceDac(false), dacMode(false), dacPeriod(0), dacRate(0), diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 574f0684c..54669a953 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -26,14 +26,13 @@ class DivPlatformMMC5: public DivDispatch { struct Channel: public SharedChannel { int prevFreq; unsigned char duty, sweep; - bool sweepChanged, furnaceDac, setPos; + bool sweepChanged, setPos; Channel(): SharedChannel(15), prevFreq(65535), duty(0), sweep(8), sweepChanged(false), - furnaceDac(false), setPos(false) {} }; Channel chan[5]; diff --git a/src/gui/newFilePicker.cpp b/src/gui/newFilePicker.cpp index 517a74d47..b017d8d9c 100644 --- a/src/gui/newFilePicker.cpp +++ b/src/gui/newFilePicker.cpp @@ -1603,7 +1603,7 @@ bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) { } // OK/Cancel buttons - ImGui::BeginDisabled(entryName.empty() && chosenEntries.empty()); + ImGui::BeginDisabled(entryName.empty() && chosenEntries.empty() && !dirSelect); if (ImGui::Button(_("OK"))) { // accept entry acknowledged=true; From 4525e05ec1e0442c41bb9963d5e4e5abb2279ebe Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 18:14:08 -0500 Subject: [PATCH 10/25] fix instrument saving --- src/engine/instrument.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index d16bf840a..d013e917d 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -886,7 +886,7 @@ size_t DivInstrument::writeFeatureLS(SafeWriter* w, std::vector& list, cons if (list.empty()) return 0; - FEATURE_BEGIN("SL"); + FEATURE_BEGIN("LS"); w->writeS(list.size()); @@ -935,7 +935,7 @@ size_t DivInstrument::writeFeatureLW(SafeWriter* w, std::vector& list, cons if (list.empty()) return 0; - FEATURE_BEGIN("WL"); + FEATURE_BEGIN("LW"); w->writeS(list.size()); @@ -2832,7 +2832,7 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b } else if (memcmp(featCode,"S3",2)==0) { // SID3 readFeatureS3(reader,version); } else { - if (song==NULL && (memcmp(featCode,"SL",2)==0 || (memcmp(featCode,"WL",2)==0))) { + if (song==NULL && (memcmp(featCode,"SL",2)==0 || (memcmp(featCode,"WL",2)==0) || (memcmp(featCode,"LS",2)==0) || (memcmp(featCode,"LW",2)==0))) { // nothing } else { logW("unknown feature code %c%c!",featCode[0],featCode[1]); From d9e23053180013fa92fb02e92d10f434f67e92df Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 18:14:18 -0500 Subject: [PATCH 11/25] file picker: fix directory selection --- src/gui/newFilePicker.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gui/newFilePicker.cpp b/src/gui/newFilePicker.cpp index 517a74d47..12afb3af8 100644 --- a/src/gui/newFilePicker.cpp +++ b/src/gui/newFilePicker.cpp @@ -1603,7 +1603,7 @@ bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) { } // OK/Cancel buttons - ImGui::BeginDisabled(entryName.empty() && chosenEntries.empty()); + ImGui::BeginDisabled(entryName.empty() && chosenEntries.empty() && !dirSelect); if (ImGui::Button(_("OK"))) { // accept entry acknowledged=true; @@ -1757,6 +1757,20 @@ bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) { } } } + } else { + if (dirSelect) { + finalSelection.push_back(path); + curStatus=FP_STATUS_ACCEPTED; + if (noClose) { + for (FileEntry* j: chosenEntries) { + j->isSelected=false; + } + chosenEntries.clear(); + updateEntryName(); + } else { + isOpen=false; + } + } } } } From 684d041dbbb3f85fd79ab510640cba3b73e4b3bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 18:30:48 -0500 Subject: [PATCH 12/25] SN: mega-optimization --- src/engine/platform/sms.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index b046f69df..636cf6560 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -142,6 +142,7 @@ void DivPlatformSMS::acquire_mame(blip_buffer_t** bb, size_t len) { // wahahaha heuristic... int advance=len-h; for (int i=0; i<4; i++) { + if (sn->m_volume[i]==0) continue; if (sn->m_count[i]m_count[i]; } if (advance<1) advance=1; From 183526cdbd4ae322e6bc397412644920b1a2d295 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 20:05:52 -0500 Subject: [PATCH 13/25] total extinction of legacy sample mode, part 3 remove all the code which handles legacy sample mode next up is a conversion strategy --- src/engine/platform/ay.cpp | 81 +++++----- src/engine/platform/ay8930.cpp | 79 +++++----- src/engine/platform/genesis.cpp | 21 +-- src/engine/platform/mmc5.cpp | 75 ++++----- src/engine/platform/msm6258.cpp | 33 ++-- src/engine/platform/msm6258.h | 2 - src/engine/platform/msm6295.cpp | 37 ++--- src/engine/platform/msm6295.h | 2 - src/engine/platform/nes.cpp | 242 ++++++++++++++--------------- src/engine/platform/nes.h | 3 +- src/engine/platform/opl.cpp | 102 ++++++------ src/engine/platform/opl.h | 3 +- src/engine/platform/opll.h | 2 - src/engine/platform/pce.cpp | 80 +++++----- src/engine/platform/pce.h | 3 +- src/engine/platform/swan.cpp | 60 ++++---- src/engine/platform/swan.h | 2 +- src/engine/platform/ym2608.cpp | 209 +++++++++++-------------- src/engine/platform/ym2610.cpp | 265 +++++++++++++++----------------- src/engine/platform/ym2610b.cpp | 265 +++++++++++++++----------------- src/gui/debug.cpp | 10 -- 21 files changed, 706 insertions(+), 870 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 001989d34..f32437737 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -598,7 +598,7 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (chan[i].dac.furnaceDAC) { + if (chan[i].curPSGMode.val&8) { double off=1.0; if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].dac.sample); @@ -677,54 +677,49 @@ int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); - if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].nextPSGMode.val|=8; - } else if (chan[c.chan].dac.furnaceDAC) { + } else { chan[c.chan].nextPSGMode.val&=~8; } if (chan[c.chan].nextPSGMode.val&8) { if (skipRegisterWrites) break; - if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].dac.sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { - chan[c.chan].dac.sample=-1; - //if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) { - rWrite(0x08+c.chan,0); - //addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); - } - } - if (chan[c.chan].dac.setPos) { - chan[c.chan].dac.setPos=false; - } else { - chan[c.chan].dac.pos=0; - } - chan[c.chan].dac.period=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - //chan[c.chan].keyOn=true; - chan[c.chan].dac.furnaceDAC=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); } + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + //if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + //addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + if (chan[c.chan].dac.setPos) { + chan[c.chan].dac.setPos=false; + } else { + chan[c.chan].dac.pos=0; + } + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + //chan[c.chan].keyOn=true; chan[c.chan].curPSGMode.val&=~8; chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; break; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 99f6f4b4e..653ffdc13 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -402,7 +402,7 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (chan[i].dac.furnaceDAC) { + if (chan[i].curPSGMode.val&8) { double off=1.0; if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].dac.sample); @@ -507,52 +507,47 @@ int DivPlatformAY8930::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930); if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].nextPSGMode.val|=8; - } else if (chan[c.chan].dac.furnaceDAC) { + } else { chan[c.chan].nextPSGMode.val&=~8; } if (chan[c.chan].nextPSGMode.val&8) { if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].dac.sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { - chan[c.chan].dac.sample=-1; - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) { - rWrite(0x08+c.chan,0); - addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); - } - } - if (chan[c.chan].dac.setPos) { - chan[c.chan].dac.setPos=false; - } else { - chan[c.chan].dac.pos=0; - } - chan[c.chan].dac.period=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - //chan[c.chan].keyOn=true; - chan[c.chan].dac.furnaceDAC=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); } + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + if (chan[c.chan].dac.setPos) { + chan[c.chan].dac.setPos=false; + } else { + chan[c.chan].dac.pos=0; + } + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + //chan[c.chan].keyOn=true; chan[c.chan].curPSGMode.val&=~8; chan[c.chan].curPSGMode.val|=chan[c.chan].nextPSGMode.val&8; break; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 276b710e6..65651fac6 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -681,7 +681,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (chan[i].std.vol.had) { int inVol=chan[i].std.vol.val; - if (chan[i].furnaceDac && inVol>0) { + if (inVol>0) { inVol+=63; } chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol,MIN(127,inVol),127); @@ -700,7 +700,7 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (i>=5 && chan[i].furnaceDac && chan[i].dacMode) { + if (i>=5 && chan[i].dacMode) { if (NEW_ARP_STRAT) { chan[i].handleArp(); } else if (chan[i].std.arp.had) { @@ -720,7 +720,7 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (i>=5 && chan[i].furnaceDac) { + if (i>=5 && chan[i].dacMode) { if (chan[i].std.panL.had) { chan[5].pan&=1; chan[5].pan|=chan[i].std.panL.val?2:0; @@ -752,7 +752,7 @@ void DivPlatformGenesis::tick(bool sysTick) { } if (i>=5 && chan[i].std.phaseReset.had) { - if (chan[i].std.phaseReset.val==1 && chan[i].furnaceDac) { + if (chan[i].std.phaseReset.val==1 && chan[i].dacMode) { chan[i].dacPos=0; } } @@ -915,7 +915,7 @@ void DivPlatformGenesis::tick(bool sysTick) { immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); hardResetElapsed+=2; } - if (chan[i].furnaceDac && chan[i].dacMode) { + if (chan[i].dacMode) { double off=1.0; if (chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].dacSample); @@ -1051,15 +1051,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (ins->type==DIV_INS_AMIGA) { chan[c.chan].dacMode=1; rWrite(0x2b,1<<7); - } else if (chan[c.chan].furnaceDac) { + } else { chan[c.chan].dacMode=0; rWrite(0x2b,0<<7); chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].sampleNoteDelta=0; - } else if (!chan[c.chan].dacMode) { - rWrite(0x2b,0<<7); - chan[c.chan].sampleNote=DIV_NOTE_NULL; - chan[c.chan].sampleNoteDelta=0; } } if (c.chan>=5 && chan[c.chan].dacMode) { @@ -1097,7 +1093,6 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; } - chan[c.chan].furnaceDac=true; chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { @@ -1251,7 +1246,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } break; } - if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { + if (c.chan>=5 && chan[c.chan].dacMode) { int destFreq=parent->calcBaseFreq(1,1,c.value2+chan[c.chan].sampleNoteDelta,false); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1298,7 +1293,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { case DIV_CMD_LEGATO: { if (c.chan==csmChan) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); - } else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { + } else if (c.chan>=5 && chan[c.chan].dacMode) { chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+chan[c.chan].sampleNoteDelta,false); } else { if (chan[c.chan].insChanged) { diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3b28c2ee7..5f66585e2 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -171,15 +171,13 @@ void DivPlatformMMC5::tick(bool sysTick) { // PCM if (chan[2].freqChanged) { chan[2].freq=parent->calcFreq(chan[2].baseFreq,chan[2].pitch,chan[2].fixedArp?chan[2].baseNoteOverride:chan[2].arpOff,chan[2].fixedArp,false,0,chan[2].pitch2,1,1); - if (chan[2].furnaceDac) { - double off=1.0; - if (dacSample>=0 && dacSamplesong.sampleLen) { - DivSample* s=parent->getSample(dacSample); - off=(double)s->centerRate/parent->getCenterRate(); - } - dacRate=MIN(chan[2].freq*off,32000); - if (dumpWrites) addWrite(0xffff0001,dacRate); + double off=1.0; + if (dacSample>=0 && dacSamplesong.sampleLen) { + DivSample* s=parent->getSample(dacSample); + off=(double)s->centerRate/parent->getCenterRate(); } + dacRate=MIN(chan[2].freq*off,32000); + if (dumpWrites) addWrite(0xffff0001,dacRate); chan[2].freqChanged=false; } } @@ -189,40 +187,35 @@ int DivPlatformMMC5::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: if (c.chan==2) { // PCM DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD); - if (ins->type==DIV_INS_AMIGA) { - if (c.value!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (dacSample<0 || dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) addWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) addWrite(0xffff0000,dacSample); - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - dacPos=0; - } - dacPeriod=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - chan[c.chan].furnaceDac=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + if (c.value!=DIV_NOTE_NULL) { + dacSample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); } + if (dacSample<0 || dacSample>=parent->song.sampleLen) { + dacSample=-1; + if (dumpWrites) addWrite(0xffff0002,0); + break; + } else { + if (dumpWrites) addWrite(0xffff0000,dacSample); + } + if (chan[c.chan].setPos) { + chan[c.chan].setPos=false; + } else { + dacPos=0; + } + dacPeriod=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; break; } else { if (c.value!=DIV_NOTE_NULL) { diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index f54104144..8fbcccaad 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -162,29 +162,20 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_MSM6258 || ins->type==DIV_INS_AMIGA) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - if (c.value!=DIV_NOTE_NULL) sample=ins->amiga.getSample(c.value); - samplePos=0; - if (sample>=0 && samplesong.sampleLen) { - //DivSample* s=parent->getSample(chan[c.chan].sample); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - break; + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + if (c.value!=DIV_NOTE_NULL) sample=ins->amiga.getSample(c.value); + samplePos=0; + if (sample>=0 && samplesong.sampleLen) { + //DivSample* s=parent->getSample(chan[c.chan].sample); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } break; } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index dde975d72..0b9f52d9f 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -27,12 +27,10 @@ class DivPlatformMSM6258: public DivDispatch { protected: struct Channel: public SharedChannel { - bool furnacePCM; int sample; unsigned char pan; Channel(): SharedChannel(8), - furnacePCM(false), sample(-1), pan(3) {} }; diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index c2d4ef70b..c084802f1 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -161,31 +161,22 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_MSM6295 || ins->type==DIV_INS_AMIGA) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - if (c.value!=DIV_NOTE_NULL) chan[c.chan].sample=ins->amiga.getSample(c.value); - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - //DivSample* s=parent->getSample(chan[c.chan].sample); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - rWriteDelay(0,(8<amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + //DivSample* s=parent->getSample(chan[c.chan].sample); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + rWriteDelay(0,(8< { - bool furnacePCM; int sample; Channel(): SharedChannel(8), - furnacePCM(false), sample(-1) {} }; Channel chan[4]; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index bf035e7bc..0fcb9fa80 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -419,79 +419,78 @@ void DivPlatformNES::tick(bool sysTick) { // PCM if (chan[4].freqChanged || chan[4].keyOn) { chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,chan[4].fixedArp?chan[4].baseNoteOverride:chan[4].arpOff,chan[4].fixedArp,false); - if (chan[4].furnaceDac) { - double off=1.0; - if (dacSample>=0 && dacSamplesong.sampleLen) { - DivSample* s=parent->getSample(dacSample); - off=(double)s->centerRate/parent->getCenterRate(); - } - dacRate=MIN(chan[4].freq*off,32000); - if (chan[4].keyOn) { - if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSamplesong.sampleLen) { - unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3); - int dpcmLen=(parent->getSample(dacSample)->lengthDPCM-(dacPos>>3))>>4; - if (dpcmLen<0) dpcmLen=0; - if (dpcmLen>255) dpcmLen=255; - goingToLoop=parent->getSample(dacSample)->isLoopable(); - // write DPCM - rWrite(0x4015,15); - if (nextDPCMFreq>=0) { - rWrite(0x4010,nextDPCMFreq|(goingToLoop?0x40:0)); - nextDPCMFreq=-1; - } else { - rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); - } - if (nextDPCMDelta>=0) { - rWrite(0x4011,nextDPCMDelta); - nextDPCMDelta=-1; - } - rWrite(0x4012,(dpcmAddr>>6)&0xff); - rWrite(0x4013,dpcmLen&0xff); - rWrite(0x4015,31); - if (dpcmBank!=(dpcmAddr>>14)) { - dpcmBank=dpcmAddr>>14; - logV("switching bank to %d",dpcmBank); - if (dumpWrites) addWrite(0xffff0004,dpcmBank); - } - - // sample custom loop point... - DivSample* lsamp=parent->getSample(dacSample); - - // how it works: - // when the initial sample info is written (see above) and playback is launched, - // the parameters (start point in memory and length) are locked until sample end - // is reached. - - // thus, if we write new data after just several APU clock cycles, it will be used only when - // sample finishes one full loop. - - // thus we can write sample's loop point as "start address" and sample's looped part length - // as "full sample length". - - // APU will play full sample once and then repeatedly cycle through the looped part. - - // sources: - // https://www.nesdev.org/wiki/APU_DMC - // https://www.youtube.com/watch?v=vB4P8x2Am6Y - - if (lsamp->loopEnd>lsamp->loopStart && goingToLoop) { - int loopStartAddr=sampleOffDPCM[dacSample]+(lsamp->loopStart>>3); - int loopLen=(lsamp->loopEnd-lsamp->loopStart)>>3; - - rWrite(0x4012,(loopStartAddr>>6)&0xff); - rWrite(0x4013,(loopLen>>4)&0xff); - } - } - } else { + double off=1.0; + if (dacSample>=0 && dacSamplesong.sampleLen) { + DivSample* s=parent->getSample(dacSample); + off=(double)s->centerRate/parent->getCenterRate(); + } + dacRate=MIN(chan[4].freq*off,32000); + if (chan[4].keyOn) { + if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSamplesong.sampleLen) { + unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3); + int dpcmLen=(parent->getSample(dacSample)->lengthDPCM-(dacPos>>3))>>4; + if (dpcmLen<0) dpcmLen=0; + if (dpcmLen>255) dpcmLen=255; + goingToLoop=parent->getSample(dacSample)->isLoopable(); + // write DPCM + rWrite(0x4015,15); if (nextDPCMFreq>=0) { rWrite(0x4010,nextDPCMFreq|(goingToLoop?0x40:0)); nextDPCMFreq=-1; } else { rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); } + if (nextDPCMDelta>=0) { + rWrite(0x4011,nextDPCMDelta); + nextDPCMDelta=-1; + } + rWrite(0x4012,(dpcmAddr>>6)&0xff); + rWrite(0x4013,dpcmLen&0xff); + rWrite(0x4015,31); + if (dpcmBank!=(dpcmAddr>>14)) { + dpcmBank=dpcmAddr>>14; + logV("switching bank to %d",dpcmBank); + if (dumpWrites) addWrite(0xffff0004,dpcmBank); + } + + // sample custom loop point... + DivSample* lsamp=parent->getSample(dacSample); + + // how it works: + // when the initial sample info is written (see above) and playback is launched, + // the parameters (start point in memory and length) are locked until sample end + // is reached. + + // thus, if we write new data after just several APU clock cycles, it will be used only when + // sample finishes one full loop. + + // thus we can write sample's loop point as "start address" and sample's looped part length + // as "full sample length". + + // APU will play full sample once and then repeatedly cycle through the looped part. + + // sources: + // https://www.nesdev.org/wiki/APU_DMC + // https://www.youtube.com/watch?v=vB4P8x2Am6Y + + if (lsamp->loopEnd>lsamp->loopStart && goingToLoop) { + int loopStartAddr=sampleOffDPCM[dacSample]+(lsamp->loopStart>>3); + int loopLen=(lsamp->loopEnd-lsamp->loopStart)>>3; + + rWrite(0x4012,(loopStartAddr>>6)&0xff); + rWrite(0x4013,(loopLen>>4)&0xff); + } + } + } else { + if (nextDPCMFreq>=0) { + rWrite(0x4010,nextDPCMFreq|(goingToLoop?0x40:0)); + nextDPCMFreq=-1; + } else { + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); } - if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate); } + if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate); + if (chan[4].keyOn) chan[4].keyOn=false; chan[4].freqChanged=false; } @@ -504,69 +503,64 @@ int DivPlatformNES::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: if (c.chan==4) { // PCM DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_NES); - if (ins->type==DIV_INS_AMIGA || (ins->type==DIV_INS_NES && !parent->song.oldDPCM)) { - if (ins->type==DIV_INS_NES) { - if (!dpcmMode) { - dpcmMode=true; - if (dumpWrites) addWrite(0xffff0002,0); - dacSample=-1; - rWrite(0x4015,15); - rWrite(0x4010,0); - rWrite(0x4012,0); - rWrite(0x4013,0); - rWrite(0x4015,31); - } - - if (ins->amiga.useNoteMap) { - nextDPCMFreq=ins->amiga.getDPCMFreq(c.value); - if (nextDPCMFreq<0 || nextDPCMFreq>15) nextDPCMFreq=lastDPCMFreq; - lastDPCMFreq=nextDPCMFreq; - nextDPCMDelta=ins->amiga.getDPCMDelta(c.value); - } else { - if (c.value==DIV_NOTE_NULL) { - nextDPCMFreq=lastDPCMFreq; - } else { - nextDPCMFreq=c.value&15; - } - } - } - if (c.value!=DIV_NOTE_NULL) { - dacSample=(int)ins->amiga.getSample(c.value); - if (ins->type==DIV_INS_AMIGA) { - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - dacSample=(int)ins->amiga.getSample(chan[c.chan].sampleNote); - if (ins->type==DIV_INS_AMIGA) { - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - } - if (dacSample<0 || dacSample>=parent->song.sampleLen) { + if (ins->type==DIV_INS_NES) { + if (!dpcmMode) { + dpcmMode=true; + if (dumpWrites) addWrite(0xffff0002,0); dacSample=-1; - if (dumpWrites && !dpcmMode) addWrite(0xffff0002,0); - break; + rWrite(0x4015,15); + rWrite(0x4010,0); + rWrite(0x4012,0); + rWrite(0x4013,0); + rWrite(0x4015,31); + } + + if (ins->amiga.useNoteMap) { + nextDPCMFreq=ins->amiga.getDPCMFreq(c.value); + if (nextDPCMFreq<0 || nextDPCMFreq>15) nextDPCMFreq=lastDPCMFreq; + lastDPCMFreq=nextDPCMFreq; + nextDPCMDelta=ins->amiga.getDPCMDelta(c.value); } else { - if (dumpWrites && !dpcmMode) addWrite(0xffff0000,dacSample); + if (c.value==DIV_NOTE_NULL) { + nextDPCMFreq=lastDPCMFreq; + } else { + nextDPCMFreq=c.value&15; + } } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - dacPos=0; - } - dacPeriod=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - chan[c.chan].furnaceDac=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); } + if (c.value!=DIV_NOTE_NULL) { + dacSample=(int)ins->amiga.getSample(c.value); + if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + dacSample=(int)ins->amiga.getSample(chan[c.chan].sampleNote); + if (ins->type==DIV_INS_AMIGA) { + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); + } + } + if (dacSample<0 || dacSample>=parent->song.sampleLen) { + dacSample=-1; + if (dumpWrites && !dpcmMode) addWrite(0xffff0002,0); + break; + } else { + if (dumpWrites && !dpcmMode) addWrite(0xffff0000,dacSample); + } + if (chan[c.chan].setPos) { + chan[c.chan].setPos=false; + } else { + dacPos=0; + } + dacPeriod=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; break; } else if (c.chan==3) { // noise if (c.value!=DIV_NOTE_NULL) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 72ef7aa34..bc3583133 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -30,7 +30,7 @@ class DivPlatformNES: public DivDispatch { struct Channel: public SharedChannel { int prevFreq; unsigned char duty, sweep, envMode, len; - bool sweepChanged, furnaceDac, setPos; + bool sweepChanged, setPos; Channel(): SharedChannel(15), prevFreq(65535), @@ -39,7 +39,6 @@ class DivPlatformNES: public DivDispatch { envMode(3), len(0x1f), sweepChanged(false), - furnaceDac(false), setPos(false) {} }; Channel chan[5]; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 3d01bb1bd..b2bcf042f 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1387,26 +1387,24 @@ void DivPlatformOPL::tick(bool sysTick) { // ADPCM if (adpcmChan>=0) { - if (chan[adpcmChan].furnacePCM) { - chan[adpcmChan].std.next(); + chan[adpcmChan].std.next(); - if (chan[adpcmChan].std.vol.had) { - chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(chan[adpcmChan].macroVolMul,chan[adpcmChan].std.vol.val))/chan[adpcmChan].macroVolMul; - immWrite(18,(isMuted[adpcmChan]?0:chan[adpcmChan].outVol)); - } + if (chan[adpcmChan].std.vol.had) { + chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(chan[adpcmChan].macroVolMul,chan[adpcmChan].std.vol.val))/chan[adpcmChan].macroVolMul; + immWrite(18,(isMuted[adpcmChan]?0:chan[adpcmChan].outVol)); + } - if (NEW_ARP_STRAT) { - chan[adpcmChan].handleArp(); - } else if (chan[adpcmChan].std.arp.had) { - if (!chan[adpcmChan].inPorta) { - chan[adpcmChan].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmChan].note,chan[adpcmChan].std.arp.val)); - } - chan[adpcmChan].freqChanged=true; + if (NEW_ARP_STRAT) { + chan[adpcmChan].handleArp(); + } else if (chan[adpcmChan].std.arp.had) { + if (!chan[adpcmChan].inPorta) { + chan[adpcmChan].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmChan].note,chan[adpcmChan].std.arp.val)); } - if (chan[adpcmChan].std.phaseReset.had) { - if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) { - chan[adpcmChan].keyOn=true; - } + chan[adpcmChan].freqChanged=true; + } + if (chan[adpcmChan].std.phaseReset.had) { + if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) { + chan[adpcmChan].keyOn=true; } } if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { @@ -1838,48 +1836,39 @@ int DivPlatformOPL::dispatch(DivCommand c) { } else if (c.chan==adpcmChan) { // ADPCM DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - chan[c.chan].fixedFreq=0; - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - immWrite(18,(isMuted[adpcmChan]?0:chan[adpcmChan].outVol)); - } + chan[c.chan].macroInit(ins); + chan[c.chan].fixedFreq=0; + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(18,(isMuted[adpcmChan]?0:chan[adpcmChan].outVol)); + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].sample=ins->amiga.getSample(c.value); + c.value=ins->amiga.getFreq(c.value); + } + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(8,0); + immWrite(9,(sampleOffB[chan[c.chan].sample]>>2)&0xff); + immWrite(10,(sampleOffB[chan[c.chan].sample]>>10)&0xff); + int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; + immWrite(11,(end>>2)&0xff); + immWrite(12,(end>>10)&0xff); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].sample=ins->amiga.getSample(c.value); - c.value=ins->amiga.getFreq(c.value); - } - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(8,0); - immWrite(9,(sampleOffB[chan[c.chan].sample]>>2)&0xff); - immWrite(10,(sampleOffB[chan[c.chan].sample]>>10)&0xff); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(11,(end>>2)&0xff); - immWrite(12,(end>>10)&0xff); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(7,0x01); // reset - immWrite(9,0); - immWrite(10,0); - immWrite(11,0); - immWrite(12,0); - break; + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + immWrite(7,0x01); // reset + immWrite(9,0); + immWrite(10,0); + immWrite(11,0); + immWrite(12,0); + break; } break; } @@ -2060,9 +2049,6 @@ int DivPlatformOPL::dispatch(DivCommand c) { break; } case DIV_CMD_PITCH: { - if (c.chan==adpcmChan) { - if (!chan[c.chan].furnacePCM) break; - } chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index adf9a6709..b06b95962 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -59,7 +59,7 @@ class DivPlatformOPL: public DivDispatch { DivInstrumentFM state; unsigned int freqH, freqL; int sample, fixedFreq; - bool furnacePCM, fourOp, hardReset, writeCtrl; + bool fourOp, hardReset, writeCtrl; bool levelDirect, damp, pseudoReverb, lfoReset, ch; int lfo, vib, am, ar, d1r, d2r, dl, rc, rr; int pan; @@ -70,7 +70,6 @@ class DivPlatformOPL: public DivDispatch { freqL(0), sample(-1), fixedFreq(0), - furnacePCM(false), fourOp(false), hardReset(false), writeCtrl(false), diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index 573f1ca6b..7967f525e 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -34,14 +34,12 @@ class DivPlatformOPLL: public DivDispatch { DivInstrumentFM state; unsigned char freqH, freqL; int fixedFreq; - bool furnaceDac; unsigned char pan; Channel(): SharedChannel(0), freqH(0), freqL(0), fixedFreq(0), - furnaceDac(false), pan(3) {} }; Channel chan[11]; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 874e45457..3023aa1fc 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -225,7 +225,7 @@ void DivPlatformPCE::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) { - if (chan[i].furnaceDac && chan[i].pcm) { + if (chan[i].pcm) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { if (chan[i].setPos) { chan[i].setPos=false; @@ -249,7 +249,7 @@ void DivPlatformPCE::tick(bool sysTick) { if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (chan[i].furnaceDac && chan[i].pcm) { + if (chan[i].pcm) { double off=1.0; if (chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].dacSample); @@ -301,54 +301,48 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:31; if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].pcm=true; - } else if (chan[c.chan].furnaceDac) { + } else { chan[c.chan].pcm=false; chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].sampleNoteDelta=0; if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); } if (chan[c.chan].pcm) { - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - chan[c.chan].furnaceDac=true; - if (skipRegisterWrites) break; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].dacSample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { - chan[c.chan].dacSample=-1; - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - break; - } else { - if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); - addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); - } - } - if (chan[c.chan].setPos) { - chan[c.chan].setPos=false; - } else { - chan[c.chan].dacPos=0; - } - chan[c.chan].dacPeriod=0; - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - //chan[c.chan].keyOn=true; + if (skipRegisterWrites) break; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); + } + if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { + chan[c.chan].dacSample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + if (dumpWrites) { + chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); + } + } + if (chan[c.chan].setPos) { + chan[c.chan].setPos=false; + } else { + chan[c.chan].dacPos=0; + } + chan[c.chan].dacPeriod=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; } break; } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 5edbd371e..07cf6a1b4 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -32,7 +32,7 @@ class DivPlatformPCE: public DivDispatch { unsigned int dacPos; int dacSample; unsigned char pan; - bool noise, pcm, furnaceDac, deferredWaveUpdate, setPos; + bool noise, pcm, deferredWaveUpdate, setPos; signed short wave; int macroVolMul, noiseSeek; DivWaveSynth ws; @@ -48,7 +48,6 @@ class DivPlatformPCE: public DivDispatch { pan(255), noise(false), pcm(false), - furnaceDac(false), deferredWaveUpdate(false), setPos(false), wave(-1), diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 03d285ff5..ca5c0906c 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -278,7 +278,7 @@ void DivPlatformSwan::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - if (i==1 && pcm && furnaceDac) { + if (i==1 && pcm) { double off=1.0; if (dacSample>=0 && dacSamplesong.sampleLen) { DivSample* s=parent->getSample(dacSample); @@ -355,7 +355,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { if (c.chan==1) { if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { pcm=true; - } else if (furnaceDac) { + } else { pcm=false; chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].sampleNoteDelta=0; @@ -368,37 +368,32 @@ int DivPlatformSwan::dispatch(DivCommand c) { dacPos=0; } dacPeriod=0; - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { - if (c.value!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { - dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); - c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); - } - if (dacSample<0 || dacSample>=parent->song.sampleLen) { - dacSample=-1; - if (dumpWrites) postWrite(0xffff0002,0); - break; - } else { - if (dumpWrites) { - postWrite(0xffff0000,dacSample); - } - } - if (c.value!=DIV_NOTE_NULL) { - chan[1].baseFreq=NOTE_PERIODIC(c.value); - chan[1].freqChanged=true; - chan[1].note=c.value; - } - chan[1].active=true; - chan[1].keyOn=true; - chan[1].macroInit(ins); - furnaceDac=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + if (c.value!=DIV_NOTE_NULL) { + dacSample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); } + if (dacSample<0 || dacSample>=parent->song.sampleLen) { + dacSample=-1; + if (dumpWrites) postWrite(0xffff0002,0); + break; + } else { + if (dumpWrites) { + postWrite(0xffff0000,dacSample); + } + } + if (c.value!=DIV_NOTE_NULL) { + chan[1].baseFreq=NOTE_PERIODIC(c.value); + chan[1].freqChanged=true; + chan[1].note=c.value; + } + chan[1].active=true; + chan[1].keyOn=true; + chan[1].macroInit(ins); break; } } @@ -652,7 +647,6 @@ void DivPlatformSwan::reset() { swan_sound_init(&ws, true); pcm=false; sweep=false; - furnaceDac=false; setPos=false; noise=0; dacPeriod=0; diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index 6b8773e94..64707d805 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -41,7 +41,7 @@ class DivPlatformSwan: public DivDispatch { bool isMuted[4]; bool stereo; bool useMdfn; - bool pcm, sweep, furnaceDac, setPos; + bool pcm, sweep, setPos; unsigned char noise; int dacPeriod, dacRate; unsigned int dacPos; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 3897e9cc5..26ecfbc63 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -947,31 +947,29 @@ void DivPlatformYM2608::tick(bool sysTick) { // RSS for (int i=(9+isCSM); i<(15+isCSM); i++) { - if (chan[i].furnacePCM) { - chan[i].std.next(); - if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; - } - if (chan[i].std.duty.had) { - if (globalRSSVolume!=(chan[i].std.duty.val&0x3f)) { - globalRSSVolume=chan[i].std.duty.val&0x3f; - immWrite(0x11,globalRSSVolume); - hardResetElapsed++; - } - } - if (chan[i].std.panL.had) { - chan[i].pan=chan[i].std.panL.val&3; - } - if (chan[i].std.phaseReset.had) { - if ((chan[i].std.phaseReset.val==1) && chan[i].active) { - chan[i].keyOn=true; - } - } - if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { - immWrite(0x18+(i-(9+isCSM)),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; + } + if (chan[i].std.duty.had) { + if (globalRSSVolume!=(chan[i].std.duty.val&0x3f)) { + globalRSSVolume=chan[i].std.duty.val&0x3f; + immWrite(0x11,globalRSSVolume); hardResetElapsed++; } } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + } + if (chan[i].std.phaseReset.had) { + if ((chan[i].std.phaseReset.val==1) && chan[i].active) { + chan[i].keyOn=true; + } + } + if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { + immWrite(0x18+(i-(9+isCSM)),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + hardResetElapsed++; + } if (chan[i].keyOff) { writeRSSOff|=(1<<(i-(9+isCSM))); chan[i].keyOff=false; @@ -982,57 +980,54 @@ void DivPlatformYM2608::tick(bool sysTick) { } } // ADPCM-B - if (chan[(15+isCSM)].furnacePCM) { - chan[(15+isCSM)].std.next(); + chan[(15+isCSM)].std.next(); - if (chan[(15+isCSM)].std.vol.had) { - chan[(15+isCSM)].outVol=(chan[(15+isCSM)].vol*MIN(chan[(15+isCSM)].macroVolMul,chan[(15+isCSM)].std.vol.val))/chan[(15+isCSM)].macroVolMul; - immWrite(0x10b,chan[(15+isCSM)].outVol); - hardResetElapsed++; - } + if (chan[(15+isCSM)].std.vol.had) { + chan[(15+isCSM)].outVol=(chan[(15+isCSM)].vol*MIN(chan[(15+isCSM)].macroVolMul,chan[(15+isCSM)].std.vol.val))/chan[(15+isCSM)].macroVolMul; + immWrite(0x10b,chan[(15+isCSM)].outVol); + hardResetElapsed++; + } - if (NEW_ARP_STRAT) { - chan[(15+isCSM)].handleArp(); - } else if (chan[(15+isCSM)].std.arp.had) { - if (!chan[(15+isCSM)].inPorta) { - chan[(15+isCSM)].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[(15+isCSM)].note,chan[(15+isCSM)].std.arp.val)); - } - chan[(15+isCSM)].freqChanged=true; + if (NEW_ARP_STRAT) { + chan[(15+isCSM)].handleArp(); + } else if (chan[(15+isCSM)].std.arp.had) { + if (!chan[(15+isCSM)].inPorta) { + chan[(15+isCSM)].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[(15+isCSM)].note,chan[(15+isCSM)].std.arp.val)); } + chan[(15+isCSM)].freqChanged=true; + } - if (chan[(15+isCSM)].std.pitch.had) { - if (chan[(15+isCSM)].std.pitch.mode) { - chan[(15+isCSM)].pitch2+=chan[(15+isCSM)].std.pitch.val; - CLAMP_VAR(chan[(15+isCSM)].pitch2,-65535,65535); - } else { - chan[(15+isCSM)].pitch2=chan[(15+isCSM)].std.pitch.val; - } - chan[(15+isCSM)].freqChanged=true; + if (chan[(15+isCSM)].std.pitch.had) { + if (chan[(15+isCSM)].std.pitch.mode) { + chan[(15+isCSM)].pitch2+=chan[(15+isCSM)].std.pitch.val; + CLAMP_VAR(chan[(15+isCSM)].pitch2,-65535,65535); + } else { + chan[(15+isCSM)].pitch2=chan[(15+isCSM)].std.pitch.val; } + chan[(15+isCSM)].freqChanged=true; + } - if (chan[(15+isCSM)].std.panL.had) { - if (chan[(15+isCSM)].pan!=(chan[(15+isCSM)].std.panL.val&3)) { - chan[(15+isCSM)].pan=chan[(15+isCSM)].std.panL.val&3; - if (!isMuted[(15 + isCSM)]) { - immWrite(0x101,(isMuted[(15 + isCSM)]?0:(chan[(15+isCSM)].pan<<6))|memConfig); - hardResetElapsed++; - } - } - } - if (chan[(15+isCSM)].std.phaseReset.had) { - if ((chan[(15+isCSM)].std.phaseReset.val==1) && chan[(15+isCSM)].active) { - chan[(15+isCSM)].keyOn=true; + if (chan[(15+isCSM)].std.panL.had) { + if (chan[(15+isCSM)].pan!=(chan[(15+isCSM)].std.panL.val&3)) { + chan[(15+isCSM)].pan=chan[(15+isCSM)].std.panL.val&3; + if (!isMuted[(15 + isCSM)]) { + immWrite(0x101,(isMuted[(15 + isCSM)]?0:(chan[(15+isCSM)].pan<<6))|memConfig); + hardResetElapsed++; } } } + if (chan[(15+isCSM)].std.phaseReset.had) { + if ((chan[(15+isCSM)].std.phaseReset.val==1) && chan[(15+isCSM)].active) { + chan[(15+isCSM)].keyOn=true; + } + } + if (chan[(15+isCSM)].freqChanged || chan[(15+isCSM)].keyOn || chan[(15+isCSM)].keyOff) { - if (chan[(15+isCSM)].furnacePCM) { - if (chan[(15+isCSM)].sample>=0 && chan[(15+isCSM)].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[(15+isCSM)].sample)->centerRate)/parent->getCenterRate(); - chan[(15+isCSM)].freq=parent->calcFreq(chan[(15+isCSM)].baseFreq,chan[(15+isCSM)].pitch,chan[(15+isCSM)].fixedArp?chan[(15+isCSM)].baseNoteOverride:chan[(15+isCSM)].arpOff,chan[(15+isCSM)].fixedArp,false,4,chan[(15+isCSM)].pitch2,(double)chipClock/144,off); - } else { - chan[(15+isCSM)].freq=0; - } + if (chan[(15+isCSM)].sample>=0 && chan[(15+isCSM)].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[(15+isCSM)].sample)->centerRate)/parent->getCenterRate(); + chan[(15+isCSM)].freq=parent->calcFreq(chan[(15+isCSM)].baseFreq,chan[(15+isCSM)].pitch,chan[(15+isCSM)].fixedArp?chan[(15+isCSM)].baseNoteOverride:chan[(15+isCSM)].arpOff,chan[(15+isCSM)].fixedArp,false,4,chan[(15+isCSM)].pitch2,(double)chipClock/144,off); + } else { + chan[(15+isCSM)].freq=0; } if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; @@ -1153,70 +1148,50 @@ int DivPlatformYM2608::dispatch(DivCommand c) { if (c.chan>(14+isCSM)) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - immWrite(0x10b,chan[c.chan].outVol); - } + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x10b,chan[c.chan].outVol); + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x100,0x01); // reset + immWrite(0x102,(sampleOffB[chan[c.chan].sample]>>5)&0xff); + immWrite(0x103,(sampleOffB[chan[c.chan].sample]>>13)&0xff); + int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; + immWrite(0x104,(end>>5)&0xff); + immWrite(0x105,(end>>13)&0xff); + immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|memConfig); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x100,0x01); // reset - immWrite(0x102,(sampleOffB[chan[c.chan].sample]>>5)&0xff); - immWrite(0x103,(sampleOffB[chan[c.chan].sample]>>13)&0xff); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x104,(end>>5)&0xff); - immWrite(0x105,(end>>13)&0xff); - immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|memConfig); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x100,0x01); // reset - immWrite(0x102,0); - immWrite(0x103,0); - immWrite(0x104,0); - immWrite(0x105,0); - break; + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + immWrite(0x100,0x01); // reset + immWrite(0x102,0); + immWrite(0x103,0); + immWrite(0x104,0); + immWrite(0x105,0); + break; } break; } if (c.chan>(8+isCSM)) { // RSS DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - immWrite(0x18+(c.chan-(9+isCSM)),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); - } - } else { - chan[c.chan].macroInit(NULL); + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(0x18+(c.chan-(9+isCSM)),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); } @@ -1337,7 +1312,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } case DIV_CMD_PITCH: { - if (c.chan==(15+isCSM) && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; @@ -1396,7 +1370,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) { if (c.chan==csmChan) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } - if (c.chan==(15+isCSM) && !chan[c.chan].furnacePCM) break; if (c.chan<=psgChanOffs) { if (chan[c.chan].insChanged) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 1a050d1ac..e8e2123a9 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -867,31 +867,30 @@ void DivPlatformYM2610::tick(bool sysTick) { // ADPCM-A for (int i=adpcmAChanOffs; icalcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val)); - } - chan[adpcmBChanOffs].freqChanged=true; + if (NEW_ARP_STRAT) { + chan[adpcmBChanOffs].handleArp(); + } else if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val)); } + chan[adpcmBChanOffs].freqChanged=true; + } - if (chan[adpcmBChanOffs].std.pitch.had) { - if (chan[adpcmBChanOffs].std.pitch.mode) { - chan[adpcmBChanOffs].pitch2+=chan[adpcmBChanOffs].std.pitch.val; - CLAMP_VAR(chan[adpcmBChanOffs].pitch2,-65535,65535); - } else { - chan[adpcmBChanOffs].pitch2=chan[adpcmBChanOffs].std.pitch.val; - } - chan[adpcmBChanOffs].freqChanged=true; + if (chan[adpcmBChanOffs].std.pitch.had) { + if (chan[adpcmBChanOffs].std.pitch.mode) { + chan[adpcmBChanOffs].pitch2+=chan[adpcmBChanOffs].std.pitch.val; + CLAMP_VAR(chan[adpcmBChanOffs].pitch2,-65535,65535); + } else { + chan[adpcmBChanOffs].pitch2=chan[adpcmBChanOffs].std.pitch.val; } + chan[adpcmBChanOffs].freqChanged=true; + } - if (chan[adpcmBChanOffs].std.panL.had) { - if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { - chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; - if (!isMuted[adpcmBChanOffs]) { - immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); - hardResetElapsed++; - } - } - } - if (chan[adpcmBChanOffs].std.phaseReset.had) { - if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { - chan[adpcmBChanOffs].keyOn=true; + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + hardResetElapsed++; } } } - if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { - if (chan[adpcmBChanOffs].furnacePCM) { - if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/parent->getCenterRate(); - chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,chan[adpcmBChanOffs].fixedArp?chan[adpcmBChanOffs].baseNoteOverride:chan[adpcmBChanOffs].arpOff,chan[adpcmBChanOffs].fixedArp,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); - } else { - chan[adpcmBChanOffs].freq=0; - } - if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; - if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; - immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); - immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); - hardResetElapsed+=2; + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; } + } + + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/parent->getCenterRate(); + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,chan[adpcmBChanOffs].fixedArp?chan[adpcmBChanOffs].baseNoteOverride:chan[adpcmBChanOffs].arpOff,chan[adpcmBChanOffs].fixedArp,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; + if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + hardResetElapsed+=2; + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { immWrite(0x10,0x01); // reset hardResetElapsed++; @@ -1071,92 +1068,74 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - immWrite(0x1b,chan[c.chan].outVol); - } + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x1b,chan[c.chan].outVol); + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); + immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); + int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); - immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); - break; + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; } break; } if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - if (c.value!=DIV_NOTE_NULL) chan[c.chan].sample=ins->amiga.getSample(c.value); - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); - immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); - int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; - immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); - immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); - immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); - immWrite(0x110+c.chan-adpcmAChanOffs,0); - immWrite(0x118+c.chan-adpcmAChanOffs,0); - immWrite(0x120+c.chan-adpcmAChanOffs,0); - immWrite(0x128+c.chan-adpcmAChanOffs,0); - break; + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + if (c.value!=DIV_NOTE_NULL) chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); + int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; } break; } @@ -1273,7 +1252,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_PITCH: { - if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; @@ -1329,7 +1307,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; if (c.chan==csmChan) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 8fe8b61dc..413bdcbae 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -936,31 +936,30 @@ void DivPlatformYM2610B::tick(bool sysTick) { // ADPCM-A for (int i=adpcmAChanOffs; icalcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val)); - } - chan[adpcmBChanOffs].freqChanged=true; + if (NEW_ARP_STRAT) { + chan[adpcmBChanOffs].handleArp(); + } else if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val)); } + chan[adpcmBChanOffs].freqChanged=true; + } - if (chan[adpcmBChanOffs].std.pitch.had) { - if (chan[adpcmBChanOffs].std.pitch.mode) { - chan[adpcmBChanOffs].pitch2+=chan[adpcmBChanOffs].std.pitch.val; - CLAMP_VAR(chan[adpcmBChanOffs].pitch2,-65535,65535); - } else { - chan[adpcmBChanOffs].pitch2=chan[adpcmBChanOffs].std.pitch.val; - } - chan[adpcmBChanOffs].freqChanged=true; + if (chan[adpcmBChanOffs].std.pitch.had) { + if (chan[adpcmBChanOffs].std.pitch.mode) { + chan[adpcmBChanOffs].pitch2+=chan[adpcmBChanOffs].std.pitch.val; + CLAMP_VAR(chan[adpcmBChanOffs].pitch2,-65535,65535); + } else { + chan[adpcmBChanOffs].pitch2=chan[adpcmBChanOffs].std.pitch.val; } + chan[adpcmBChanOffs].freqChanged=true; + } - if (chan[adpcmBChanOffs].std.panL.had) { - if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { - chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; - if (!isMuted[adpcmBChanOffs]) { - immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); - hardResetElapsed++; - } - } - } - if (chan[adpcmBChanOffs].std.phaseReset.had) { - if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { - chan[adpcmBChanOffs].keyOn=true; + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + hardResetElapsed++; } } } - if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { - if (chan[adpcmBChanOffs].furnacePCM) { - if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/parent->getCenterRate(); - chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,chan[adpcmBChanOffs].fixedArp?chan[adpcmBChanOffs].baseNoteOverride:chan[adpcmBChanOffs].arpOff,chan[adpcmBChanOffs].fixedArp,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); - } else { - chan[adpcmBChanOffs].freq=0; - } - if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; - if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; - immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); - immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); - hardResetElapsed+=2; + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; } + } + + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/parent->getCenterRate(); + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,chan[adpcmBChanOffs].fixedArp?chan[adpcmBChanOffs].baseNoteOverride:chan[adpcmBChanOffs].arpOff,chan[adpcmBChanOffs].fixedArp,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; + if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + hardResetElapsed+=2; + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { immWrite(0x10,0x01); // reset hardResetElapsed++; @@ -1140,92 +1137,74 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - immWrite(0x1b,chan[c.chan].outVol); - } + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x1b,chan[c.chan].outVol); + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); + immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); + int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x12,(sampleOffB[chan[c.chan].sample]>>8)&0xff); - immWrite(0x13,sampleOffB[chan[c.chan].sample]>>16); - int end=sampleOffB[chan[c.chan].sample]+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); - break; + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; } break; } if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { - chan[c.chan].furnacePCM=true; - } else { - chan[c.chan].furnacePCM=false; - } if (skipRegisterWrites) break; - if (chan[c.chan].furnacePCM) { - chan[c.chan].macroInit(ins); - if (!chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - if (c.value!=DIV_NOTE_NULL) chan[c.chan].sample=ins->amiga.getSample(c.value); - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[c.chan].sample); - immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); - immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); - int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; - immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); - immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); - immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); - chan[c.chan].freqChanged=true; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); - immWrite(0x110+c.chan-adpcmAChanOffs,0); - immWrite(0x118+c.chan-adpcmAChanOffs,0); - immWrite(0x120+c.chan-adpcmAChanOffs,0); - immWrite(0x128+c.chan-adpcmAChanOffs,0); - break; + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + if (c.value!=DIV_NOTE_NULL) chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(sampleOffA[chan[c.chan].sample]>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,sampleOffA[chan[c.chan].sample]>>16); + int end=sampleOffA[chan[c.chan].sample]+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; } break; } @@ -1342,7 +1321,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_PITCH: { - if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; @@ -1398,7 +1376,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; if (c.chan==csmChan) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 40cfb5dc1..a77e4af1f 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -164,7 +164,6 @@ ImGui::Text("- pan: %x",ch->pan); \ ImGui::Text("- opMask: %x",ch->opMask); \ COMMON_CHAN_DEBUG_BOOL; \ - ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \ ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \ @@ -201,7 +200,6 @@ COMMON_CHAN_DEBUG_BOOL; \ ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ - ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); #define OPN_OPCHAN_DEBUG \ DivPlatformOPN::OPNOpChannel* ch=(DivPlatformOPN::OPNOpChannel*)data; \ @@ -227,7 +225,6 @@ COMMON_CHAN_DEBUG_BOOL; \ ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ - ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); #define OPNB_OPCHAN_DEBUG \ ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ @@ -697,7 +694,6 @@ void putDispatchChan(void* data, int chanNum, int type) { COMMON_CHAN_DEBUG_BOOL; ImGui::TextColored(ch->noise?colorOn:colorOff,">> Noise"); ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC"); - ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); break; } case DIV_SYSTEM_NES: { @@ -709,7 +705,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- sweep: %.2x",ch->sweep); COMMON_CHAN_DEBUG_BOOL; ImGui::TextColored(ch->sweepChanged?colorOn:colorOff,">> SweepChanged"); - ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); break; } case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: { @@ -760,7 +755,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- chPanR: %.2x",ch->chPanR); ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); COMMON_CHAN_DEBUG_BOOL; - ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); ImGui::TextColored(ch->isNewSegaPCM?colorOn:colorOff,">> IsNewSegaPCM"); break; } @@ -777,7 +771,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); COMMON_CHAN_DEBUG_BOOL; - ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); break; } case DIV_SYSTEM_AY8930: { @@ -794,7 +787,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); COMMON_CHAN_DEBUG_BOOL; - ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); break; } case DIV_SYSTEM_QSOUND: { @@ -831,7 +823,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- Rvol: %.2x",ch->rvol); COMMON_CHAN_DEBUG_BOOL; ImGui::TextColored(ch->envChanged?colorOn:colorOff,">> EnvChanged"); - ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); ImGui::TextColored(ch->pcm?colorOn:colorOff,">> PCM"); ImGui::TextColored(ch->env.flag.envEnable?colorOn:colorOff,">> EnvEnable"); ImGui::TextColored(ch->env.flag.envOneshot?colorOn:colorOff,">> EnvOneshot"); @@ -870,7 +861,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- duty: %d",ch->duty); COMMON_CHAN_DEBUG_BOOL; ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC"); - ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); break; } case DIV_SYSTEM_ES5506: { From f45bb9731874a3d2e42f9fe600e0e0be81d54726 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Nov 2025 20:15:40 -0500 Subject: [PATCH 14/25] total extinction of legacy sample mode, part 4 prepare the conversion code... --- src/engine/fileOps/dmf.cpp | 3 +++ src/engine/fileOps/fur.cpp | 5 +++++ src/engine/song.cpp | 6 ++++++ src/engine/song.h | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 52e6e9079..2ae9d2a92 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1166,6 +1166,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.systemFlags[0].set("brokenPitch",true); } + // always convert to normal sample mode (I have no idea how will I do export) + ds.convertLegacySampleMode(); + ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); if (active) quitDispatch(); diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 8acc5285b..ab80bc076 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2181,6 +2181,11 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { addWarning("this song used partial pitch linearity, which has been removed from Furnace. you may have to adjust your song."); } + // removal of legacy sample mode + if (ds.version<239) { + ds.convertLegacySampleMode(); + } + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 116815da7..b7b363295 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -729,3 +729,9 @@ void DivSong::unload() { } subsong.clear(); } + +// from this point onwards, a mess. + +void DivSong::convertLegacySampleMode() { + +} diff --git a/src/engine/song.h b/src/engine/song.h index 437e1159e..2384dd51e 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -408,6 +408,11 @@ struct DivSong { */ void findSubSongs(int chans); + /** + * try to convert usage of legacy sample mode into normal mode. + */ + void convertLegacySampleMode(); + /** * clear orders and patterns. */ From 61ac87d505b598e734c89e6efdd4df61423adeb0 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Sun, 9 Nov 2025 10:36:35 +0400 Subject: [PATCH 15/25] fix moving subsongs not marking as modified --- src/gui/subSongs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index b21861251..ec6464466 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -53,6 +53,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) { ImGui::PushID(i); if (ImGui::SmallButton(ICON_FA_ARROW_UP "##SubUp")) { e->moveSubSongUp(i); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Move up")); @@ -60,6 +61,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) { ImGui::SameLine(); if (ImGui::SmallButton(ICON_FA_ARROW_DOWN "##SubDown")) { e->moveSubSongDown(i); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Move down")); From 734f36b483ffaf5ad991bce7a3b2a79d79db277e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 01:56:36 -0500 Subject: [PATCH 16/25] what the hell --- src/engine/fileOps/dmf.cpp | 5 ++++- src/engine/fileOps/fur.cpp | 2 +- src/engine/song.cpp | 15 ++++++++++++++- src/engine/song.h | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 2ae9d2a92..ac517df40 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1103,6 +1103,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } + // store channel count for later + int chCount=getChannelCount(ds.system[0]); + // handle compound systems if (ds.system[0]==DIV_SYSTEM_GENESIS) { ds.systemLen=2; @@ -1167,7 +1170,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } // always convert to normal sample mode (I have no idea how will I do export) - ds.convertLegacySampleMode(); + ds.convertLegacySampleMode(chCount); ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index ab80bc076..922499952 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2183,7 +2183,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { // removal of legacy sample mode if (ds.version<239) { - ds.convertLegacySampleMode(); + ds.convertLegacySampleMode(tchans); } if (active) quitDispatch(); diff --git a/src/engine/song.cpp b/src/engine/song.cpp index b7b363295..4f20b34e1 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -732,6 +732,19 @@ void DivSong::unload() { // from this point onwards, a mess. -void DivSong::convertLegacySampleMode() { +void DivSong::convertLegacySampleMode(int chans) { + for (DivSubSong* h: subsong) { + for (int i=0; iordersLen; j++) { + DivPattern* p=h->pat[i].data[h->orders.ord[i][j]]; + if (p==NULL) continue; + switch ( + for (int k=0; kpatLen; k++) { + + } + } + } + } } diff --git a/src/engine/song.h b/src/engine/song.h index 2384dd51e..8d5d5c8c0 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -411,7 +411,7 @@ struct DivSong { /** * try to convert usage of legacy sample mode into normal mode. */ - void convertLegacySampleMode(); + void convertLegacySampleMode(int chans); /** * clear orders and patterns. From 0f5455831ac93b0a797a5369efe6394a98722b6d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 05:23:32 -0500 Subject: [PATCH 17/25] total extinction of legacy sample mode, part 5 partially working converter --- CMakeLists.txt | 1 + src/engine/engine.h | 4 + src/engine/fileOps/dmf.cpp | 8 +- src/engine/fileOps/fur.cpp | 9 +- src/engine/legacySample.cpp | 201 ++++++++++++++++++++++++++++++++ src/engine/platform/segapcm.cpp | 142 ++++++++++------------ src/engine/platform/segapcm.h | 7 +- src/engine/song.cpp | 21 +--- src/engine/song.h | 5 - 9 files changed, 279 insertions(+), 119 deletions(-) create mode 100644 src/engine/legacySample.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bb3b6f96..85259de3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -795,6 +795,7 @@ src/engine/fileOpsSample.cpp src/engine/filePlayer.cpp src/engine/filter.cpp src/engine/instrument.cpp +src/engine/legacySample.cpp src/engine/macroInt.cpp src/engine/pattern.cpp src/engine/pitchTable.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index f84dcdbd8..f318feb4b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -695,6 +695,10 @@ class DivEngine { // change song (UNSAFE) void changeSong(size_t songIndex); + // convert legacy sample mode to normal + // returns whether conversion occurred + bool convertLegacySampleMode(); + void swapSystemUnsafe(int src, int dest, bool preserveOrder=true); // move an asset diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index ac517df40..4dbea03bf 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1103,9 +1103,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } - // store channel count for later - int chCount=getChannelCount(ds.system[0]); - // handle compound systems if (ds.system[0]==DIV_SYSTEM_GENESIS) { ds.systemLen=2; @@ -1169,9 +1166,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.systemFlags[0].set("brokenPitch",true); } - // always convert to normal sample mode (I have no idea how will I do export) - ds.convertLegacySampleMode(chCount); - ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); if (active) quitDispatch(); @@ -1181,6 +1175,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { song=ds; changeSong(0); recalcChans(); + // always convert to normal sample mode (I have no idea how will I do export) + convertLegacySampleMode(); saveLock.unlock(); BUSY_END; if (active) { diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 922499952..2a7efb348 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2181,11 +2181,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { addWarning("this song used partial pitch linearity, which has been removed from Furnace. you may have to adjust your song."); } - // removal of legacy sample mode - if (ds.version<239) { - ds.convertLegacySampleMode(tchans); - } - if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); @@ -2193,6 +2188,10 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { song=ds; changeSong(0); recalcChans(); + // removal of legacy sample mode + if (song.version<239) { + convertLegacySampleMode(); + } saveLock.unlock(); BUSY_END; if (active) { diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp new file mode 100644 index 000000000..f3d3a5793 --- /dev/null +++ b/src/engine/legacySample.cpp @@ -0,0 +1,201 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2025 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. + */ + +// from this point onwards, a mess. + +#include "engine.h" + +bool DivEngine::convertLegacySampleMode() { + logD("converting legacy sample mode..."); + int legacyInsInit=-1; + + // quit if we don't have space for a legacy sample instrument + if (song.ins.size()>254) { + logW("no space left on instrument list!"); + return false; + } + + auto initSampleInsIfNeeded=[this,&legacyInsInit]() { + if (legacyInsInit==-1) { + DivInstrument* ins=new DivInstrument; + legacyInsInit=(int)song.ins.size(); + + ins->type=DIV_INS_AMIGA; + ins->amiga.useNoteMap=true; + ins->name="Legacy Samples"; + for (int i=0; i<120; i++) { + ins->amiga.noteMap[i].freq=48; // C-4 + ins->amiga.noteMap[i].map=i%12; + } + + song.ins.push_back(ins); + song.insLen=song.ins.size(); + checkAssetDir(song.insDir,song.ins.size()); + } + }; + + for (DivSubSong* h: song.subsong) { + for (int i=0; iordersLen; j++) { + int patIndex=h->orders.ord[i][j]; + if (didThisPattern[patIndex]) continue; + didThisPattern[patIndex]=true; + DivPattern* p=h->pat[i].data[patIndex]; + if (p==NULL) continue; + + for (int k=0; kpatLen; k++) { + // check for legacy mode toggle and sample bank changes + for (int l=0; lpat[i].effectCols; l++) { + int fxVal=p->newData[k][DIV_PAT_FXVAL(l)]; + if (fxVal<0) fxVal=0; + switch (p->newData[k][DIV_PAT_FX(l)]) { + case 0x17: // set legacy sample mode + if (fxVal==0) { + sampleMode=0; + } else { + sampleMode=1; + } + // clear effect + p->newData[k][DIV_PAT_FX(l)]=-1; + p->newData[k][DIV_PAT_FXVAL(l)]=-1; + break; + case 0xeb: // set sample bank + sampleBank=fxVal; + // clear effect + p->newData[k][DIV_PAT_FX(l)]=-1; + p->newData[k][DIV_PAT_FXVAL(l)]=-1; + logV("change bank to %d",sampleBank); + break; + } + } + + // check for instrument changes + if (p->newData[k][DIV_PAT_INS]!=-1) { + DivInstrument* ins=getIns(p->newData[k][DIV_PAT_INS]); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample || ins->type==preferredInsType || ins->type==preferredInsType2) { + sampleMode=2; + } + } + + if (p->newData[k][DIV_PAT_NOTE]!=-1 && + p->newData[k][DIV_PAT_NOTE]!=DIV_NOTE_OFF && + p->newData[k][DIV_PAT_NOTE]!=DIV_NOTE_REL && + p->newData[k][DIV_PAT_NOTE]!=DIV_MACRO_REL) { + // we've got a note + if (sampleMode==1) { + initSampleInsIfNeeded(); + //p->newData[k][DIV_PAT_NOTE]=60+12*sampleBank+(p->newData[k][DIV_PAT_NOTE]%12); + p->newData[k][DIV_PAT_INS]=legacyInsInit; + } + } else if (p->newData[k][DIV_PAT_NOTE]==DIV_NOTE_OFF && noteOffDisablesSampleMode) { + sampleMode=0; + } + } + } + } + } + + return (legacyInsInit!=-1); +} diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 984765ea7..c659b8f2a 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -78,11 +78,15 @@ void DivPlatformSegaPCM::tick(bool sysTick) { if (NEW_ARP_STRAT) { chan[i].handleArp(); + if (chan[i].std.arp.had) { + if (chan[i].freqChanged) chan[i].pcm.freq=-1; + } } else if (chan[i].std.arp.had) { if (!chan[i].inPorta) { chan[i].baseFreq=(parent->calcArp(chan[i].note,chan[i].std.arp.val)<<7); } chan[i].freqChanged=true; + chan[i].pcm.freq=-1; } if (parent->song.newSegaPCM) if (chan[i].std.panL.had) { @@ -105,6 +109,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { chan[i].pitch2=chan[i].std.pitch.val; } chan[i].freqChanged=true; + chan[i].pcm.freq=-1; } if (chan[i].std.phaseReset.had) { @@ -123,12 +128,13 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } } if (oldSlides) chan[i].freq&=~1; - if (chan[i].furnacePCM) { - double off=1.0; - if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[i].pcm.sample); - off=(double)s->centerRate/parent->getCenterRate(); - } + + double off=1.0; + if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].pcm.sample); + off=(double)s->centerRate/parent->getCenterRate(); + } + if (chan[i].pcm.freq==-1) { chan[i].pcm.freq=MIN(255,((rate*0.5)+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+512)/(128.0*12.0)))*255)/rate)+(oldSlides?chan[i].pitch2:0); rWrite(7+(i<<3),chan[i].pcm.freq); } @@ -141,44 +147,23 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } else { chan[i].pcm.pos=0; } - if (chan[i].furnacePCM) { - DivSample* s=parent->getSample(chan[i].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>0xfeff) actualLength=0xfeff; - int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos; - rWrite(0x86+(i<<3),3+((actualPos>>16)<<3)); - rWrite(0x84+(i<<3),(actualPos)&0xff); - rWrite(0x85+(i<<3),(actualPos>>8)&0xff); - rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]); - if (!s->isLoopable()) { - rWrite(0x86+(i<<3),2+((actualPos>>16)<<3)); - } else { - int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart; - logV("sampleOff: %x loopPos: %x",actualPos,loopPos); - rWrite(4+(i<<3),loopPos&0xff); - rWrite(5+(i<<3),(loopPos>>8)&0xff); - rWrite(0x86+(i<<3),((actualPos>>16)<<3)); - } + DivSample* s=parent->getSample(chan[i].pcm.sample); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + if (actualLength>0xfeff) actualLength=0xfeff; + int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos; + rWrite(0x86+(i<<3),3+((actualPos>>16)<<3)); + rWrite(0x84+(i<<3),(actualPos)&0xff); + rWrite(0x85+(i<<3),(actualPos>>8)&0xff); + rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]); + if (!s->isLoopable()) { + rWrite(0x86+(i<<3),2+((actualPos>>16)<<3)); } else { - DivSample* s=parent->getSample(chan[i].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>0xfeff) actualLength=0xfeff; - int actualPos=sampleOffSegaPCM[chan[i].pcm.sample]+chan[i].pcm.pos; - rWrite(0x86+(i<<3),3+((actualPos>>16)<<3)); - rWrite(0x84+(i<<3),(actualPos)&0xff); - rWrite(0x85+(i<<3),(actualPos>>8)&0xff); - rWrite(6+(i<<3),sampleEndSegaPCM[chan[i].pcm.sample]); - if (!s->isLoopable()) { - rWrite(0x86+(i<<3),2+((actualPos>>16)<<3)); - } else { - int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart; - rWrite(4+(i<<3),loopPos&0xff); - rWrite(5+(i<<3),(loopPos>>8)&0xff); - rWrite(0x86+(i<<3),((actualPos>>16)<<3)); - } - rWrite(7+(i<<3),chan[i].pcm.freq); + int loopPos=(sampleOffSegaPCM[chan[i].pcm.sample]&0xffff)+loopStart; + logV("sampleOff: %x loopPos: %x",actualPos,loopPos); + rWrite(4+(i<<3),loopPos&0xff); + rWrite(5+(i<<3),(loopPos>>8)&0xff); + rWrite(0x86+(i<<3),((actualPos>>16)<<3)); } } chan[i].keyOn=false; @@ -198,43 +183,39 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) { - chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; - chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); - chan[c.chan].sampleNote=c.value; - c.value=ins->amiga.getFreq(c.value); - chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; - } - if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { - chan[c.chan].pcm.sample=-1; - rWrite(0x86+(c.chan<<3),3); - chan[c.chan].macroInit(NULL); - break; - } - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].note=c.value; - chan[c.chan].baseFreq=(c.value<<7); - chan[c.chan].freqChanged=true; - } - chan[c.chan].furnacePCM=true; - chan[c.chan].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - - if (parent->song.newSegaPCM) { - chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; - chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127; - rWrite(2+(c.chan<<3),chan[c.chan].chVolL); - rWrite(3+(c.chan<<3),chan[c.chan].chVolR); - } - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - } else { - assert(false && "LEGACY SAMPLE MODE!!!"); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; + chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; } + if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { + chan[c.chan].pcm.sample=-1; + rWrite(0x86+(c.chan<<3),3); + chan[c.chan].macroInit(NULL); + break; + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=(c.value<<7); + chan[c.chan].freqChanged=true; + chan[c.chan].pcm.freq=-1; + } + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + + if (parent->song.newSegaPCM) { + chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; + chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127; + rWrite(2+(c.chan<<3),chan[c.chan].chVolL); + rWrite(3+(c.chan<<3),chan[c.chan].chVolR); + } + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; break; } case DIV_CMD_NOTE_OFF: @@ -297,6 +278,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { case DIV_CMD_PITCH: { chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; + chan[c.chan].pcm.freq=-1; break; } case DIV_CMD_NOTE_PORTA: { @@ -319,6 +301,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } chan[c.chan].baseFreq=newFreq; chan[c.chan].freqChanged=true; + chan[c.chan].pcm.freq=-1; if (return2) { chan[c.chan].inPorta=false; return 2; @@ -328,6 +311,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { case DIV_CMD_LEGATO: { chan[c.chan].baseFreq=((c.value+chan[c.chan].sampleNoteDelta)<<7); chan[c.chan].freqChanged=true; + chan[c.chan].pcm.freq=-1; break; } case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 3eb0c8475..e00fb0d74 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -28,7 +28,7 @@ class DivPlatformSegaPCM: public DivDispatch { protected: struct Channel: public SharedChannel { - bool furnacePCM, isNewSegaPCM, setPos; + bool isNewSegaPCM, setPos; unsigned char chVolL, chVolR; unsigned char chPanL, chPanR; int macroVolMul; @@ -37,12 +37,11 @@ class DivPlatformSegaPCM: public DivDispatch { int sample; unsigned int pos; // <<8 unsigned short len; - unsigned char freq; - PCMChannel(): sample(-1), pos(0), len(0), freq(0) {} + short freq; + PCMChannel(): sample(-1), pos(0), len(0), freq(-1) {} } pcm; Channel(): SharedChannel(127), - furnacePCM(false), isNewSegaPCM(false), setPos(false), chVolL(127), diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 4f20b34e1..2afd0fddc 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -728,23 +728,4 @@ void DivSong::unload() { delete i; } subsong.clear(); -} - -// from this point onwards, a mess. - -void DivSong::convertLegacySampleMode(int chans) { - for (DivSubSong* h: subsong) { - for (int i=0; iordersLen; j++) { - DivPattern* p=h->pat[i].data[h->orders.ord[i][j]]; - if (p==NULL) continue; - - switch ( - for (int k=0; kpatLen; k++) { - - } - } - } - } -} +} \ No newline at end of file diff --git a/src/engine/song.h b/src/engine/song.h index 8d5d5c8c0..437e1159e 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -408,11 +408,6 @@ struct DivSong { */ void findSubSongs(int chans); - /** - * try to convert usage of legacy sample mode into normal mode. - */ - void convertLegacySampleMode(int chans); - /** * clear orders and patterns. */ From 0ac7106e0efd140bed410e65a2b68968ff13d3e5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 15:04:16 -0500 Subject: [PATCH 18/25] total extinction of legacy sample mode, part 6 almost there --- src/engine/fileOps/fur.cpp | 4 +- src/engine/legacySample.cpp | 141 +++++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 18 deletions(-) diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 2a7efb348..f3a0ad4b8 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2190,7 +2190,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { recalcChans(); // removal of legacy sample mode if (song.version<239) { - convertLegacySampleMode(); + if (convertLegacySampleMode()) { + addWarning("Furnace no longer supports legacy sample mode. your song has been converted."); + } } saveLock.unlock(); BUSY_END; diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp index f3d3a5793..2b0299d28 100644 --- a/src/engine/legacySample.cpp +++ b/src/engine/legacySample.cpp @@ -20,6 +20,7 @@ // from this point onwards, a mess. #include "engine.h" +#include bool DivEngine::convertLegacySampleMode() { logD("converting legacy sample mode..."); @@ -33,18 +34,25 @@ bool DivEngine::convertLegacySampleMode() { auto initSampleInsIfNeeded=[this,&legacyInsInit]() { if (legacyInsInit==-1) { - DivInstrument* ins=new DivInstrument; legacyInsInit=(int)song.ins.size(); + for (size_t bank=0; bank<(11+song.sample.size())/12; bank++) { + DivInstrument* ins=new DivInstrument; - ins->type=DIV_INS_AMIGA; - ins->amiga.useNoteMap=true; - ins->name="Legacy Samples"; - for (int i=0; i<120; i++) { - ins->amiga.noteMap[i].freq=48; // C-4 - ins->amiga.noteMap[i].map=i%12; + ins->type=DIV_INS_AMIGA; + ins->amiga.useNoteMap=true; + if (bank==0) { + ins->name="Legacy Samples"; + } else { + ins->name=fmt::sprintf("Legacy Samples (bank %d)",(int)bank); + } + for (int i=0; i<120; i++) { + ins->amiga.noteMap[i].freq=48; // C-4 + ins->amiga.noteMap[i].map=12*bank+(i%12); + } + + song.ins.push_back(ins); + if (song.ins.size()>=256) break; } - - song.ins.push_back(ins); song.insLen=song.ins.size(); checkAssetDir(song.insDir,song.ins.size()); } @@ -60,30 +68,48 @@ bool DivEngine::convertLegacySampleMode() { DivInstrumentType preferredInsType=DIV_INS_AMIGA; DivInstrumentType preferredInsType2=DIV_INS_AMIGA; bool noteOffDisablesSampleMode=false; + bool hasLegacyToggle=false; switch (sysOfChan[i]) { case DIV_SYSTEM_NES: + case DIV_SYSTEM_5E01: // NES PCM channel (on by default) if (dispatchChanOfChan[i]!=4) { continue; } sampleMode=1; break; + case DIV_SYSTEM_MMC5: + // MMC5 PCM channel + if (dispatchChanOfChan[i]!=2) { + continue; + } + sampleMode=1; + break; case DIV_SYSTEM_YM2612: // YM2612 DAC channel if (dispatchChanOfChan[i]!=5) { continue; } + hasLegacyToggle=true; break; case DIV_SYSTEM_YM2612_EXT: + case DIV_SYSTEM_YM2612_CSM: // YM2612 DAC channel if (dispatchChanOfChan[i]!=8) { continue; } + hasLegacyToggle=true; break; case DIV_SYSTEM_PCE: + case DIV_SYSTEM_X1_010: // any channel can be DAC'd noteOffDisablesSampleMode=true; + hasLegacyToggle=true; + break; + case DIV_SYSTEM_AY8910: + case DIV_SYSTEM_AY8930: + // any channel can be DAC'd break; case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_FULL: @@ -105,6 +131,15 @@ bool DivEngine::convertLegacySampleMode() { preferredInsType=DIV_INS_ADPCMA; preferredInsType2=DIV_INS_ADPCMB; break; + case DIV_SYSTEM_YM2610_CSM: + // Neo Geo CD ADPCM channels + if (dispatchChanOfChan[i]<11) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMA; + preferredInsType2=DIV_INS_ADPCMB; + break; case DIV_SYSTEM_YM2610B: // ADPCM channels if (dispatchChanOfChan[i]<9) { @@ -123,12 +158,82 @@ bool DivEngine::convertLegacySampleMode() { preferredInsType=DIV_INS_ADPCMA; preferredInsType2=DIV_INS_ADPCMB; break; + case DIV_SYSTEM_YM2610B_CSM: + // ADPCM channels + if (dispatchChanOfChan[i]<13) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMA; + preferredInsType2=DIV_INS_ADPCMB; + break; + case DIV_SYSTEM_YM2608: + // ADPCM channel + if (dispatchChanOfChan[i]!=15) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMB; + break; + case DIV_SYSTEM_YM2608_EXT: + // ADPCM channel + if (dispatchChanOfChan[i]!=18) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMB; + break; + case DIV_SYSTEM_YM2608_CSM: + // ADPCM channel + if (dispatchChanOfChan[i]!=19) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMB; + break; case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: // all channels can play back samples sampleMode=1; preferredInsType=DIV_INS_SEGAPCM; break; + case DIV_SYSTEM_MSM6258: + sampleMode=1; + preferredInsType=DIV_INS_MSM6258; + break; + case DIV_SYSTEM_MSM6295: + sampleMode=1; + preferredInsType=DIV_INS_MSM6295; + break; + case DIV_SYSTEM_Y8950: + // Y8950 ADPCM + if (dispatchChanOfChan[i]!=9) { + continue; + } + sampleMode=1; + break; + case DIV_SYSTEM_Y8950_DRUMS: + // Y8950 ADPCM + if (dispatchChanOfChan[i]!=11) { + continue; + } + sampleMode=1; + break; + case DIV_SYSTEM_SWAN: + // PCM channel + if (dispatchChanOfChan[i]!=1) { + continue; + } + noteOffDisablesSampleMode=true; + hasLegacyToggle=true; + break; + case DIV_SYSTEM_VRC6: + // pulse DAC mode + if (dispatchChanOfChan[i]>=2) { + continue; + } + hasLegacyToggle=true; + break; default: // not a chip with convertible channels continue; } @@ -152,14 +257,16 @@ bool DivEngine::convertLegacySampleMode() { if (fxVal<0) fxVal=0; switch (p->newData[k][DIV_PAT_FX(l)]) { case 0x17: // set legacy sample mode - if (fxVal==0) { - sampleMode=0; - } else { - sampleMode=1; + if (hasLegacyToggle) { + if (fxVal==0) { + sampleMode=0; + } else { + sampleMode=1; + } + // clear effect + p->newData[k][DIV_PAT_FX(l)]=-1; + p->newData[k][DIV_PAT_FXVAL(l)]=-1; } - // clear effect - p->newData[k][DIV_PAT_FX(l)]=-1; - p->newData[k][DIV_PAT_FXVAL(l)]=-1; break; case 0xeb: // set sample bank sampleBank=fxVal; @@ -187,7 +294,7 @@ bool DivEngine::convertLegacySampleMode() { if (sampleMode==1) { initSampleInsIfNeeded(); //p->newData[k][DIV_PAT_NOTE]=60+12*sampleBank+(p->newData[k][DIV_PAT_NOTE]%12); - p->newData[k][DIV_PAT_INS]=legacyInsInit; + p->newData[k][DIV_PAT_INS]=MIN(0xff,legacyInsInit+sampleBank); } } else if (p->newData[k][DIV_PAT_NOTE]==DIV_NOTE_OFF && noteOffDisablesSampleMode) { sampleMode=0; From 69ae4f56bde07d7260165944bd389ac714110408 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 17:47:37 -0500 Subject: [PATCH 19/25] total extinction of legacy sample mode, part 7 finish the conversion method --- src/engine/fileOps/dmf.cpp | 1 + src/engine/legacySample.cpp | 64 ++++++++++++++++++++++++++++++++++++- src/engine/sample.cpp | 1 + src/engine/sample.h | 2 ++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 4dbea03bf..06c0754ed 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -948,6 +948,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (ds.version<=0x08) { sample->centerRate=ymuSampleRate*400; } + sample->legacyRate=sample->centerRate; if (ds.version>0x15) { sample->depth=(DivSampleDepth)reader.readC(); if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp index 2b0299d28..faf91086a 100644 --- a/src/engine/legacySample.cpp +++ b/src/engine/legacySample.cpp @@ -32,6 +32,61 @@ bool DivEngine::convertLegacySampleMode() { return false; } + // check which samples are used by instruments so we don't touch them + bool* isUsedByIns=new bool[MAX(1,song.sample.size())]; + memset(isUsedByIns,0,MAX(1,song.sample.size())*sizeof(bool)); + for (DivInstrument* ins: song.ins) { + bool canUse=false; + if (ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_MSM6295 || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB || + ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_QSOUND || + ins->type==DIV_INS_YMZ280B || + ins->type==DIV_INS_RF5C68 || + ins->type==DIV_INS_AMIGA || + ins->type==DIV_INS_MULTIPCM || + ins->type==DIV_INS_SNES || + ins->type==DIV_INS_ES5506 || + ins->type==DIV_INS_K007232 || + ins->type==DIV_INS_GA20 || + ins->type==DIV_INS_K053260 || + ins->type==DIV_INS_C140 || + ins->type==DIV_INS_C219 || + ins->type==DIV_INS_NDS || + ins->type==DIV_INS_GBA_DMA || + ins->type==DIV_INS_GBA_MINMOD || + ins->type==DIV_INS_NES || + ins->type==DIV_INS_SUPERVISION) { + canUse=true; + } + if (ins->type==DIV_INS_SU || + ins->type==DIV_INS_AY || + ins->type==DIV_INS_AY8930 || + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_PCE || + ins->type==DIV_INS_X1_010 || + ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_VRC6) { + if (ins->amiga.useSample) canUse=true; + } + + if (canUse) { + if (ins->amiga.useNoteMap) { + for (int i=0; i<120; i++) { + if (ins->amiga.noteMap[i].map>=0 && ins->amiga.noteMap[i].map<(int)song.sample.size()) { + isUsedByIns[ins->amiga.noteMap[i].map]=true; + } + } + } else { + if (ins->amiga.initSample>=0 && ins->amiga.initSample<(int)song.sample.size()) { + isUsedByIns[ins->amiga.initSample]=true; + } + } + } + } + auto initSampleInsIfNeeded=[this,&legacyInsInit]() { if (legacyInsInit==-1) { legacyInsInit=(int)song.ins.size(); @@ -293,8 +348,15 @@ bool DivEngine::convertLegacySampleMode() { // we've got a note if (sampleMode==1) { initSampleInsIfNeeded(); - //p->newData[k][DIV_PAT_NOTE]=60+12*sampleBank+(p->newData[k][DIV_PAT_NOTE]%12); p->newData[k][DIV_PAT_INS]=MIN(0xff,legacyInsInit+sampleBank); + + int involvedSample=12*sampleBank+(p->newData[k][DIV_PAT_NOTE]%12); + if (involvedSample>=0 && involvedSamplecenterRate=sample->legacyRate; + } + } } } else if (p->newData[k][DIV_PAT_NOTE]==DIV_NOTE_OFF && noteOffDisablesSampleMode) { sampleMode=0; diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 03a6d1089..a52d937b7 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -118,6 +118,7 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) { } // just in case it's not new sample, it's a very old version and we gotta read a rate. centerRate=reader.readI(); + legacyRate=centerRate; if (isNewSample) { centerRate=reader.readI(); diff --git a/src/engine/sample.h b/src/engine/sample.h index 9f30c44af..975eac6e0 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -104,6 +104,7 @@ struct DivSampleHistory { struct DivSample { String name; int centerRate, loopStart, loopEnd; + int legacyRate; // valid values are: // - 0: ZX Spectrum overlay drum (1-bit) // - 1: 1-bit NES DPCM (1-bit) @@ -338,6 +339,7 @@ struct DivSample { centerRate(8363), loopStart(-1), loopEnd(-1), + legacyRate(32000), depth(DIV_SAMPLE_DEPTH_16BIT), loop(false), brrEmphasis(true), From 9e41e509a095b723461030fefdf836b6cd3cff83 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 19:22:49 -0500 Subject: [PATCH 20/25] total extinction of legacy sample mode, part 8 fix conversion memory leak add reverse conversion for .dmf export --- src/engine/fileOps/dmf.cpp | 135 +++++++++++++++++++++++++++++++++++- src/engine/legacySample.cpp | 2 + 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 06c0754ed..7a7f06918 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1646,8 +1646,139 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { short note, octave; w->writeC(curPat[i].effectCols); + bool convertSampleUsage=false; + int convIns=-1; + bool isConverting=false; + bool alwaysConvert=false; + + switch (sys) { + case DIV_SYSTEM_GENESIS: + if (i==5) convertSampleUsage=true; + break; + case DIV_SYSTEM_GENESIS_EXT: + if (i==8) convertSampleUsage=true; + break; + case DIV_SYSTEM_PCE: + convertSampleUsage=true; + break; + case DIV_SYSTEM_NES: + if (i==4) { + convertSampleUsage=true; + alwaysConvert=true; + } + break; + case DIV_SYSTEM_ARCADE: + if (i>=8) { + convertSampleUsage=true; + alwaysConvert=true; + } + break; + case DIV_SYSTEM_YM2610: + if (i>=7) { + convertSampleUsage=true; + alwaysConvert=true; + } + break; + case DIV_SYSTEM_YM2610_EXT: + if (i>=10) { + convertSampleUsage=true; + alwaysConvert=true; + } + break; + default: + break; + } + for (int j=0; jordersLen; j++) { - DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][j],false); + // we make a copy in order to convertFurnace sample mode to Defle one + DivPattern* origPat=curPat[i].getPattern(curOrders->ord[i][j],false); + DivPattern* pat=new DivPattern; + origPat->copyOn(pat); + + if (convertSampleUsage) { + for (int k=0; kpatLen; k++) { + int insert17xx=-1; + int insertEBxx=-1; + + if (pat->newData[k][DIV_PAT_INS]!=-1) { + if (pat->newData[k][DIV_PAT_INS]>=0 && pat->newData[k][DIV_PAT_INS]newData[k][DIV_PAT_INS]; + } else { + convIns=-1; + } + + bool willBeConverting=false; + if (convIns>=0 && convInstype==DIV_INS_AMIGA || + convInsInst->type==DIV_INS_ADPCMA || + convInsInst->type==DIV_INS_SEGAPCM || + (convInsInst->type==DIV_INS_PCE && convInsInst->amiga.useSample)) { + willBeConverting=true; + } + } + + if (isConverting!=willBeConverting) { + if (!alwaysConvert) { + if (willBeConverting) { + insert17xx=1; + } else { + insert17xx=0; + } + } + isConverting=willBeConverting; + } + + if (isConverting || alwaysConvert) { + pat->newData[k][DIV_PAT_INS]=-1; + } + } + + if (pat->newData[k][DIV_PAT_NOTE]!=-1 && pat->newData[k][DIV_PAT_NOTE]!=DIV_NOTE_OFF && pat->newData[k][DIV_PAT_NOTE]!=DIV_NOTE_REL && pat->newData[k][DIV_PAT_NOTE]!=DIV_MACRO_REL) { + if (isConverting || alwaysConvert) { + if (convIns>=0 && convInsamiga.useNoteMap) { + int mapTarget=pat->newData[k][DIV_PAT_NOTE]-60; + if (mapTarget<0) mapTarget=0; + if (mapTarget>119) mapTarget=119; + insertEBxx=convInsInst->amiga.noteMap[mapTarget].map/12; + pat->newData[k][DIV_PAT_NOTE]=(12*(pat->newData[k][DIV_PAT_NOTE]/12))+(convInsInst->amiga.noteMap[mapTarget].map%12); + } else { + insertEBxx=convInsInst->amiga.initSample/12; + pat->newData[k][DIV_PAT_NOTE]=(12*(pat->newData[k][DIV_PAT_NOTE]/12))+(convInsInst->amiga.initSample%12); + } + } + } + } + + if (insert17xx!=-1) { + int freeSlot=0; + for (int l=0; lnewData[k][DIV_PAT_FX(l)]==-1) { + freeSlot=l; + break; + } + } + + pat->newData[k][DIV_PAT_FX(freeSlot)]=0x17; + pat->newData[k][DIV_PAT_FXVAL(freeSlot)]=insert17xx; + } + if (insertEBxx!=-1) { + int freeSlot=1; + for (int l=0; lnewData[k][DIV_PAT_FX(l)]==-1) { + freeSlot=l; + break; + } + } + + pat->newData[k][DIV_PAT_FX(freeSlot)]=0xeb; + pat->newData[k][DIV_PAT_FXVAL(freeSlot)]=insertEBxx; + } + } + } + for (int k=0; kpatLen; k++) { if (pat->newData[k][DIV_PAT_NOTE]==DIV_NOTE_REL || pat->newData[k][DIV_PAT_NOTE]==DIV_MACRO_REL) { w->writeS(100); @@ -1671,6 +1802,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { #endif w->writeS(pat->newData[k][DIV_PAT_INS]); // instrument } + + delete pat; } } diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp index faf91086a..dbaab38c5 100644 --- a/src/engine/legacySample.cpp +++ b/src/engine/legacySample.cpp @@ -366,5 +366,7 @@ bool DivEngine::convertLegacySampleMode() { } } + delete[] isUsedByIns; + return (legacyInsInit!=-1); } From edb139505868d566c029ef3815d99d4f9330a6a9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 19:40:04 -0500 Subject: [PATCH 21/25] total extinction of legacy sample mode, part 9 fix .dmf export a bit --- src/engine/fileOps/dmf.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 7a7f06918..dd4f93281 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1647,8 +1647,6 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeC(curPat[i].effectCols); bool convertSampleUsage=false; - int convIns=-1; - bool isConverting=false; bool alwaysConvert=false; switch (sys) { @@ -1690,12 +1688,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } for (int j=0; jordersLen; j++) { - // we make a copy in order to convertFurnace sample mode to Defle one + // we make a copy in order to convert Furnace sample mode to Defle one DivPattern* origPat=curPat[i].getPattern(curOrders->ord[i][j],false); DivPattern* pat=new DivPattern; origPat->copyOn(pat); if (convertSampleUsage) { + int convIns=-1; + bool isConverting=false; for (int k=0; kpatLen; k++) { int insert17xx=-1; int insertEBxx=-1; @@ -1754,6 +1754,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { if (insert17xx!=-1) { int freeSlot=0; + logV("insert 17xx at %d:[%d]:%d (%d)",i,j,k,insert17xx); for (int l=0; lnewData[k][DIV_PAT_FX(l)]==-1) { freeSlot=l; From 9e8c97cc6f445ade0f84223b7fb5de5451118777 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 9 Nov 2025 20:42:38 -0500 Subject: [PATCH 22/25] heuristic for song length determination song length calculation of lorge.fur now takes 18ms (from ~1 hour) --- src/engine/engine.cpp | 13 +++++++++++++ src/engine/engine.h | 1 + src/engine/song.cpp | 37 +++++++++++++++++++++++++++++-------- src/engine/song.h | 2 +- src/gui/debugWindow.cpp | 4 ++-- src/main.cpp | 10 +++++++--- 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0f1c30822..b7935803d 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -264,6 +264,19 @@ double DivEngine::benchmarkSeek() { return tAvg; } +double DivEngine::benchmarkWalk() { + std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); + + // benchmark + calcSongTimestamps(); + + std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); + + double t=(double)(std::chrono::duration_cast(timeEnd-timeStart).count())/1000000.0; + printf("[RESULT] %fs\n",t); + return t; +} + void DivEngine::notifyInsChange(int ins) { BUSY_BEGIN; for (int i=0; i #include TimeMicros DivSongTimestamps::getTimes(int order, int row) { @@ -347,22 +348,40 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove // MAKE IT WORK while (!endOfSong) { + // heuristic + int advance=(curVirtualTempoD*ticks)/curVirtualTempoN; + for (int i=0; i0) { + if (rowDelay[i]0) { - if (--rowDelay[i]==0) { + rowDelay[i]-=advance; + if (rowDelay[i]==0) { tinyProcessRow(i,true); } } } // run virtual tempo - tempoAccum+=curVirtualTempoN; + tempoAccum+=curVirtualTempoN*advance; while (tempoAccum>=curVirtualTempoD) { - tempoAccum-=curVirtualTempoD; + int ticksToRun=tempoAccum/curVirtualTempoD; + tempoAccum%=curVirtualTempoD; // tick counter - if (--ticks<=0) { + ticks-=ticksToRun; + if (ticks<0) { + // if ticks is negative, we must call ticks back + tempoAccum+=-ticks*curVirtualTempoD; + } + if (ticks<=0) { if (shallStopSched) { shallStop=true; break; @@ -400,8 +419,8 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove if (!endOfSong) { // update playback time - double dt=divider;//*((double)virtualTempoN/(double)MAX(1,virtualTempoD)); - ts.totalTicks++; + double dt=divider/(double)advance;//*((double)virtualTempoN/(double)MAX(1,virtualTempoD)); + ts.totalTicks+=advance; ts.totalTime.micros+=1000000/dt; totalMicrosOff+=fmod(1000000.0,dt); @@ -410,9 +429,10 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove ts.totalTime.micros++; } if (ts.totalTime.micros>=1000000) { - ts.totalTime.micros-=1000000; // who's gonna play a song for 68 years? - if (ts.totalTime.seconds<0x7fffffff) ts.totalTime.seconds++; + ts.totalTime.seconds+=ts.totalTime.micros/1000000; + if (ts.totalTime.seconds<0) ts.totalTime.seconds=INT_MAX; + ts.totalTime.micros%=1000000; } } if (ts.maxRow[curOrder]& groove std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); logV("calcTimestamps() took %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); + logV("song length: %s; %" PRIu64 " ticks",ts.totalTime.toString(6,TA_TIME_FORMAT_AUTO),ts.totalTicks); } void DivSubSong::clearData() { diff --git a/src/engine/song.h b/src/engine/song.h index 437e1159e..4b6e1b7fc 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -171,7 +171,7 @@ struct DivGroovePattern { struct DivSongTimestamps { // song duration (in seconds and microseconds) TimeMicros totalTime; - int totalTicks; + uint64_t totalTicks; int totalRows; // loop region (order/row positions) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 1b3ba9259..dfd809e84 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -21,7 +21,7 @@ #include "guiConst.h" #include "debug.h" #include "IconsFontAwesome4.h" -#include +#include #include #include "imgui.h" #include "imgui_internal.h" @@ -208,7 +208,7 @@ void FurnaceGUI::drawDebug() { DivSongTimestamps& ts=e->curSubSong->ts; String timeFormatted=ts.totalTime.toString(-1,TA_TIME_FORMAT_AUTO); - ImGui::Text("song duration: %s (%d ticks; %d rows)",timeFormatted.c_str(),ts.totalTicks,ts.totalRows); + ImGui::Text("song duration: %s (%" PRIu64 " ticks; %d rows)",timeFormatted.c_str(),ts.totalTicks,ts.totalRows); if (ts.isLoopDefined) { ImGui::Text("loop region is defined"); } else { diff --git a/src/main.cpp b/src/main.cpp index 28706699e..51bc477f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -539,8 +539,10 @@ TAParamResult pBenchmark(String val) { benchMode=1; } else if (val=="seek") { benchMode=2; + } else if (val=="walk") { + benchMode=3; } else { - logE("invalid value for benchmark! valid values are: render and seek."); + logE("invalid value for benchmark! valid values are: render, seek and walk."); return TA_PARAM_ERROR; } e.setAudio(DIV_AUDIO_DUMMY); @@ -653,7 +655,7 @@ void initParams() { params.push_back(TAParam("S","safemode",false,pSafeMode,"","enable safe mode (software rendering and no audio)")); params.push_back(TAParam("A","safeaudio",false,pSafeModeAudio,"","enable safe mode (with audio")); - params.push_back(TAParam("B","benchmark",true,pBenchmark,"render|seek","run performance test")); + params.push_back(TAParam("B","benchmark",true,pBenchmark,"render|seek|walk","run performance test")); params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace.")); params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer.")); @@ -1031,7 +1033,9 @@ int main(int argc, char** argv) { if (benchMode) { logI("starting benchmark!"); - if (benchMode==2) { + if (benchMode==3) { + e.benchmarkWalk(); + } else if (benchMode==2) { e.benchmarkSeek(); } else { e.benchmarkPlayback(); From 55c3966eda7b930953cbc81c9ce0c8e83d8a5f5d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 10 Nov 2025 04:43:45 -0500 Subject: [PATCH 23/25] total extinction of legacy sample mode, part 10 it's ready! you must merge, now! --- src/engine/legacySample.cpp | 17 +++++++++++++++++ src/engine/platform/nes.cpp | 2 +- src/gui/tutorial.cpp | 12 ++++++++++-- test/furnace-test.sh | 2 +- test/last-stage.sh | 11 +++++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100755 test/last-stage.sh diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp index dbaab38c5..21734c903 100644 --- a/src/engine/legacySample.cpp +++ b/src/engine/legacySample.cpp @@ -133,6 +133,7 @@ bool DivEngine::convertLegacySampleMode() { continue; } sampleMode=1; + preferredInsType=DIV_INS_NES; break; case DIV_SYSTEM_MMC5: // MMC5 PCM channel @@ -186,6 +187,22 @@ bool DivEngine::convertLegacySampleMode() { preferredInsType=DIV_INS_ADPCMA; preferredInsType2=DIV_INS_ADPCMB; break; + case DIV_SYSTEM_YM2612_DUALPCM: + // DualPCM DAC + if (dispatchChanOfChan[i]<5) { + continue; + } + sampleMode=1; + hasLegacyToggle=true; + break; + case DIV_SYSTEM_YM2612_DUALPCM_EXT: + // DualPCM DAC + if (dispatchChanOfChan[i]<8 || dispatchChanOfChan[i]>9) { + continue; + } + sampleMode=1; + hasLegacyToggle=true; + break; case DIV_SYSTEM_YM2610_CSM: // Neo Geo CD ADPCM channels if (dispatchChanOfChan[i]<11) { diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 0fcb9fa80..d56b57288 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -424,7 +424,7 @@ void DivPlatformNES::tick(bool sysTick) { DivSample* s=parent->getSample(dacSample); off=(double)s->centerRate/parent->getCenterRate(); } - dacRate=MIN(chan[4].freq*off,32000); + dacRate=MIN(chan[4].freq*off,48000); if (chan[4].keyOn) { if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSamplesong.sampleLen) { unsigned int dpcmAddr=sampleOffDPCM[dacSample]+(dacPos>>3); diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index 50812fbd2..d1d5901a4 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -180,6 +180,9 @@ struct FurnaceCV { // this offset is applied to sprites. int viewX, viewY; + // other + char hiScoreText[512]; + // input unsigned char joyInputPrev; unsigned char joyPressed; @@ -666,7 +669,11 @@ static const char* cvText[]={ _N("GAME OVER"), - _N("High Score!"), + _N(" CONGREGURATION\n\n\n" + "YOU ARE GOOD PLAY AT GAME\n" + "PRESS ESCAPE TO RESET GAME\n\n" + "AND PLAY AGAIN AT ELEVATED DIFFICULTY\n\n\n" + "%d SCORES THIS GAME"), _N("Welcome to Combat Vehicle!\n\n" "Controls:\n" @@ -1695,7 +1702,8 @@ void FurnaceCV::render(unsigned char joyIn) { } memset(tile0,0,80*56*sizeof(short)); memset(tile1,0,80*56*sizeof(short)); - startTyping(_(cvText[3]),2,3); + snprintf(hiScoreText,511,_(cvText[3]),hiScore); + startTyping(hiScoreText,2,3); e->setConf("cvHiScore",hiScore); e->saveConf(); curText=4; diff --git a/test/furnace-test.sh b/test/furnace-test.sh index c6e0f8f40..1bf5525f5 100755 --- a/test/furnace-test.sh +++ b/test/furnace-test.sh @@ -41,7 +41,7 @@ else echo "OK" else echo "FAIL FAIL FAIL" - ffmpeg -loglevel quiet -i "test/delta/$testDir/$i" -lavfi showspectrumpic "test/delta/$testDir/$i.png" + ffmpeg -loglevel quiet -i "test/delta/$testDir/$i" -lavfi showspectrumpic -y "test/delta/$testDir/$i.png" fi done fi diff --git a/test/last-stage.sh b/test/last-stage.sh new file mode 100755 index 000000000..cff8aab90 --- /dev/null +++ b/test/last-stage.sh @@ -0,0 +1,11 @@ +#!/bin/bash +testDir=20251109215858 +if ./assert_delta "delta/$testDir/$1"; then + true + #echo "OK" +else +echo -n "$1... " + echo "FAIL FAIL FAIL" + mpv "delta/$testDir/$1" + #ffmpeg -loglevel quiet -i "test/delta/$testDir/$1" -lavfi showspectrumpic -y "test/delta/$testDir/$1.png" +fi From 5190d7b9e68984921b7104c7f711cbbf356d817d Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Mon, 10 Nov 2025 18:34:41 +0400 Subject: [PATCH 24/25] keyboard shortcuts for opening the new windows --- src/gui/settings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 136640a2a..7c785d169 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2268,6 +2268,9 @@ void FurnaceGUI::drawSettings() { drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_EFFECT_LIST); drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_DEBUG); drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_CS_PLAYER); + drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_REF_PLAYER); + drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_TUNER); + drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_SPECTRUM); drawKeybindSettingsTableRow(GUI_ACTION_WINDOW_ABOUT); drawKeybindSettingsTableRow(GUI_ACTION_COLLAPSE_WINDOW); drawKeybindSettingsTableRow(GUI_ACTION_CLOSE_WINDOW); From d3ce1a0b8453a32d76f5abb5ab459a0eab690062 Mon Sep 17 00:00:00 2001 From: recme Date: Sat, 8 Nov 2025 13:23:53 -0500 Subject: [PATCH 25/25] Saves edit step and coarse step number between instances --- src/gui/gui.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 3a1592c79..e80930911 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -8341,6 +8341,8 @@ void FurnaceGUI::syncState() { orderLock=e->getConfBool("orderLock",false); followOrders=e->getConfBool("followOrders",true); followPattern=e->getConfBool("followPattern",true); + editStep=e->getConfInt("editStep",1); + editStepCoarse=e->getConfInt("editStepCoarse",16); noteInputMode=e->getConfInt("noteInputMode",GUI_NOTE_INPUT_POLY); if (noteInputMode!=GUI_NOTE_INPUT_MONO && noteInputMode!=GUI_NOTE_INPUT_POLY && noteInputMode!=GUI_NOTE_INPUT_CHORD) { noteInputMode=GUI_NOTE_INPUT_POLY; @@ -8513,6 +8515,8 @@ void FurnaceGUI::commitState(DivConfig& conf) { conf.set("orderLock",orderLock); conf.set("followOrders",followOrders); conf.set("followPattern",followPattern); + conf.set("editStep",editStep); + conf.set("editStepCoarse",editStepCoarse); conf.set("orderEditMode",orderEditMode); conf.set("noteInputMode",(int)noteInputMode); conf.set("filePlayerSync",filePlayerSync);