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/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. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b7935803d..0d00756ec 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/engine.h b/src/engine/engine.h index 71842de23..b1ebc6765 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 @@ -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 8593993ef..dd4f93281 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,8 +946,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } if (ds.version<=0x08) { - sample->rate=ymuSampleRate*400; + 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) { @@ -1176,6 +1176,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) { @@ -1644,8 +1646,140 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { short note, octave; w->writeC(curPat[i].effectCols); + bool convertSampleUsage=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 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; + + 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; + 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; + 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); @@ -1669,6 +1803,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { #endif w->writeS(pat->newData[k][DIV_PAT_INS]); // instrument } + + delete pat; } } @@ -1680,7 +1816,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/fur.cpp b/src/engine/fileOps/fur.cpp index 8acc5285b..f3a0ad4b8 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2188,6 +2188,12 @@ 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) { + if (convertLegacySampleMode()) { + addWarning("Furnace no longer supports legacy sample mode. your song has been converted."); + } + } saveLock.unlock(); BUSY_END; if (active) { 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/legacySample.cpp b/src/engine/legacySample.cpp new file mode 100644 index 000000000..21734c903 --- /dev/null +++ b/src/engine/legacySample.cpp @@ -0,0 +1,389 @@ +/** + * 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" +#include + +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; + } + + // 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(); + 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; + 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.insLen=song.ins.size(); + checkAssetDir(song.insDir,song.ins.size()); + } + }; + + for (DivSubSong* h: song.subsong) { + for (int i=0; i9) { + continue; + } + sampleMode=1; + hasLegacyToggle=true; + 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) { + continue; + } + sampleMode=1; + preferredInsType=DIV_INS_ADPCMA; + preferredInsType2=DIV_INS_ADPCMB; + break; + case DIV_SYSTEM_YM2610B_EXT: + // ADPCM channels + if (dispatchChanOfChan[i]<12) { + continue; + } + sampleMode=1; + 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; + } + + logV("- channel %d",i); + + bool didThisPattern[DIV_MAX_PATTERNS]; + memset(didThisPattern,0,DIV_MAX_PATTERNS*sizeof(bool)); + + for (int j=0; jordersLen; 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 (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; + } + 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_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; + } + } + } + } + } + + delete[] isUsedByIns; + + return (legacyInsInit!=-1); +} diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 00e02905b..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,76 +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; + 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 (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); + //addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); } - chan[c.chan].dac.furnaceDAC=false; } + 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; @@ -950,12 +923,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; @@ -1086,7 +1053,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..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; @@ -121,7 +120,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 2190202e9..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,74 +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; + 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 (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); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); } - chan[c.chan].dac.furnaceDAC=false; } + 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; @@ -772,12 +745,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; @@ -895,7 +862,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..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; @@ -111,8 +110,6 @@ class DivPlatformAY8930: public DivDispatch { unsigned char stereoSep; bool bank; - unsigned char sampleBank; - int delay; int lastOut[2]; 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.cpp b/src/engine/platform/genesis.cpp index d163daec5..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) { @@ -1108,25 +1103,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; } @@ -1269,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) { @@ -1301,13 +1278,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; @@ -1323,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/genesis.h b/src/engine/platform/genesis.h index 82495bdef..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; @@ -46,11 +45,9 @@ class DivPlatformGenesis: public DivPlatformOPN { int dacDelay; bool dacDirection; bool setPos; - unsigned char sampleBank; signed char dacOutput; Channel(): FMChannelStereo(), - furnaceDac(false), dacMode(false), dacPeriod(0), dacRate(0), @@ -59,7 +56,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 fcb8dbdc6..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,59 +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 { - 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; + 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) { @@ -323,12 +297,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; @@ -422,7 +390,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..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]; @@ -49,7 +48,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..8fbcccaad 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -162,39 +162,18 @@ 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; - } - } else { - chan[c.chan].sample=-1; - 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; - if ((12*sampleBank+c.value%12)<0 || (12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; + } + 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; } - //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; } @@ -238,12 +217,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 +333,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..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) {} }; @@ -48,7 +46,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..c084802f1 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -161,40 +161,19 @@ 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<=parent->song.sampleLen) { - break; + } + 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; } - //DivSample* s=parent->getSample(12*sampleBank+c.value%12); - chan[c.chan].sample=12*sampleBank+c.value%12; + chan[c.chan].active=true; + chan[c.chan].keyOn=true; rWriteDelay(0,(8<(parent->song.sample.size()/12)) { - sampleBank=parent->song.sample.size()/12; - } - break; case DIV_CMD_LEGATO: { break; } @@ -335,7 +308,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..d65826e57 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -27,11 +27,9 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { protected: struct Channel: public SharedChannel { - bool furnacePCM; int sample; Channel(): SharedChannel(8), - furnacePCM(false), sample(-1) {} }; Channel chan[4]; @@ -53,7 +51,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 7ef5db9f6..d56b57288 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,48000); + 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,111 +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; - } 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; - 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(0x4010,0); + rWrite(0x4012,0); + rWrite(0x4013,0); rWrite(0x4015,31); - if (dpcmBank!=(dpcmAddr>>14)) { - dpcmBank=dpcmAddr>>14; - logV("switching bank to %d",dpcmBank); - if (dumpWrites) addWrite(0xffff0004,dpcmBank); + } + + 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) { + 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) { @@ -779,12 +731,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; @@ -900,7 +846,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..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]; @@ -59,7 +58,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 4b7268f13..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,75 +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)); - } - 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; - } - } else { - chan[c.chan].sample=-1; - chan[c.chan].macroInit(NULL); + 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; - 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); + 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].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; } break; } @@ -2087,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; @@ -2155,14 +2114,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) { @@ -2935,7 +2886,6 @@ void DivPlatformOPL::reset() { lastBusy=60; lfoValue=8; drumState=0; - sampleBank=0; drumVol[0]=0; drumVol[1]=0; @@ -3498,7 +3448,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); } @@ -3506,7 +3455,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..b06b95962 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 { @@ -60,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; @@ -71,7 +70,6 @@ class DivPlatformOPL: public DivDispatch { freqL(0), sample(-1), fixedFreq(0), - furnacePCM(false), fourOp(false), hardReset(false), writeCtrl(false), @@ -134,7 +132,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/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 1a84a2504..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,79 +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 { - 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); - } + 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; } @@ -491,12 +460,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; @@ -630,7 +593,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..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), @@ -70,7 +69,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 eaebf022e..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,56 +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 { - 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; + 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: @@ -310,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: { @@ -332,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; @@ -341,14 +311,9 @@ 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_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; @@ -488,7 +453,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..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), @@ -68,7 +67,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 e7430096e..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,54 +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 { - 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; + 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; } } @@ -544,12 +522,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; @@ -675,14 +647,12 @@ void DivPlatformSwan::reset() { swan_sound_init(&ws, true); 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,0x0f); // enable speakers, minimum headphone volume } diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index e3ea745f9..64707d805 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -41,8 +41,8 @@ class DivPlatformSwan: public DivDispatch { bool isMuted[4]; bool stereo; bool useMdfn; - bool pcm, sweep, furnaceDac, setPos; - unsigned char sampleBank, noise; + bool pcm, sweep, setPos; + 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 a7ae0d3da..18a7be76a 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; } @@ -432,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; @@ -535,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 9599b06b4..36f0d26ee 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; @@ -739,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); @@ -919,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 11a1b72c2..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,99 +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); - } - 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; - } - } else { - chan[c.chan].sample=-1; - 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; - 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; + 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].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; } 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)); } @@ -1366,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; @@ -1421,18 +1366,10 @@ 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); } - 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); @@ -1913,7 +1850,6 @@ void DivPlatformYM2608::reset() { lastBusy=60; lfoValue=8; - sampleBank=0; writeRSSOff=0; writeRSSOn=0; globalRSSVolume=0x3f; @@ -2116,7 +2052,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 5a92212c3..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,144 +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); - } - 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; - } - } else { - chan[c.chan].sample=-1; - 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; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; + 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].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } - 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; - } + 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; } 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; - } - } else { - chan[c.chan].sample=-1; - 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; - 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; + } + 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; } break; } @@ -1325,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; @@ -1380,15 +1306,7 @@ 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) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } @@ -1820,7 +1738,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 78bed5eda..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,144 +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); - } - 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; - } - } else { - chan[c.chan].sample=-1; - 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; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - break; + 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].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; } - 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; - } + 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; } 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; - } - } else { - chan[c.chan].sample=-1; - 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; - 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; + } + 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; } break; } @@ -1394,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; @@ -1449,15 +1375,7 @@ 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) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); } @@ -1889,7 +1807,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/engine/sample.cpp b/src/engine/sample.cpp index e506321d1..a52d937b7 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,9 @@ 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(); + legacyRate=centerRate; if (isNewSample) { centerRate=reader.readI(); @@ -916,7 +918,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 +1666,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 +1696,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..975eac6e0 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,8 @@ struct DivSampleHistory { struct DivSample { String name; - int rate, centerRate, loopStart, loopEnd; + int centerRate, loopStart, loopEnd; + int legacyRate; // valid values are: // - 0: ZX Spectrum overlay drum (1-bit) // - 1: 1-bit NES DPCM (1-bit) @@ -337,10 +336,10 @@ struct DivSample { int redo(); DivSample(): name(""), - rate(32000), centerRate(8363), loopStart(-1), loopEnd(-1), + legacyRate(32000), depth(DIV_SAMPLE_DEPTH_16BIT), loop(false), brrEmphasis(true), diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 77ccbf052..798c5f1c4 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -749,4 +749,4 @@ void DivSong::unload() { delete i; } subsong.clear(); -} +} \ No newline at end of file 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)")}}, diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 9097c2dcf..a77e4af1f 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,9 +163,7 @@ 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"); \ ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \ @@ -203,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; \ @@ -229,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); \ @@ -265,7 +260,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 +270,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 +311,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 +328,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 +371,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 +378,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 +406,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 +433,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 +455,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; } @@ -708,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: { @@ -720,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: { @@ -771,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; } @@ -788,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: { @@ -805,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: { @@ -842,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"); @@ -881,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: { diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index dfd809e84..8e152ebec 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; 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