From 29ea6dc360a27a3480c9f9b966909f501d4879b7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 21 Apr 2022 01:52:37 +0900 Subject: [PATCH 01/74] Partially ES5506 support (not working yet!) Add sample related enums Add support for backward/pingpong loop, loop end position Structize Notemap in sample instrument --- CMakeLists.txt | 8 + TODO.md | 8 + src/engine/dispatchContainer.cpp | 4 + src/engine/engine.cpp | 52 +- src/engine/engine.h | 10 +- src/engine/fileOps.cpp | 39 +- src/engine/instrument.cpp | 16 +- src/engine/instrument.h | 56 +- src/engine/platform/amiga.cpp | 4 +- src/engine/platform/es5506.cpp | 638 ++++++++++++++ src/engine/platform/es5506.h | 173 ++++ src/engine/platform/genesis.cpp | 10 +- src/engine/platform/mmc5.cpp | 5 +- src/engine/platform/nes.cpp | 5 +- src/engine/platform/pce.cpp | 4 +- src/engine/platform/qsound.cpp | 4 +- src/engine/platform/segapcm.cpp | 8 +- src/engine/platform/sound/es550x/es5504.cpp | 444 ++++++++++ src/engine/platform/sound/es550x/es5504.hpp | 87 ++ src/engine/platform/sound/es550x/es5505.cpp | 599 +++++++++++++ src/engine/platform/sound/es550x/es5505.hpp | 141 ++++ src/engine/platform/sound/es550x/es5506.cpp | 787 ++++++++++++++++++ src/engine/platform/sound/es550x/es5506.hpp | 179 ++++ src/engine/platform/sound/es550x/es550x.cpp | 75 ++ src/engine/platform/sound/es550x/es550x.hpp | 391 +++++++++ .../platform/sound/es550x/es550x_alu.cpp | 116 +++ .../platform/sound/es550x/es550x_filter.cpp | 70 ++ src/engine/platform/swan.cpp | 4 +- src/engine/platform/vera.cpp | 4 +- src/engine/platform/vrc6.cpp | 4 +- src/engine/platform/ym2610.cpp | 8 +- src/engine/platform/ym2610b.cpp | 8 +- src/engine/playback.cpp | 119 ++- src/engine/sample.cpp | 228 ++--- src/engine/sample.h | 69 +- src/engine/song.h | 3 +- src/engine/sysDef.cpp | 25 +- src/engine/vgmOps.cpp | 75 +- src/gui/dataList.cpp | 4 + src/gui/doAction.cpp | 2 + src/gui/gui.h | 1 + src/gui/guiConst.cpp | 16 +- src/gui/guiConst.h | 3 +- src/gui/insEdit.cpp | 78 +- src/gui/intConst.cpp | 3 + src/gui/intConst.h | 3 + src/gui/presets.cpp | 6 + src/gui/sampleEdit.cpp | 136 ++- src/gui/stats.cpp | 4 + src/gui/sysConf.cpp | 13 +- 50 files changed, 4501 insertions(+), 248 deletions(-) create mode 100644 src/engine/platform/es5506.cpp create mode 100644 src/engine/platform/es5506.h create mode 100644 src/engine/platform/sound/es550x/es5504.cpp create mode 100644 src/engine/platform/sound/es550x/es5504.hpp create mode 100644 src/engine/platform/sound/es550x/es5505.cpp create mode 100644 src/engine/platform/sound/es550x/es5505.hpp create mode 100644 src/engine/platform/sound/es550x/es5506.cpp create mode 100644 src/engine/platform/sound/es550x/es5506.hpp create mode 100644 src/engine/platform/sound/es550x/es550x.cpp create mode 100644 src/engine/platform/sound/es550x/es550x.hpp create mode 100644 src/engine/platform/sound/es550x/es550x_alu.cpp create mode 100644 src/engine/platform/sound/es550x/es550x_filter.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 498f3df69..e529f49ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,6 +292,13 @@ src/engine/platform/sound/vic20sound.c src/engine/platform/sound/vrcvi/vrcvi.cpp +src/engine/platform/sound/es550x/es550x.cpp +src/engine/platform/sound/es550x/es550x_alu.cpp +src/engine/platform/sound/es550x/es550x_filter.cpp +src/engine/platform/sound/es550x/es5504.cpp +src/engine/platform/sound/es550x/es5505.cpp +src/engine/platform/sound/es550x/es5506.cpp + src/engine/platform/ym2610Interface.cpp src/engine/blip_buf.c @@ -348,6 +355,7 @@ src/engine/platform/n163.cpp src/engine/platform/pet.cpp src/engine/platform/vic20.cpp src/engine/platform/vrc6.cpp +src/engine/platform/es5506.cpp src/engine/platform/dummy.cpp ) diff --git a/TODO.md b/TODO.md index d9817937e..2077bbae1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,11 @@ +# to-do for ES5506 + +- make sound produces actually +- filter, envelope macro, commands +- envelope shape +- reversed playing flag in instrument/macro/commands +- transwave synthesizer (like ensoniq synths - 12 bit command and macro) + # to-do for 0.6pre1 - panning macro diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 4f4ecf398..9e5cd4b80 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -53,6 +53,7 @@ #include "platform/vrc6.h" #include "platform/fds.h" #include "platform/mmc5.h" +#include "platform/es5506.h" #include "platform/dummy.h" #include "../ta-log.h" #include "song.h" @@ -311,6 +312,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do case DIV_SYSTEM_MMC5: dispatch=new DivPlatformMMC5; break; + case DIV_SYSTEM_ES5506: + dispatch=new DivPlatformES5506; + break; default: logW("this system is not supported yet! using dummy platform."); dispatch=new DivPlatformDummy; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 81d7947a7..290e154d9 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -495,6 +495,7 @@ void DivEngine::renderSamplesP() { void DivEngine::renderSamples() { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; // step 1: render samples for (int i=0; ilength16; + // fit sample size to single bank size + if (length>2097152*sizeof(short)) { + length=2097152*sizeof(short); + } + if ((memPos&0xc00000)!=((memPos+length)&0xc00000)) { + memPos=(memPos+0x3fffff)&0xc00000; + } + if (memPos>=16777216) { + logW("out of ES5506 memory for sample %d!",i); + break; + } + if (memPos+length>=16777216) { + memcpy(es5506Mem+memPos,s->data16,16777216-memPos); + logW("out of ES5506 memory for sample %d!",i); + } else { + memcpy(es5506Mem+memPos,s->data16,length); + } + s->offES5506=memPos; + memPos+=length; + } + es5506MemLen=memPos+256; } void DivEngine::createNew(const int* description) { @@ -897,6 +928,7 @@ void DivEngine::play() { sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; if (stepPlay==0) { freelance=false; playSub(false); @@ -919,6 +951,7 @@ void DivEngine::playToRow(int row) { sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; freelance=false; playSub(false,row); for (int i=0; inotifyPlaybackStop(); } @@ -1093,6 +1127,8 @@ int DivEngine::getEffectiveSampleRate(int rate) { return (48828*MIN(128,(rate*128/48828)))/128; case DIV_SYSTEM_X1_010: return (31250*MIN(255,(rate*16/31250)))/16; // TODO: support variable clock case + case DIV_SYSTEM_ES5506: + return (31250*MIN(131071,(rate*2048/31250)))/2048; // TODO: support variable clock, channel limit case default: break; } @@ -1104,6 +1140,7 @@ void DivEngine::previewSample(int sample, int note) { if (sample<0 || sample>=(int)song.sample.size()) { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1119,6 +1156,7 @@ void DivEngine::previewSample(int sample, int note) { sPreview.pos=0; sPreview.sample=sample; sPreview.wave=-1; + sPreview.dir=false; BUSY_END; } @@ -1126,6 +1164,7 @@ void DivEngine::stopSamplePreview() { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -1134,6 +1173,7 @@ void DivEngine::previewWave(int wave, int note) { if (wave<0 || wave>=(int)song.wave.size()) { sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1149,6 +1189,7 @@ void DivEngine::previewWave(int wave, int note) { sPreview.pos=0; sPreview.sample=-1; sPreview.wave=wave; + sPreview.dir=false; BUSY_END; } @@ -1156,6 +1197,7 @@ void DivEngine::stopWavePreview() { BUSY_BEGIN; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -1571,7 +1613,7 @@ int DivEngine::addSampleFromFile(const char* path) { sample->rate=33144; sample->centerRate=33144; - sample->depth=1; + sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM; sample->init(len*8); if (fread(sample->dataDPCM,1,len,f)==0) { @@ -1620,9 +1662,9 @@ int DivEngine::addSampleFromFile(const char* path) { int index=0; if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { - sample->depth=8; + sample->depth=DIV_SAMPLE_DEPTH_8BIT; } else { - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } sample->init(si.frames); for (int i=0; icenterRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); - if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD) + if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { sample->loopStart=inst.loops[0].start; + sample->loopEnd=inst.loops[0].end; + sample->loopMode=DivSampleLoopMode(int(inst.loops[0].mode-SF_LOOP_NONE)); if(inst.loops[0].end < (unsigned int)sampleCount) sampleCount=inst.loops[0].end; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 6bcaa38c9..18c9459b5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -234,10 +234,12 @@ class DivEngine { int sample; int wave; unsigned int pos; + bool dir; SamplePreview(): sample(-1), wave(-1), - pos(0) {} + pos(0), + dir(false) {} } sPreview; short vibTable[64]; @@ -723,6 +725,8 @@ class DivEngine { size_t dpcmMemLen; unsigned char* x1_010Mem; size_t x1_010MemLen; + signed short* es5506Mem; + size_t es5506MemLen; DivEngine(): output(NULL), @@ -805,7 +809,9 @@ class DivEngine { dpcmMem(NULL), dpcmMemLen(0), x1_010Mem(NULL), - x1_010MemLen(0) { + x1_010MemLen(0), + es5506Mem(NULL), + es5506MemLen(0) { memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool)); memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool)); memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int)); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 183ff81a1..0b11b5522 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -772,17 +772,17 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { sample->rate=ymuSampleRate*400; } if (ds.version>0x15) { - sample->depth=reader.readC(); - if (sample->depth!=8 && sample->depth!=16) { + sample->depth=DivSampleDepth(reader.readC()); + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { logW("%d: sample depth is wrong! (%d)",i,sample->depth); - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } } else { if (ds.version>0x05) { - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } else { // it appears samples were stored as ADPCM back then - sample->depth=6; + sample->depth=DIV_SAMPLE_DEPTH_ADPCM_B; } } if (length>0) { @@ -811,7 +811,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (k>=sample->samples) { break; } - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { float next=(float)(data[(unsigned int)j]-0x80)*mult; sample->data8[k++]=fmin(fmax(next,-128),127); } else { @@ -1414,6 +1414,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { sample->name=reader.readString(); sample->samples=reader.readI(); + sample->loopEnd=sample->samples; sample->rate=reader.readI(); if (ds.version<58) { vol=reader.readS(); @@ -1421,7 +1422,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readI(); } - sample->depth=reader.readC(); + sample->depth=DivSampleDepth(reader.readC()); // reserved reader.readC(); @@ -1435,6 +1436,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version>=19) { sample->loopStart=reader.readI(); + if (sample->loopStart<0) { + sample->loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; + sample->loopStart=0; + } else { + sample->loopMode=DIV_SAMPLE_LOOPMODE_FOWARD; + } } else { reader.readI(); } @@ -1452,9 +1459,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } // render data - if (sample->depth!=8 && sample->depth!=16) { + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { logW("%d: sample depth is wrong! (%d)",i,sample->depth); - sample->depth=16; + sample->depth=DIV_SAMPLE_DEPTH_16BIT; } sample->samples=(double)sample->samples/samplePitches[pitch]; sample->init(sample->samples); @@ -1465,7 +1472,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (k>=sample->samples) { break; } - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { float next=(float)(data[(unsigned int)j]-0x80)*mult; sample->data8[k++]=fmin(fmax(next,-128),127); } else { @@ -1645,7 +1652,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { logD("reading samples... (%d)",insCount); for (int i=0; idepth=8; + sample->depth=DIV_SAMPLE_DEPTH_8BIT; sample->name=reader.readString(22); logD("%d: %s",i+1,sample->name); int slen=((unsigned short)reader.readS_BE())*2; @@ -1667,6 +1674,12 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { if (loopLen>=2) { if (loopEndloopStart=loopStart; + if (sample->loopStart<0) { + sample->loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; + sample->loopStart=0; + } else { + sample->loopMode=DIV_SAMPLE_LOOPMODE_FOWARD; + } } sample->init(slen); ds.sample.push_back(sample); @@ -2303,10 +2316,10 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(sample->samples); w->writeI(sample->rate); w->writeI(0); // reserved (for now) - w->writeC(sample->depth); + w->writeC((unsigned char)(sample->depth)); w->writeC(0); w->writeS(sample->centerRate); - w->writeI(sample->loopStart); + w->writeI((sample->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?-1:sample->loopStart); w->write(sample->getCurBuf(),sample->getCurBufLen()); } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index b5ed40890..cfd338c13 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -384,8 +384,12 @@ void DivInstrument::putInsData(SafeWriter* w) { // sample map w->writeC(amiga.useNoteMap); if (amiga.useNoteMap) { - w->write(amiga.noteFreq,120*sizeof(unsigned int)); - w->write(amiga.noteMap,120*sizeof(short)); + for (int i=0; i<120; i++) { + w->writeI(amiga.noteMap[i].freq); + } + for (int i=0; i<120; i++) { + w->writeS(amiga.noteMap[i].ind); + } } // N163 @@ -862,8 +866,12 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { if (version>=67) { amiga.useNoteMap=reader.readC(); if (amiga.useNoteMap) { - reader.read(amiga.noteFreq,120*sizeof(unsigned int)); - reader.read(amiga.noteMap,120*sizeof(short)); + for (int i=0; i<120; i++) { + amiga.noteMap[i].freq=reader.readI(); + } + for (int i=0; i<120; i++) { + amiga.noteMap[i].ind=reader.readS(); + } } } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index d9e943866..ee832e7f3 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -54,6 +54,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_VERA=24, DIV_INS_X1_010=25, DIV_INS_VRC6_SAW=26, + DIV_INS_ES5506=27, DIV_INS_MAX, }; @@ -291,21 +292,26 @@ struct DivInstrumentC64 { }; struct DivInstrumentAmiga { + struct NoteMap { + int freq; + short ind; + + NoteMap(): + freq(0), + ind(-1) {} + }; + short initSample; bool useNoteMap; bool useWave; unsigned char waveLen; - int noteFreq[120]; - short noteMap[120]; + NoteMap noteMap[120]; DivInstrumentAmiga(): initSample(0), useNoteMap(false), useWave(false), - waveLen(31) { - memset(noteMap,-1,120*sizeof(short)); - memset(noteFreq,0,120*sizeof(int)); - } + waveLen(31) {} }; struct DivInstrumentN163 { @@ -332,6 +338,43 @@ struct DivInstrumentFDS { } }; +struct DivInstrumentES5506 { + struct Filter { + enum FilterMode: unsigned char { // filter mode for pole 4,3 + FILTER_MODE_HPK2_HPK2, + FILTER_MODE_HPK2_LPK1, + FILTER_MODE_LPK2_LPK2, + FILTER_MODE_LPK2_LPK1, + }; + FilterMode mode; + unsigned short k1, k2; + Filter(): + mode(FILTER_MODE_LPK2_LPK1), + k1(0xffff), + k2(0xffff) {} + }; + struct Envelope { + unsigned short ecount; + signed char lVRamp, rVRamp; + signed char k1Ramp, k2Ramp; + bool k1Slow, k2Slow; + Envelope(): + ecount(0), + lVRamp(0), + rVRamp(0), + k1Ramp(0), + k2Ramp(0), + k1Slow(false), + k2Slow(false) {} + }; + signed int lVol, rVol; + Filter filter; + Envelope envelope; + DivInstrumentES5506(): + lVol(0xffff), + rVol(0xffff) {} +}; + enum DivWaveSynthEffects { DIV_WS_NONE=0, // one waveform effects @@ -387,6 +430,7 @@ struct DivInstrument { DivInstrumentAmiga amiga; DivInstrumentN163 n163; DivInstrumentFDS fds; + DivInstrumentES5506 es5506; DivInstrumentWaveSynth ws; /** diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index b8419d197..678f9afad 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -109,8 +109,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le DivSample* s=parent->getSample(chan[i].sample); if (s->samples>0) { writeAudDat(s->data8[chan[i].audPos++]); - if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].audPos>=s->loopEnd) || (chan[i].audPos>=s->samples) || (chan[i].audPos>=131071)) { + if (s->isLoopable()) { chan[i].audPos=s->loopStart; } else { chan[i].sample=-1; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp new file mode 100644 index 000000000..dfc435c62 --- /dev/null +++ b/src/engine/platform/es5506.cpp @@ -0,0 +1,638 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 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 "es5506.h" +#include "../engine.h" +#include "../../ta-log.h" +#include +#include + +#define CHIP_FREQBASE (16*2048) +#define NOTE_ES5506(c,note) (chan[c].pcm.freqOffs*NOTE_FREQUENCY(note)) + +#define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }} +#define rRead(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} +#define immWrite(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} +#define pageWrite(p,a,...) \ + if (!skipRegisterWrites) { \ + if (curPage!=(p)) { \ + curPage=(p); \ + rWrite(0xf,curPage); \ + } \ + rWrite((a),__VA_ARGS__); \ + } + +#define pageWriteMask(p,pm,a,...) \ + if (!skipRegisterWrites) { \ + if ((curPage&(pm))!=((p)&(pm))) { \ + curPage=(curPage&~(pm))|((p)&(pm)); \ + rWrite(0xf,curPage,(pm)); \ + } \ + rWrite((a),__VA_ARGS__); \ + } + + +const char* regCheatSheetES5506[]={ + "CR", "00|00", + "FC", "00|01", + "LVOL", "00|02", + "LVRAMP", "00|03", + "RVOL", "00|04", + "RVRAMP", "00|05", + "ECOUNT", "00|06", + "K2", "00|07", + "K2RAMP", "00|08", + "K1", "00|09", + "K1RAMP", "00|0A", + "ACTV", "00|0B", + "MODE", "00|0C", + "POT", "00|0D", + "IRQV", "00|0E", + "PAGE", "00|0F", + "CR", "20|00", + "START", "20|01", + "END", "20|02", + "ACCUM", "20|03", + "O4(n-1)", "20|04", + "O3(n-2)", "20|05", + "O3(n-1)", "20|06", + "O2(n-2)", "20|07", + "O2(n-1)", "20|08", + "O1(n-1)", "20|09", + "W_ST", "20|0A", + "W_END", "20|0B", + "LR_END", "20|0C", + "POT", "20|0D", + "IRQV", "20|0E", + "PAGE", "20|0F", + "CH0L", "40|00", + "CH0R", "40|01", + "CH1L", "40|02", + "CH1R", "40|03", + "CH2L", "40|04", + "CH2R", "40|05", + "CH3L", "40|06", + "CH3R", "40|07", + "CH4L", "40|08", + "CH4R", "40|09", + "CH5L", "40|0A", + "CH5R", "40|0B", + "POT", "40|0D", + "IRQV", "40|0E", + "PAGE", "40|0F", + NULL +}; + +const char** DivPlatformES5506::getRegisterSheet() { + return regCheatSheetES5506; +} + +const char* DivPlatformES5506::getEffectName(unsigned char effect) { + switch (effect) { + case 0x10: + return "10xx: Set echo feedback level (00 to FF)"; + break; + case 0x11: + return "11xx: Set channel echo level (00 to FF)"; + break; + default: + if ((effect & 0xf0) == 0x30) { + return "3xxx: Set echo delay buffer length (000 to AA5)"; + } + } + return NULL; +} +void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t len) { + for (size_t h=start; h0) { + cycle+=w.delay; + } + isReaded=true; + } else { + isReaded=false; + } + hostIntf8.pop(); + } else { + isReaded=false; + unsigned int mask=(w.mask>>shift)&0xff; + if ((mask==0xff) || isMasked) { + if (mask==0xff) { + maskedVal=(w.val>>shift)&0xff; + } + es5506.host_w((w.addr<<2)+w.step,maskedVal); + if(dumpWrites) { + addWrite((w.addr<<2)+w.step,maskedVal); + } + isMasked=false; + if ((w.step==3) && (w.delay>0)) { + cycle+=w.delay; + } + hostIntf8.pop(); + } else if (!isMasked) { + maskedVal=((w.val>>shift)&mask)|(es5506.host_r((w.addr<<2)+w.step)&~mask); + isMasked=true; + } + } + } + } + if (isReaded) { + isReaded=false; + if (irqTrigger) { + irqTrigger=false; + if ((irqv&0x80)==0) { + unsigned char ch=irqv&0x1f; + if (chan[ch].isReversed) { // Reversed loop + pageWriteMask(0x00|ch,0x5f,0x00,0x48,0x78); + chan[ch].isReversed=false; + } + } + } + } +} + +void DivPlatformES5506::irqb(bool state) { + rRead(0x0e,&irqv,0x9f); + irqTrigger=true; +} + +void DivPlatformES5506::tick() { + for (int i=0; i<=chanMax; i++) { + chan[i].std.next(); + DivInstrument* ins=parent->getIns(chan[i].ins); + // volume/panning macros + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; + if (!isMuted[i]) { + chan[i].volChanged=true; + } + } + if (chan[i].std.panL.had) { + chan[i].outLVol=(((ins->es5506.lVol*(chan[i].lVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panL.val))/0xffff; + if (!isMuted[i]) { + chan[i].volChanged=true; + } + } + if (chan[i].std.panR.had) { + chan[i].outRVol=(((ins->es5506.rVol*(chan[i].rVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panR.val))/0xffff; + if (!isMuted[i]) { + chan[i].volChanged=true; + } + } + // arpeggio/pitch macros, frequency related + if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_ES5506(i,chan[i].std.arp.val); + } else { + chan[i].baseFreq=NOTE_ES5506(i,chan[i].note+chan[i].std.arp.val); + } + } + chan[i].freqChanged=true; + } else { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { + chan[i].baseFreq=NOTE_ES5506(i,chan[i].note); + chan[i].freqChanged=true; + } + } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + // phase reset macro + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1) { + chan[i].keyOn=true; + } + } + // update registers + if (chan[i].volChanged) { + if (!isMuted[i]) { // calculate volume (16 bit) + chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; + chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x02,chan[i].resLVol); + pageWrite(0x00|i,0x04,chan[i].resRVol); + } + } else { // mute + pageWrite(0x00|i,0x02,0); + pageWrite(0x00|i,0x04,0); + } + chan[i].volChanged=false; + } + if (chan[i].filterChanged) { + pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300); + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x07,chan[i].filter.k2); + pageWrite(0x00|i,0x09,chan[i].filter.k1); + } + chan[i].filterChanged=false; + } + if (chan[i].envChanged) { + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x06,chan[i].envelope.ecount); + } + chan[i].envChanged=false; + } + if (chan[i].rampChanged) { + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8); + pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8); + pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0)); + pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); + } + chan[i].rampChanged=false; + } + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq*(chanMax+1),chan[i].pitch,false)+chan[i].std.pitch.val; + if (chan[i].freq<0) chan[i].freq=0; + if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff; + if (chan[i].keyOn) { + if (chan[i].pcm.index>=0) { + pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR + pageWrite(0x00|i,0x06,0); // Clear ECOUNT + pageWrite(0x20|i,0x03,chan[i].pcm.base); // Set ACCUM to start address + pageWrite(0x00|i,0x09,0xffff); // Set K1 and K2 to 0xffff + pageWrite(0x00|i,0x07,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay + pageWrite(0x00|i,0x01,chan[i].freq); + if (chan[i].pcm.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + pageWrite(0x20|i,0x01,chan[i].pcm.loopStart); + } + pageWrite(0x20|i,0x02,chan[i].pcm.loopEnd); + // initialize envelope + pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8); + pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8); + pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0)); + pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); + // initialize filter + pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300); + pageWrite(0x00|i,0x09,chan[i].filter.k1); + pageWrite(0x00|i,0x07,chan[i].filter.k2); + pageWrite(0x00|i,0x02,chan[i].resLVol); + pageWrite(0x00|i,0x04,chan[i].resRVol); + unsigned int loopFlag=0x0000; + chan[i].isReversed=false; + switch (chan[i].pcm.loopMode) { + case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) + default: + loopFlag=0x0000; + break; + case DIV_SAMPLE_LOOPMODE_FOWARD: // Foward loop + loopFlag=0x0008; + break; + case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable + loopFlag=0x0038; + chan[i].isReversed=true; + break; + case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support + loopFlag=0x0018; + break; + } + // Run sample + pageWrite(0x00|i,0x06,chan[i].envelope.ecount); // Clear ECOUNT + pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0x3cff); + } + } + if (chan[i].keyOff) { + pageWriteMask(0x00|i,0x5f,0x00,0x0003); // Wipeout CR + } else if (chan[i].active) { + pageWrite(0x00|i,0x01,chan[i].freq); + } + if (chan[i].keyOn) chan[i].keyOn=false; + if (chan[i].keyOff) chan[i].keyOff=false; + chan[i].freqChanged=false; + } + } +} + +int DivPlatformES5506::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins); + chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample; + double off=1.0; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + chan[c.chan].pcm.index=chan[c.chan].sample; + DivSample* s=parent->getSample(chan[c.chan].sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0); + } + unsigned int base=s->offES5506<<10; + chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + chan[c.chan].pcm.freqOffs=off; + chan[c.chan].pcm.bank=(s->offES5506>>22)&3; + chan[c.chan].pcm.base=base; + chan[c.chan].pcm.loopStart=(base+(s->loopStart<<11))&0xfffff800; + chan[c.chan].pcm.loopEnd=((base+(s->loopEnd<<11))-0x800)&0xffffff80; + chan[c.chan].filter=ins->es5506.filter; + chan[c.chan].envelope=ins->es5506.envelope; + } else { + chan[c.chan].sample=-1; + chan[c.chan].pcm.index=-1; + chan[c.chan].filter=DivInstrumentES5506::Filter(); + chan[c.chan].envelope=DivInstrumentES5506::Envelope(); + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].volChanged=true; + chan[c.chan].note=c.value; + } + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=(0xffff*chan[c.chan].vol)/0xff; + } + if (!chan[c.chan].std.panL.will) { + chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xf; + } + if (!chan[c.chan].std.panR.will) { + chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xf; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + chan[c.chan].std.init(ins); + break; + } + case DIV_CMD_NOTE_OFF: + chan[c.chan].filter=DivInstrumentES5506::Filter(); + chan[c.chan].envelope=DivInstrumentES5506::Envelope(); + chan[c.chan].sample=-1; + chan[c.chan].active=false; + chan[c.chan].keyOff=true; + chan[c.chan].std.init(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; + } + break; + case DIV_CMD_VOLUME: + if (chan[c.chan].vol!=c.value) { + chan[c.chan].vol=c.value; + if (!chan[c.chan].std.vol.has) { + chan[c.chan].outVol=(0xffff*c.value)/0xff; + if (!isMuted[c.chan]) { + chan[c.chan].volChanged=true; + } + } + } + break; + case DIV_CMD_GET_VOLUME: + if (chan[c.chan].std.vol.has) { + return chan[c.chan].vol; + } + return chan[c.chan].outVol; + break; + case DIV_CMD_PANNING: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins); + // 08LR, each nibble means volume multipler for each channels + // Left volume + unsigned char lVol=(c.value>>4)&0xf; + if (chan[c.chan].lVol!=lVol) { + chan[c.chan].lVol=lVol; + if (!chan[c.chan].std.panL.has) { + chan[c.chan].outLVol=(ins->es5506.lVol*lVol)/0xf; + if (!isMuted[c.chan]) { + chan[c.chan].volChanged=true; + } + } + } + // Right volume + unsigned char rVol=(c.value>>0)&0xf; + if (chan[c.chan].rVol!=rVol) { + chan[c.chan].rVol=rVol; + if (!chan[c.chan].std.panR.has) { + chan[c.chan].outRVol=(ins->es5506.rVol*rVol)/0xf; + if (!isMuted[c.chan]) { + chan[c.chan].volChanged=true; + } + } + } + break; + } + case DIV_CMD_PITCH: + chan[c.chan].pitch=c.value; + chan[c.chan].freqChanged=true; + break; + case DIV_CMD_NOTE_PORTA: { + int destFreq=NOTE_ES5506(c.chan,c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } + case DIV_CMD_LEGATO: { + chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(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].std.init(parent->getIns(chan[c.chan].ins)); + } + chan[c.chan].inPorta=c.value; + break; + case DIV_CMD_GET_VOLMAX: + return 255; + break; + case DIV_ALWAYS_SET_VOLUME: + return 1; + break; + default: + break; + } + return 1; +} + +void DivPlatformES5506::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + es5506.set_mute(ch,mute); +} + +void DivPlatformES5506::forceIns() { + for (int i=0; i<=chanMax; i++) { + chan[i].insChanged=true; + chan[i].freqChanged=true; + chan[i].volChanged=true; + chan[i].sample=-1; + } +} + +void* DivPlatformES5506::getChanState(int ch) { + return &chan[ch]; +} + +void DivPlatformES5506::reset() { + while (!hostIntf32.empty()) hostIntf32.pop(); + while (!hostIntf8.empty()) hostIntf8.pop(); + for (int i=0; i<32; i++) { + chan[i]=DivPlatformES5506::Channel(); + chan[i].std.setEngine(parent); + } + es5506.reset(); + for (int i=0; i<32; i++) { + es5506.set_mute(i,isMuted[i]); + } + + cycle=0; + curPage=0; + maskedVal=0; + irqv=0x80; + isMasked=false; + isReaded=false; + irqTrigger=false; + chanMax=initChanMax; + + pageWriteMask(0x00,0x60,0x0b,chanMax); + pageWriteMask(0x00,0x60,0x0b,0x1f); + pageWriteMask(0x20,0x60,0x0a,0x01); + pageWriteMask(0x20,0x60,0x0b,0x11); + pageWriteMask(0x20,0x60,0x0c,0x20); + pageWriteMask(0x00,0x60,0x0c,0x08); // Reset serial output +} + +bool DivPlatformES5506::isStereo() { + return true; +} + +bool DivPlatformES5506::keyOffAffectsArp(int ch) { + return true; +} + +void DivPlatformES5506::notifyInsChange(int ins) { + for (int i=0; i<32; i++) { + if (chan[i].ins==ins) { + chan[i].insChanged=true; + } + } +} + +void DivPlatformES5506::notifyWaveChange(int wave) { + // TODO when wavetables are added + // TODO they probably won't be added unless the samples reside in RAM +} + +void DivPlatformES5506::notifyInsDeletion(void* ins) { + for (int i=0; i<32; i++) { + chan[i].std.notifyInsDeletion((DivInstrument*)ins); + } +} + +void DivPlatformES5506::setFlags(unsigned int flags) { + initChanMax=MAX(4,flags&0x1f); + chanMax=initChanMax; + pageWriteMask(0x00,0x60,0x0b,chanMax); +} + +void DivPlatformES5506::poke(unsigned int addr, unsigned short val) { + immWrite(addr, val); +} + +void DivPlatformES5506::poke(std::vector& wlist) { + for (DivRegWrite& i: wlist) immWrite(i.addr,i.val); +} + +unsigned char* DivPlatformES5506::getRegisterPool() { + unsigned char* regPoolPtr = regPool; + for (unsigned char p=0; p<128; p++) { + for (unsigned char r=0; r<16; r++) { + unsigned int reg=es5506.regs_r(p,r,false); + for (int b=0; b<4; b++) { + *regPoolPtr++ = reg>>(24-(b<<3)); + } + } + } + return regPool; +} + +int DivPlatformES5506::getRegisterPoolSize() { + return 4*16*128; // 7 bit page x 16 registers per page x 32 bit per registers +} + +int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + + for (int i=0; i<32; i++) { + isMuted[i]=false; + } + setFlags(flags); + + chipClock=16000000; + rate=chipClock/16; + reset(); + return 32; +} + +void DivPlatformES5506::quit() { +} diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h new file mode 100644 index 000000000..8f9bf185d --- /dev/null +++ b/src/engine/platform/es5506.h @@ -0,0 +1,173 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 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 _ES5506_H +#define _ES5506_H + +#pragma once + +#include "../dispatch.h" +#include "../engine.h" +#include +#include "../macroInt.h" +#include "../sample.h" +#include "sound/es550x/es5506.hpp" + +class DivPlatformES5506: public DivDispatch, public es550x_intf { + struct Channel { + struct PCM { + double freqOffs; + int index; + unsigned int bank; + unsigned int base; + unsigned int loopStart; + unsigned int loopEnd; + DivSampleLoopMode loopMode; + PCM(): + freqOffs(1.0), + index(-1), + bank(0), + base(0), + loopStart(0), + loopEnd(0), + loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} + } pcm; + int freq, baseFreq, pitch; + unsigned short audLen; + unsigned int audPos; + int sample, wave; + unsigned char ins; + int note; + int panning; + bool active, insChanged, freqChanged, volChanged, filterChanged, envChanged, rampChanged, keyOn, keyOff, inPorta, useWave, isReversed; + int vol, outVol; + int lVol, outLVol; + int rVol, outRVol; + int resLVol, resRVol; + DivInstrumentES5506::Filter filter; + DivInstrumentES5506::Envelope envelope; + DivMacroInt std; + Channel(): + freq(0), + baseFreq(0), + pitch(0), + audLen(0), + audPos(0), + sample(-1), + ins(-1), + note(0), + panning(0x10), + active(false), + insChanged(true), + freqChanged(false), + volChanged(false), + filterChanged(false), + envChanged(false), + rampChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + vol(0xffff), + outVol(0xffff), + lVol(0xffff), + outLVol(0xffff), + rVol(0xffff), + outRVol(0xffff), + resLVol(0xffff), + resRVol(0xffff) {} + }; + Channel chan[32]; + bool isMuted[32]; + struct QueuedHostIntf { + unsigned char step; + unsigned char addr; + unsigned int val; + unsigned int mask; + unsigned int* read; + unsigned short delay; + bool isRead; + QueuedHostIntf(unsigned char s, unsigned char a, unsigned int v, unsigned int m=(unsigned int)(~0), unsigned short d=0): + step(s), + addr(a), + val(v), + mask(m), + read(NULL), + delay(0), + isRead(false) {} + QueuedHostIntf(unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0): + step(s), + addr(a), + val(0), + mask(m), + read(r), + delay(d), + isRead(true) {} + }; + std::queue hostIntf32; + std::queue hostIntf8; + int cycle, curPage; + unsigned char maskedVal; + unsigned int irqv; + bool isMasked, isReaded; + bool irqTrigger; + + unsigned char initChanMax, chanMax; + + es5506_core es5506; + unsigned char regPool[4*16*128]; // 7 bit page x 16 registers per page x 32 bit per registers + + friend void putDispatchChan(void*,int,int); + + public: + virtual void e(bool state) override; // E output + + virtual void irqb(bool state) override; // IRQB output + virtual s16 read_sample(u8 voice, u8 bank, u32 address) override { + if (parent->es5506Mem==NULL) return 0; + return parent->es5506Mem[((bank&3)<<21)|(address&0x1fffff)]; + } + + virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override; + virtual int dispatch(DivCommand c) override; + virtual void* getChanState(int chan) override; + virtual unsigned char* getRegisterPool() override; + virtual int getRegisterPoolSize() override; + virtual void reset() override; + virtual void forceIns() override; + virtual void tick() override; + virtual void muteChannel(int ch, bool mute) override; + virtual bool isStereo() override; + virtual bool keyOffAffectsArp(int ch) override; + virtual void setFlags(unsigned int flags) override; + virtual void notifyInsChange(int ins) override; + virtual void notifyWaveChange(int wave) override; + virtual void notifyInsDeletion(void* ins) override; + virtual void poke(unsigned int addr, unsigned short val) override; + virtual void poke(std::vector& wlist) override; + virtual const char** getRegisterSheet() override; + virtual const char* getEffectName(unsigned char effect) override; + virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override; + virtual void quit() override; + DivPlatformES5506(): + DivDispatch(), + es550x_intf(), + es5506(*this) {} +}; + +#endif diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 7a9a1d51a..97a6384d2 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -96,8 +96,9 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80); } } - if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + dacPos++; + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) { + if (s->isLoopable()) { dacPos=s->loopStart; } else { dacSample=-1; @@ -165,8 +166,9 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80); } } - if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + dacPos++; + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) { + if (s->isLoopable()) { dacPos=s->loopStart; } else { dacSample=-1; diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index a9f9bb796..31f1e2545 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -62,8 +62,9 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (!isMuted[4]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } - if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + dacPos++; + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) { + if (s->isLoopable()) { dacPos=s->loopStart; } else { dacSample=-1; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 4c65ce4f2..3208df611 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -89,8 +89,9 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) rWrite(0x4011,next); } } - if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + dacPos++; + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) { + if (s->isLoopable()) { dacPos=s->loopStart; } else { dacSample=-1; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 2c61a5fa1..3acdd4958 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -90,8 +90,8 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x04,0xdf); chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); chan[i].dacPos++; - if (chan[i].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].dacPos>=s->loopEnd) || (chan[i].dacPos>=s->samples)) { + if (s->isLoopable()) { chan[i].dacPos=s->loopStart; } else { chan[i].dacSample=-1; diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 2a1460d15..bfdaad3eb 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -299,11 +299,11 @@ void DivPlatformQSound::tick() { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int length = s->samples; + int length = s->isLoopable()?s->loopEnd:s->samples; if (length > 65536 - 16) { length = 65536 - 16; } - if (s->loopStart == -1 || s->loopStart >= length) { + if ((!s->isLoopable()) || s->loopStart>=length) { qsound_end = s->offQSound + length + 15; qsound_loop = 15; } else { diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index b2a8b3db8..d5bb86da2 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -53,8 +53,8 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (chan[i].pcm.pos>=(s->samples<<8)) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].pcm.pos>=(s->loopEnd<<8)) || (chan[i].pcm.pos>=(s->samples<<8))) { + if (s->isLoopable()) { chan[i].pcm.pos=s->loopStart<<8; } else { chan[i].pcm.sample=-1; @@ -153,7 +153,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+s->length8-1)>>8)); - if (s->loopStart<0 || s->loopStart>=(int)s->length8) { + if (!s->isLoopable()) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; @@ -183,7 +183,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+s->length8-1)>>8)); - if (s->loopStart<0 || s->loopStart>=(int)s->length8) { + if (!s->isLoopable()) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp new file mode 100644 index 000000000..d9750b7f1 --- /dev/null +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -0,0 +1,444 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core + + see es550x.cpp for more info +*/ + +#include "es5504.hpp" + +// Internal functions +void es5504_core::tick() +{ + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // /CAS high, E low: get sample address + if (m_cas.falling_edge()) + { + // /CAS low, E low: fetch sample + if (!m_e.current_edge()) + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + // E + if (m_clkin.falling_edge()) // falling edge triggers E clock + { + if (m_e.tick()) + { + m_intf.e(m_e.current_edge()); + if (m_e.rising_edge()) // Host access + { + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + voice_tick(); + } + if (m_e.falling_edge()) // Voice memory + { + m_host_intf.m_host_access = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.m_host_access) + { + if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read + { + m_hd = read(m_ha); + m_host_intf.m_host_access = false; + } + else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write + write(m_ha, m_hd); + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.m_host_access_strobe = false; + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5504_core::tick_perf() +{ + // update + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; +} + +void es5504_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) + if (bitfield(m_voice_fetch++, 0)) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output (Multiplexed analog output) + m_ch[m_voice[m_voice_cycle].m_cr.ca] = m_voice[m_voice_cycle].m_ch; + + if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices + m_voice_cycle = 0; + + m_voice_fetch = 0; + } +} + +void es5504_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.ca, 0, 3), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); +} + +void es5504_core::voice_t::tick(u8 voice) +{ + m_ch = 0; + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + // Send to output + m_ch = ((sign_ext(m_filter.m_o4_1, 16) >> 3) * m_volume) >> 12; // Analog multiplied in real chip, 13/12 bit ladder DAC + + // ALU execute + if (m_alu.tick()) + { + m_alu.loop_exec(); + } + + // ADC check + adc_exec(); + } + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// ADC; Correct? +void es5504_core::voice_t::adc_exec() +{ + if (m_cr.adc) + m_host.m_adc = m_host.m_intf.adc_r() & ~0x7; +} + +void es5504_core::reset() +{ + es550x_shared_core::reset(); + for (auto & elem : m_voice) + elem.reset(); + + m_adc = 0; + std::fill(std::begin(m_ch), std::end(m_ch), 0); +} + +void es5504_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_volume = 0; + m_ch = 0; +} + +// Accessors +u16 es5504_core::host_r(u8 address) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + if (m_e.rising_edge()) // update directly + m_hd = read(m_ha, true); + else + { + m_host_intf.m_rw_strobe = true; + m_host_intf.m_host_access_strobe = true; + } + } + return m_hd; +} + +void es5504_core::host_w(u8 address, u16 data) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) // update directly + write(m_ha, m_hd, true); + else + { + m_host_intf.m_rw_strobe = false; + m_host_intf.m_host_access_strobe = true; + } + } +} + +u16 es5504_core::read(u8 address, bool cpu_access) +{ + return regs_r(m_page, address, cpu_access); +} + +void es5504_core::write(u8 address, u16 data, bool cpu_access) +{ + regs_w(m_page, address, data, cpu_access); +} + +u16 es5504_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u16 ret = 0xffff; + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 12: // A/D (A to D Convert/Test) + ret = (ret & ~0xfffb) | (m_adc & 0xfffb); + break; + case 13: // ACT (Number of voices) + ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 14: // IRQV (Interrupting voice vector) + ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); + if (cpu_access) + { + m_irqv.clear(); + if (bitfield(ret, 7) != m_irqv.irqb) + m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); + } + break; + case 15: // PAGE (Page select register) + ret = (ret & ~0x3f) | bitfield(m_page, 0, 6); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + if (voice < 25) + { + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + ret = v.m_filter.m_o4_1; + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + ret = v.m_filter.m_o3_2; + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + ret = v.m_filter.m_o3_1; + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + ret = v.m_filter.m_o2_2; + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + ret = v.m_filter.m_o2_1; + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + ret = v.m_filter.m_o1_1; + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + ret = (ret & ~0xff) | + (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) + | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) + | (v.m_cr.adc ? 0x04 : 0x00) + | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) + | (v.m_alu.m_cr.ble ? 0x10 : 0x00) + | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) + | (v.m_alu.m_cr.dir ? 0x40 : 0x00) + | (v.m_alu.m_cr.irq ? 0x80 : 0x00); + break; + case 1: // FC (Frequency Control) + ret = (ret & ~0xfffe) | (v.m_alu.m_fc << 1); + break; + case 2: // STRT-H (Loop Start Register High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); + break; + case 3: // STRT-L (Loop Start Register Low) + ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); + break; + case 5: // END-L (Loop End Register Low) + ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); + break; + case 8: // Volume + ret = (ret & ~0xfff0) | ((v.m_volume << 4) & 0xfff0); + break; + case 9: // CA (Filter Config, Channel Assign) + ret = (ret & ~0x3f) | + bitfield(v.m_cr.ca, 0, 4) + | (bitfield(v.m_filter.m_lp, 0, 2) << 4); + break; + case 10: // ACCH (Accumulator High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); + break; + case 11: // ACCL (Accumulator Low) + ret = bitfield(v.m_alu.m_accum, 0, 16); + break; + } + } + } + } + + return ret; +} + +void es5504_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) +{ + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 12: // A/D (A to D Convert/Test) + if (bitfield(m_adc, 0)) // Writable ADC + { + m_adc = (m_adc & 7) | (data & ~7); + m_intf.adc_w(m_adc & ~7); + } + m_adc = (m_adc & ~3) | (data & 3); + break; + case 13: // ACT (Number of voices) + m_active = std::min(24, bitfield(data, 0, 5)); + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 6); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + if (voice < 25) + { + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + v.m_filter.m_o4_1 = sign_ext(data, 16); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + v.m_filter.m_o3_2 = sign_ext(data, 16); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + v.m_filter.m_o3_1 = sign_ext(data, 16); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + v.m_filter.m_o2_2 = sign_ext(data, 16); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + v.m_filter.m_o2_1 = sign_ext(data, 16); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + v.m_filter.m_o1_1 = sign_ext(data, 16); + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + v.m_alu.m_cr.stop0 = bitfield(data, 0); + v.m_alu.m_cr.stop1 = bitfield(data, 1); + v.m_cr.adc = bitfield(data, 2); + v.m_alu.m_cr.lpe = bitfield(data, 3); + v.m_alu.m_cr.ble = bitfield(data, 4); + v.m_alu.m_cr.irqe = bitfield(data, 5); + v.m_alu.m_cr.dir = bitfield(data, 6); + v.m_alu.m_cr.irq = bitfield(data, 7); + break; + case 1: // FC (Frequency Control) + v.m_alu.m_fc = bitfield(data, 1, 15); + break; + case 2: // STRT-H (Loop Start Register High) + v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 3: // STRT-L (Loop Start Register Low) + v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 5: // END-L (Loop End Register Low) + v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + v.m_filter.m_k2 = data & 0xfff0; + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + v.m_filter.m_k1 = data & 0xfff0; + break; + case 8: // Volume + v.m_volume = bitfield(data, 4, 12); + break; + case 9: // CA (Filter Config, Channel Assign) + v.m_cr.ca = bitfield(data, 0, 4); + v.m_filter.m_lp = bitfield(data, 4, 2); + break; + case 10: // ACCH (Accumulator High) + v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 11: // ACCL (Accumulator Low) + v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; + break; + } + } + } + } +} diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp new file mode 100644 index 000000000..f6743e18b --- /dev/null +++ b/src/engine/platform/sound/es550x/es5504.hpp @@ -0,0 +1,87 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core + + See es550x.cpp for more info +*/ + +#include "es550x.hpp" + +#ifndef _VGSOUND_EMU_ES5504_HPP +#define _VGSOUND_EMU_ES5504_HPP + +#pragma once + +// ES5504 specific +class es5504_core : public es550x_shared_core +{ +public: + // constructor + es5504_core(es550x_intf &intf) + : es550x_shared_core(intf) + , m_voice{*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this, + *this,*this,*this,*this,*this, + *this,*this,*this,*this,*this, + *this,*this,*this,*this,*this} + { + } + // host interface + u16 host_r(u8 address); + void host_w(u8 address, u16 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // 16 analog output channels + s32 out(u8 ch) { return m_ch[ch & 0xf]; } + + // bypass chips host interface for debug purpose only + u16 read(u8 address, bool cpu_access = false); + void write(u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + +protected: + virtual inline u8 max_voices() override { return 25; } + virtual void voice_tick() override; + +private: + // es5504 voice structs + struct voice_t : es550x_voice_t + { + // constructor + voice_t(es5504_core &host) + : es550x_voice_t(20, 9, false) + , m_host(host) + {} + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + void adc_exec(); + + // registers + es5504_core &m_host; + u16 m_volume = 0; // 12 bit Volume + s32 m_ch = 0; // channel outputs + }; + + voice_t m_voice[25]; // 25 voices + u16 m_adc = 0; // ADC register + s32 m_ch[16] = {0}; // 16 channel outputs +}; + +#endif diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp new file mode 100644 index 000000000..ca5fb8902 --- /dev/null +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -0,0 +1,599 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5505 emulation core + + see es550x.cpp for more info +*/ + +#include "es5505.hpp" + +// Internal functions +void es5505_core::tick() +{ + // CLKIN + if (m_clkin.tick()) + { + // SERBCLK + if (m_clkin.m_edge.m_changed) // BCLK is freely running clock + { + if (m_bclk.tick()) + { + m_intf.bclk(m_bclk.current_edge()); + // Serial output + if (m_bclk.falling_edge()) + { + // SERLRCLK + if (m_lrclk.tick()) + m_intf.lrclk(m_lrclk.current_edge()); + } + // SERWCLK + if (m_lrclk.m_edge.m_changed) + m_wclk = 0; + if (m_bclk.falling_edge()) + { + if (m_wclk == ((m_sermode.sony_bb) ? 1 : 0)) + { + if (m_lrclk.current_edge()) + { + for (int i = 0; i < 4; i++) + { + // copy output + m_output[i] = m_output_temp[i]; + m_output_latch[i] = m_ch[i]; + m_output_temp[i].reset(); + // clamp to 16 bit (upper 5 bits are overflow guard bits) + m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x8000, 0x7fff); + m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x8000, 0x7fff); + // set signed + if (m_output_latch[i].m_left < 0) + m_output_temp[i].m_left = -1; + if (m_output_latch[i].m_right < 0) + m_output_temp[i].m_right = -1; + } + } + m_wclk_lr = m_lrclk.current_edge(); + m_output_bit = 16; + } + s8 output_bit = --m_output_bit; + if (m_output_bit >= 0) + { + for (int i = 0; i < 4; i++) + { + if (m_wclk_lr) // Right output + m_output_temp[i].m_right = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_right, output_bit); + else // Left output + m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); + } + } + m_wclk++; + } + } + } + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // /CAS high, E low: get sample address + if (m_cas.falling_edge()) + { + // /CAS low, E low: fetch sample + if (!m_e.current_edge()) + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + // E + if (m_e.tick()) + { + m_intf.e(m_e.current_edge()); + if (m_e.rising_edge()) // Host access + { + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + voice_tick(); + } + else if (m_e.falling_edge()) // Voice memory + { + m_host_intf.m_host_access = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.m_host_access) + { + if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read + { + m_hd = read(m_ha); + m_host_intf.m_host_access = false; + } + else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write + write(m_ha, m_hd); + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.m_host_access_strobe = false; + } + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5505_core::tick_perf() +{ + // output + for (int c = 0; c < 4; c++) + { + m_output[c].m_left = clamp(m_ch[c].m_left, -0x8000, 0x7fff); + m_output[c].m_right = clamp(m_ch[c].m_right, -0x8000, 0x7fff); + } + + // update + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; +} + +void es5505_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) + if (bitfield(m_voice_fetch++, 0)) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output + if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices + { + m_voice_cycle = 0; + for (auto & elem : m_ch) + elem.reset(); + + for (auto & elem : m_voice) + { + m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_left += elem.m_ch.m_left; + m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_right += elem.m_ch.m_right; + elem.m_ch.reset(); + } + } + m_voice_fetch = 0; + } +} + +void es5505_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); +} + +void es5505_core::voice_t::tick(u8 voice) +{ + m_ch.reset(); + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + // Send to output + m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); + m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); + + // ALU execute + if (m_alu.tick()) + m_alu.loop_exec(); + } + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// volume calculation +s32 es5505_core::voice_t::volume_calc(u8 volume, s32 in) +{ + u8 exponent = bitfield(volume, 4, 4); + u8 mantissa = bitfield(volume, 0, 4); + return exponent ? (in * s32(0x10 | mantissa)) >> (20 - exponent) : 0; +} + +void es5505_core::reset() +{ + es550x_shared_core::reset(); + for (auto & elem : m_voice) + elem.reset(); + + m_sermode.reset(); + m_bclk.reset(); + m_lrclk.reset(); + m_wclk = 0; + m_wclk_lr = false; + m_output_bit = 0; + for (auto & elem : m_ch) + elem.reset(); + for (auto & elem : m_output) + elem.reset(); + for (auto & elem : m_output_temp) + elem.reset(); + for (auto & elem : m_output_latch) + elem.reset(); +} + +void es5505_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_lvol = 0; + m_rvol = 0; + m_ch.reset(); +} + +// Accessors +u16 es5505_core::host_r(u8 address) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + if (m_e.rising_edge()) // update directly + m_hd = read(m_ha, true); + else + { + m_host_intf.m_rw_strobe = true; + m_host_intf.m_host_access_strobe = true; + } + } + return m_hd; +} + +void es5505_core::host_w(u8 address, u16 data) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) // update directly + write(m_ha, m_hd, true); + else + { + m_host_intf.m_rw_strobe = false; + m_host_intf.m_host_access_strobe = true; + } + } +} + +u16 es5505_core::read(u8 address, bool cpu_access) +{ + return regs_r(m_page, address, cpu_access); +} + +void es5505_core::write(u8 address, u16 data, bool cpu_access) +{ + regs_w(m_page, address, data, cpu_access); +} + +u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u16 ret = 0xffff; + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 13) // Global registers + { + switch (address) + { + case 13: // ACT (Number of voices) + ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 14: // IRQV (Interrupting voice vector) + ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); + if (cpu_access) + { + m_irqv.clear(); + if (bitfield(ret, 7) != m_irqv.irqb) + m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); + } + break; + case 15: // PAGE (Page select register) + ret = (ret & ~0x7f) | bitfield(m_page, 0, 7); + break; + } + } + else + { + if (bitfield(page, 6)) // Channel registers + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + if (!cpu_access) // CPU can't read here + ret = m_ch[bitfield(address, 0, 2)].m_left; + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + if (!cpu_access) // CPU can't read here + ret = m_ch[bitfield(address, 0, 2)].m_right; + break; + case 6: // CH3L (Channel 3 Left) + if ((!cpu_access) || m_sermode.adc) + ret = m_ch[3].m_left; + break; + case 7: // CH3R (Channel 3 Right) + if ((!cpu_access) || m_sermode.adc) + ret = m_ch[3].m_right; + break; + case 8: // SERMODE (Serial Mode) + ret = (ret & ~0xf807) | + (m_sermode.adc ? 0x01 : 0x00) + | (m_sermode.test ? 0x02 : 0x00) + | (m_sermode.sony_bb ? 0x04 : 0x00) + | (bitfield(m_sermode.msb, 0, 5) << 11); + break; + case 9: // PAR (Port A/D Register) + ret = (ret & ~0x3f) | (m_intf.adc_r() & ~0x3f); + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + ret = v.m_filter.m_o4_1; + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + ret = v.m_filter.m_o3_2; + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + ret = v.m_filter.m_o3_1; + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + ret = v.m_filter.m_o2_2; + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + ret = v.m_filter.m_o2_1; + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + ret = v.m_filter.m_o1_1; + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + ret = (ret & ~0xfff) | + (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) + | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) + | (bitfield(v.m_cr.bs, 0) ? 0x04 : 0x00) + | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) + | (v.m_alu.m_cr.ble ? 0x10 : 0x00) + | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) + | (v.m_alu.m_cr.dir ? 0x40 : 0x00) + | (v.m_alu.m_cr.irq ? 0x80 : 0x00) + | (bitfield(v.m_cr.ca, 0, 2) << 8) + | (bitfield(v.m_filter.m_lp, 0, 2) << 10); + break; + case 1: // FC (Frequency Control) + ret = (ret & ~0xfffe) | (bitfield(v.m_alu.m_fc, 0, 15) << 1); + break; + case 2: // STRT-H (Loop Start Register High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); + break; + case 3: // STRT-L (Loop Start Register Low) + ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); + break; + case 5: // END-L (Loop End Register Low) + ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); + break; + case 8: // LVOL (Left Volume) + ret = (ret & ~0xff00) | ((v.m_lvol << 8) & 0xff00); + break; + case 9: // RVOL (Right Volume) + ret = (ret & ~0xff00) | ((v.m_rvol << 8) & 0xff00); + break; + case 10: // ACCH (Accumulator High) + ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); + break; + case 11: // ACCL (Accumulator Low) + ret = bitfield(v.m_alu.m_accum, 0, 16); + break; + } + } + } + } + + return ret; +} + +void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) +{ + address = bitfield(address, 0, 4); // 4 bit address for CPU access + + if (address >= 12) // Global registers + { + switch (address) + { + case 13: // ACT (Number of voices) + m_active = clamp(bitfield(data, 0, 5), 7, 31); + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 7); + break; + } + } + else // Voice specific registers + { + if (bitfield(page, 6)) // Channel registers + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + if (m_sermode.test) + m_ch[0].m_left = data; + break; + case 1: // CH0R (Channel 0 Right) + if (m_sermode.test) + m_ch[0].m_right = data; + break; + case 2: // CH1L (Channel 1 Left) + if (m_sermode.test) + m_ch[1].m_left = data; + break; + case 3: // CH1R (Channel 1 Right) + if (m_sermode.test) + m_ch[1].m_right = data; + break; + case 4: // CH2L (Channel 2 Left) + if (m_sermode.test) + m_ch[2].m_left = data; + break; + case 5: // CH2R (Channel 2 Right) + if (m_sermode.test) + m_ch[2].m_right = data; + break; + case 6: // CH3L (Channel 3 Left) + if (m_sermode.test) + m_ch[3].m_left = data; + break; + case 7: // CH3R (Channel 3 Right) + if (m_sermode.test) + m_ch[3].m_right = data; + break; + case 8: // SERMODE (Serial Mode) + m_sermode.adc = bitfield(data, 0); + m_sermode.test = bitfield(data, 1); + m_sermode.sony_bb = bitfield(data, 2); + m_sermode.msb = bitfield(data, 11, 5); + break; + case 9: // PAR (Port A/D Register) + // Read only + break; + } + } + else // Voice specific registers + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 56 + { + switch (address) + { + case 1: // O4(n-1) (Filter 4 Temp Register) + v.m_filter.m_o4_1 = sign_ext(data, 16); + break; + case 2: // O3(n-2) (Filter 3 Temp Register #2) + v.m_filter.m_o3_2 = sign_ext(data, 16); + break; + case 3: // O3(n-1) (Filter 3 Temp Register #1) + v.m_filter.m_o3_1 = sign_ext(data, 16); + break; + case 4: // O2(n-2) (Filter 2 Temp Register #2) + v.m_filter.m_o2_2 = sign_ext(data, 16); + break; + case 5: // O2(n-1) (Filter 2 Temp Register #1) + v.m_filter.m_o2_1 = sign_ext(data, 16); + break; + case 6: // O1(n-1) (Filter 1 Temp Register) + v.m_filter.m_o1_1 = sign_ext(data, 16); + break; + } + } + else // Page 0 - 24 + { + switch (address) + { + case 0: // CR (Control Register) + v.m_alu.m_cr.stop0 = bitfield(data, 0); + v.m_alu.m_cr.stop1 = bitfield(data, 1); + v.m_cr.bs = bitfield(data, 2); + v.m_alu.m_cr.lpe = bitfield(data, 3); + v.m_alu.m_cr.ble = bitfield(data, 4); + v.m_alu.m_cr.irqe = bitfield(data, 5); + v.m_alu.m_cr.dir = bitfield(data, 6); + v.m_alu.m_cr.irq = bitfield(data, 7); + v.m_cr.ca = bitfield(data, 8, 2); + v.m_filter.m_lp = bitfield(data, 10, 2); + break; + case 1: // FC (Frequency Control) + v.m_alu.m_fc = bitfield(data, 1, 15); + break; + case 2: // STRT-H (Loop Start Register High) + v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 3: // STRT-L (Loop Start Register Low) + v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); + break; + case 4: // END-H (Loop End Register High) + v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 5: // END-L (Loop End Register Low) + v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); + break; + case 6: // K2 (Filter Cutoff Coefficient #2) + v.m_filter.m_k2 = data & 0xfff0; + break; + case 7: // K1 (Filter Cutoff Coefficient #1) + v.m_filter.m_k1 = data & 0xfff0; + break; + case 8: // LVOL (Left Volume) + v.m_lvol = bitfield(data, 8, 8); + break; + case 9: // RVOL (Right Volume) + v.m_rvol = bitfield(data, 8, 8); + break; + case 10: // ACCH (Accumulator High) + v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); + break; + case 11: // ACCL (Accumulator Low) + v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; + break; + } + } + } + } +} diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp new file mode 100644 index 000000000..be6505f66 --- /dev/null +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -0,0 +1,141 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core + + See es550x.cpp for more info +*/ + +#include "es550x.hpp" + +#ifndef _VGSOUND_EMU_ES5505_HPP +#define _VGSOUND_EMU_ES5505_HPP + +#pragma once + +// ES5505 specific +class es5505_core : public es550x_shared_core +{ +public: + // constructor + es5505_core(es550x_intf &intf) + : es550x_shared_core(intf) + , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this} + { + } + // host interface + u16 host_r(u8 address); + void host_w(u8 address, u16 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // clock outputs + bool bclk() { return m_bclk.current_edge(); } + bool bclk_rising_edge() { return m_bclk.rising_edge(); } + bool bclk_falling_edge() { return m_bclk.falling_edge(); } + + // Input mode for Channel 3 + void lin(s32 in) { if (m_sermode.adc) { m_ch[3].m_left = in; } } + void rin(s32 in) { if (m_sermode.adc) { m_ch[3].m_right = in; } } + + // 4 stereo output channels + s32 lout(u8 ch) { return m_ch[ch & 0x3].m_left; } + s32 rout(u8 ch) { return m_ch[ch & 0x3].m_right; } + + // bypass chips host interface for debug purpose only + u16 read(u8 address, bool cpu_access = false); + void write(u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); + + u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + +protected: + virtual inline u8 max_voices() override { return 32; } + virtual void voice_tick() override; + +private: + struct output_t + { + void reset() + { + m_left = 0; + m_right = 0; + }; + + s32 m_left = 0; + s32 m_right = 0; + }; + + // es5505 voice structs + struct voice_t : es550x_voice_t + { + // constructor + voice_t(es5505_core &host) + : es550x_voice_t(20, 9, false) + , m_host(host) + {} + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + s32 volume_calc(u8 volume, s32 in); + + // registers + es5505_core &m_host; + u8 m_lvol = 0; // Left volume + u8 m_rvol = 0; // Right volume + output_t m_ch; // channel output + }; + + struct sermode_t + { + sermode_t() + : adc(0) + , test(0) + , sony_bb(0) + , msb(0) + {}; + + void reset() + { + adc = 0; + test = 0; + sony_bb = 0; + msb = 0; + } + + u8 adc : 1; // A/D + u8 test : 1; // Test + u8 sony_bb : 1; // Sony/BB format serial output + u8 msb : 5; // Serial output MSB + }; + + voice_t m_voice[32]; // 32 voices + // Serial related stuffs + sermode_t m_sermode; // Serial mode register + clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock + clock_pulse_t m_lrclk; // LRCLK + s16 m_wclk = 0; // WCLK + bool m_wclk_lr = false; // WCLK, L/R output select + u8 m_output_bit = 0; // Bit position in output + output_t m_ch[4]; // 4 stereo output channels + output_t m_output[4]; // Serial outputs + output_t m_output_temp[4]; // temporary signal for serial output + output_t m_output_latch[4]; // output latch +}; + +#endif diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp new file mode 100644 index 000000000..1bbee0e17 --- /dev/null +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -0,0 +1,787 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5506 emulation core + + see es550x.cpp for more info +*/ + +#include "es5506.hpp" + +// Internal functions +void es5506_core::tick() +{ + // CLKIN + if (m_clkin.tick()) + { + // BCLK + if (m_clkin.m_edge.m_changed && (!m_mode.bclk_en)) // BCLK is freely running clock + { + if (m_bclk.tick()) + { + m_intf.bclk(m_bclk.current_edge()); + // Serial output + if (!m_mode.lrclk_en) + { + if (m_bclk.falling_edge()) + { + // LRCLK + if (m_lrclk.tick()) + { + m_intf.lrclk(m_lrclk.current_edge()); + if (m_lrclk.rising_edge()) + { + m_w_st_curr = m_w_st; + m_w_end_curr = m_w_end; + } + if (m_lrclk.falling_edge()) // update width + m_lrclk.set_width_latch(m_lr_end); + } + } + } + // WCLK + if (!m_mode.wclk_en) + { + if (!m_mode.lrclk_en) + { + if (m_lrclk.m_edge.m_changed) + m_wclk = 0; + } + if (m_bclk.falling_edge()) + { + if (m_wclk == m_w_st_curr) + { + m_intf.wclk(true); + if (m_lrclk.current_edge()) + { + for (int i = 0; i < 6; i++) + { + // copy output + m_output[i] = m_output_temp[i]; + m_output_latch[i] = m_ch[i]; + m_output_temp[i].reset(); + // clamp to 20 bit (upper 3 bits are overflow guard bits) + m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x80000, 0x7ffff); + m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x80000, 0x7ffff); + // set signed + if (m_output_latch[i].m_left < 0) + m_output_temp[i].m_left = -1; + if (m_output_latch[i].m_right < 0) + m_output_temp[i].m_right = -1; + } + } + m_wclk_lr = m_lrclk.current_edge(); + m_output_bit = 20; + } + if (m_wclk < m_w_end_curr) + { + s8 output_bit = --m_output_bit; + if (m_output_bit >= 0) + { + for (int i = 0; i < 6; i++) + { + if (m_wclk_lr) // Right output + m_output_temp[i].m_right = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_right, output_bit); + else // Left output + m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); + } + } + } + if (m_wclk == m_w_end_curr) + m_intf.wclk(false); + + m_wclk++; + } + } + } + } + // /CAS, E + if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock + { + // /CAS + if (m_cas.tick()) + { + // single OTTO master mode, /CAS high, E low: get sample address + // single OTTO early mode, /CAS falling, E high: get sample address + if (m_cas.falling_edge()) + { + if (!m_e.current_edge()) + { + // single OTTO master mode, /CAS low, E low: fetch sample + if (m_mode.master) + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + else if (m_e.current_edge()) + { + // dual OTTO slave mode, /CAS low, E high: fetch sample + if (m_mode.dual && (!m_mode.master)) // Dual OTTO, slave mode + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + } + } + } + // E + if (m_e.tick()) + { + m_intf.e(m_e.current_edge()); + if (m_e.rising_edge()) + { + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + } + else if (m_e.falling_edge()) + { + m_host_intf.m_host_access = false; + voice_tick(); + } + if (m_e.current_edge()) // Host interface + { + if (m_host_intf.m_host_access) + { + if (m_host_intf.m_rw && (m_e.cycle() == 0)) // Read + { + m_hd = read(m_ha); + m_host_intf.m_host_access = false; + } + else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write + write(m_ha, m_hd); + } + } + else if (!m_e.current_edge()) + { + if (m_e.cycle() == 2) + { + // reset host access state + m_hd = 0; + m_host_intf.m_host_access_strobe = false; + } + } + } + } + } +} + +// less cycle accurate, but less CPU heavy routine +void es5506_core::tick_perf() +{ + // output + if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.bclk_en)) && (m_w_st < m_w_end)) + { + const int output_bits = 20 - (m_w_end - m_w_st); + if (output_bits < 20) + { + for (int c = 0; c < 6; c++) + { + m_output[c].m_left = clamp(m_ch[c].m_left, -0x80000, 0x7ffff) >> output_bits; + m_output[c].m_right = clamp(m_ch[c].m_right, -0x80000, 0x7ffff) >> output_bits; + } + } + } + else + { + for (int c = 0; c < 6; c++) + { + m_output[c].m_left = 0; + m_output[c].m_right = 0; + } + } + + // update + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; + // falling edge + m_e.m_edge.set(false); + m_intf.e(false); + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; + m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); + voice_tick(); + // rising edge + m_e.m_edge.set(true); + m_intf.e(true); + m_host_intf.m_rw = m_host_intf.m_rw_strobe; + m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; +} + +void es5506_core::voice_tick() +{ + // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) + if (bitfield(m_voice_fetch++, 0)) + { + // Update voice + m_voice[m_voice_cycle].tick(m_voice_cycle); + + // Refresh output + if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices + { + m_voice_cycle = 0; + for (auto & elem : m_ch) + elem.reset(); + + for (auto & elem : m_voice) + { + const u8 ca = bitfield(elem.m_cr.ca, 0, 3); + if (ca < 6) + { + m_ch[ca].m_left += elem.m_ch.m_left; + m_ch[ca].m_right += elem.m_ch.m_right; + } + elem.m_ch.reset(); + } + } + m_voice_fetch = 0; + } +} + +void es5506_core::voice_t::fetch(u8 voice, u8 cycle) +{ + m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0, 1), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); + if (m_cr.cmpd) // Decompress (Upper 8 bit is used for compressed format) + m_alu.m_sample[cycle] = decompress(bitfield(m_alu.m_sample[cycle], 8, 8)); +} + +void es5506_core::voice_t::tick(u8 voice) +{ + m_ch.reset(); + + // Filter execute + m_filter.tick(m_alu.interpolation()); + + if (m_alu.busy()) + { + if (!m_mute) + { + // Send to output + m_ch.m_left = volume_calc(sign_ext(m_filter.m_o4_1, 16), m_lvol); + m_ch.m_right = volume_calc(sign_ext(m_filter.m_o4_1, 16), m_rvol); + } + + // ALU execute + if (m_alu.tick()) + m_alu.loop_exec(); + } + // Envelope + if (m_ecount != 0) + { + // Left and Right volume + if (bitfield(m_lvramp, 0, 8) != 0) + m_lvol = clamp(m_lvol + sign_ext(bitfield(m_lvramp, 0, 8), 8), 0, 0xffff); + if (bitfield(m_rvramp, 0, 8) != 0) + m_rvol = clamp(m_rvol + sign_ext(bitfield(m_rvramp, 0, 8), 8), 0, 0xffff); + + // Filter coeffcient + if ((m_k1ramp.ramp != 0) && ((m_k1ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) + m_filter.m_k1 = clamp(m_filter.m_k1 + sign_ext(m_k1ramp.ramp, 8), 0, 0xffff); + if ((m_k2ramp.ramp != 0) && ((m_k2ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) + m_filter.m_k2 = clamp(m_filter.m_k2 + sign_ext(m_k2ramp.ramp, 8), 0, 0xffff); + + m_ecount--; + } + m_filtcount = bitfield(m_filtcount + 1, 0, 3); + + // Update IRQ + m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); +} + +// Compressed format +s16 es5506_core::voice_t::decompress(u8 sample) +{ + u8 exponent = bitfield(sample, 5, 3); + u8 mantissa = bitfield(sample, 0, 5); + return (exponent > 0) ? + s16(((bitfield(mantissa, 4) ? 0x10 : ~0x1f) | bitfield(mantissa, 0, 4)) << (4 + (exponent - 1))) : + s16(((bitfield(mantissa, 4) ? ~0xf : 0) | bitfield(mantissa, 0, 4)) << 4); +} + +// volume calculation +s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in) +{ + u8 exponent = bitfield(volume, 12, 4); + u8 mantissa = bitfield(volume, 4, 8); + return (in * s32(0x100 | mantissa)) >> (20 - exponent); +} + +void es5506_core::reset() +{ + es550x_shared_core::reset(); + for (auto & elem : m_voice) + elem.reset(); + + m_read_latch = 0xffffffff; + m_write_latch = 0xffffffff; + m_w_st = 0; + m_w_end = 0; + m_lr_end = 0; + m_w_st_curr = 0; + m_w_end_curr = 0; + m_mode.reset(); + m_bclk.reset(); + m_lrclk.reset(32); + m_wclk = 0; + m_wclk_lr = false; + m_output_bit = 0; + for (auto & elem : m_ch) + elem.reset(); + for (auto & elem : m_output) + elem.reset(); + for (auto & elem : m_output_temp) + elem.reset(); + for (auto & elem : m_output_latch) + elem.reset(); +} + +void es5506_core::voice_t::reset() +{ + es550x_shared_core::es550x_voice_t::reset(); + m_lvol = 0; + m_lvramp = 0; + m_rvol = 0; + m_rvramp = 0; + m_ecount = 0; + m_k2ramp.reset(); + m_k1ramp.reset(); + m_filtcount = 0; + m_ch.reset(); + m_mute = false; +} + +// Accessors +u8 es5506_core::host_r(u8 address) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + if (m_e.rising_edge()) // update directly + m_hd = read(m_ha, true); + else + { + m_host_intf.m_rw_strobe = true; + m_host_intf.m_host_access_strobe = true; + } + } + return m_hd; +} + +void es5506_core::host_w(u8 address, u8 data) +{ + if (!m_host_intf.m_host_access) + { + m_ha = address; + m_hd = data; + if (m_e.rising_edge()) // update directly + write(m_ha, m_hd, true); + else + { + m_host_intf.m_rw_strobe = false; + m_host_intf.m_host_access_strobe = true; + } + } +} + +u8 es5506_core::read(u8 address, bool cpu_access) +{ + const u8 byte = bitfield(address, 0, 2); // byte select + const u8 shift = 24 - (byte << 3); + if (byte != 0) // Return already latched register if not highest byte is accessing + return bitfield(m_read_latch, shift, 8); + + address = bitfield(address, 2, 4); // 4 bit address for CPU access + + // get read register + m_read_latch = regs_r(m_page, address, cpu_access); + + return bitfield(m_read_latch, 24, 8); +} + +void es5506_core::write(u8 address, u8 data, bool cpu_access) +{ + const u8 byte = bitfield(address, 0, 2); // byte select + const u8 shift = 24 - (byte << 3); + address = bitfield(address, 2, 4); // 4 bit address for CPU access + + // Update register latch + m_write_latch = (m_write_latch & ~(0xff << shift)) | (u32(data) << shift); + + if (byte != 3) // Wait until lowest byte is writed + return; + + regs_w(m_page, address, m_write_latch, cpu_access); + + // Reset latch + m_write_latch = 0; +} + +u32 es5506_core::regs_r(u8 page, u8 address, bool cpu_access) +{ + u32 read_latch = 0xffffffff; + if (address >= 13) // Global registers + { + switch (address) + { + case 13: // POT (Pot A/D Register) + read_latch = (read_latch & ~0x3ff) | bitfield(m_intf.adc_r(), 0, 10); + break; + case 14: // IRQV (Interrupting voice vector) + read_latch = (read_latch & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); + if (cpu_access) + { + m_irqv.clear(); + if (bitfield(read_latch, 7) != m_irqv.irqb) + m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); + } + break; + case 15: // PAGE (Page select register) + read_latch = (read_latch & ~0x7f) | bitfield(m_page, 0, 7); + break; + } + } + else + { + if (bitfield(page, 6)) // Channel registers are Write only + { + if (!cpu_access) // CPU can't read here + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + case 6: // CH3L (Channel 3 Left) + case 8: // CH4L (Channel 4 Left) + case 10: // CH5L (Channel 5 Left) + read_latch = m_ch[bitfield(address, 1, 3)].m_left; + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + case 7: // CH3R (Channel 3 Right) + case 9: // CH4R (Channel 4 Right) + case 11: // CH5R (Channel 5 Right) + read_latch = m_ch[bitfield(address, 1, 3)].m_right; + break; + } + } + } + else + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 0: // CR (Control Register) + read_latch = (read_latch & ~0xffff) | + (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) + | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) + | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) + | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) + | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) + | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) + | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) + | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) + | (bitfield(v.m_filter.m_lp, 0, 2) << 8) + | (bitfield(v.m_cr.ca, 0, 3) << 10) + | (v.m_cr.cmpd ? 0x2000 : 0x0000) + | (bitfield(v.m_cr.bs, 0, 2) << 14); + break; + case 1: // START (Loop Start Register) + read_latch = (read_latch & ~0xfffff800) | (v.m_alu.m_start & 0xfffff800); + break; + case 2: // END (Loop End Register) + read_latch = (read_latch & ~0xffffff80) | (v.m_alu.m_end & 0xffffff80); + break; + case 3: // ACCUM (Accumulator Register) + read_latch = v.m_alu.m_accum; + break; + case 4: // O4(n-1) (Filter 4 Temp Register) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o4_1, 0, 18); + else + read_latch = v.m_filter.m_o4_1; + break; + case 5: // O3(n-2) (Filter 3 Temp Register #2) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_2, 0, 18); + else + read_latch = v.m_filter.m_o3_2; + break; + case 6: // O3(n-1) (Filter 3 Temp Register #1) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_1, 0, 18); + else + read_latch = v.m_filter.m_o3_1; + break; + case 7: // O2(n-2) (Filter 2 Temp Register #2) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_2, 0, 18); + else + read_latch = v.m_filter.m_o2_2; + break; + case 8: // O2(n-1) (Filter 2 Temp Register #1) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_1, 0, 18); + else + read_latch = v.m_filter.m_o2_1; + break; + case 9: // O1(n-1) (Filter 1 Temp Register) + if (cpu_access) + read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o1_1, 0, 18); + else + read_latch = v.m_filter.m_o1_1; + break; + case 10: // W_ST (Word Clock Start Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_w_st, 0, 7); + break; + case 11: // W_END (Word Clock End Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_w_end, 0, 7); + break; + case 12: // LR_END (Left/Right Clock End Register) + read_latch = (read_latch & ~0x7f) | bitfield(m_lr_end, 0, 7); + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + read_latch = (read_latch & ~0xffff) | + (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) + | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) + | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) + | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) + | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) + | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) + | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) + | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) + | (bitfield(v.m_filter.m_lp, 0, 2) << 8) + | (bitfield(v.m_cr.ca, 0, 3) << 10) + | (v.m_cr.cmpd ? 0x2000 : 0x0000) + | (bitfield(v.m_cr.bs, 0, 2) << 14); + break; + case 1: // FC (Frequency Control) + read_latch = (read_latch & ~0x1ffff) | bitfield(v.m_alu.m_fc, 0, 17); + break; + case 2: // LVOL (Left Volume) + read_latch = (read_latch & ~0xffff) | bitfield(v.m_lvol, 0, 16); + break; + case 3: // LVRAMP (Left Volume Ramp) + read_latch = (read_latch & ~0xff00) | (bitfield(v.m_lvramp, 0, 8) << 8); + break; + case 4: // RVOL (Right Volume) + read_latch = (read_latch & ~0xffff) | bitfield(v.m_rvol, 0, 16); + break; + case 5: // RVRAMP (Right Volume Ramp) + read_latch = (read_latch & ~0xff00) | (bitfield(v.m_rvramp, 0, 8) << 8); + break; + case 6: // ECOUNT (Envelope Counter) + read_latch = (read_latch & ~0x01ff) | bitfield(v.m_ecount, 0, 9); + break; + case 7: // K2 (Filter Cutoff Coefficient #2) + read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k2, 0, 16); + break; + case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) + read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k2ramp.ramp, 0, 8) << 8) | (v.m_k2ramp.slow ? 0x0001 : 0x0000); + break; + case 9: // K1 (Filter Cutoff Coefficient #1) + read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k1, 0, 16); + break; + case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) + read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k1ramp.ramp, 0, 8) << 8) | (v.m_k1ramp.slow ? 0x0001 : 0x0000); + break; + case 11: // ACT (Number of voices) + read_latch = (read_latch & ~0x1f) | bitfield(m_active, 0, 5); + break; + case 12: // MODE (Global Mode) + read_latch = (read_latch & ~0x1f) | + (m_mode.lrclk_en ? 0x01 : 0x00) + | (m_mode.wclk_en ? 0x02 : 0x00) + | (m_mode.bclk_en ? 0x04 : 0x00) + | (m_mode.master ? 0x08 : 0x00) + | (m_mode.dual ? 0x10 : 0x00); + break; + } + } + } + } + + return read_latch; +} + +void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) +{ + if (address >= 13) // Global registers + { + switch (address) + { + case 13: // POT (Pot A/D Register) + // Read only + break; + case 14: // IRQV (Interrupting voice vector) + // Read only + break; + case 15: // PAGE (Page select register) + m_page = bitfield(data, 0, 7); + break; + } + } + else + { + if (bitfield(page, 6)) // Channel registers are Write only, and for test purposes + { + switch (address) + { + case 0: // CH0L (Channel 0 Left) + case 2: // CH1L (Channel 1 Left) + case 4: // CH2L (Channel 2 Left) + case 6: // CH3L (Channel 3 Left) + case 8: // CH4L (Channel 4 Left) + case 10: // CH5L (Channel 5 Left) + m_ch[bitfield(address, 1, 3)].m_left = sign_ext(bitfield(data, 0, 23), 23); + break; + case 1: // CH0R (Channel 0 Right) + case 3: // CH1R (Channel 1 Right) + case 5: // CH2R (Channel 2 Right) + case 7: // CH3R (Channel 3 Right) + case 9: // CH4R (Channel 4 Right) + case 11: // CH5R (Channel 5 Right) + m_ch[bitfield(address, 1, 3)].m_right = sign_ext(bitfield(data, 0, 23), 23); + break; + } + } + else + { + const u8 voice = bitfield(page, 0, 5); // Voice select + voice_t &v = m_voice[voice]; + if (bitfield(page, 5)) // Page 32 - 63 + { + switch (address) + { + case 0: // CR (Control Register) + v.m_alu.m_cr.stop0 = bitfield(data, 0); + v.m_alu.m_cr.stop1 = bitfield(data, 1); + v.m_alu.m_cr.lei = bitfield(data, 2); + v.m_alu.m_cr.lpe = bitfield(data, 3); + v.m_alu.m_cr.ble = bitfield(data, 4); + v.m_alu.m_cr.irqe = bitfield(data, 5); + v.m_alu.m_cr.dir = bitfield(data, 6); + v.m_alu.m_cr.irq = bitfield(data, 7); + v.m_filter.m_lp = bitfield(data, 8, 2); + v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); + v.m_cr.cmpd = bitfield(data, 13); + v.m_cr.bs = bitfield(data, 14, 2); + break; + case 1: // START (Loop Start Register) + v.m_alu.m_start = data & 0xfffff800; + break; + case 2: // END (Loop End Register) + v.m_alu.m_end = data & 0xffffff80; + break; + case 3: // ACCUM (Accumulator Register) + v.m_alu.m_accum = data; + break; + case 4: // O4(n-1) (Filter 4 Temp Register) + v.m_filter.m_o4_1 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 5: // O3(n-2) (Filter 3 Temp Register #2) + v.m_filter.m_o3_2 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 6: // O3(n-1) (Filter 3 Temp Register #1) + v.m_filter.m_o3_1 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 7: // O2(n-2) (Filter 2 Temp Register #2) + v.m_filter.m_o2_2 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 8: // O2(n-1) (Filter 2 Temp Register #1) + v.m_filter.m_o2_1 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 9: // O1(n-1) (Filter 1 Temp Register) + v.m_filter.m_o1_1 = sign_ext(bitfield(data, 0, 18), 18); + break; + case 10: // W_ST (Word Clock Start Register) + m_w_st = bitfield(data, 0, 7); + break; + case 11: // W_END (Word Clock End Register) + m_w_end = bitfield(data, 0, 7); + break; + case 12: // LR_END (Left/Right Clock End Register) + m_lr_end = bitfield(data, 0, 7); + m_lrclk.set_width(m_lr_end); + break; + } + } + else // Page 0 - 31 + { + switch (address) + { + case 0: // CR (Control Register) + v.m_alu.m_cr.stop0 = bitfield(data, 0); + v.m_alu.m_cr.stop1 = bitfield(data, 1); + v.m_alu.m_cr.lei = bitfield(data, 2); + v.m_alu.m_cr.lpe = bitfield(data, 3); + v.m_alu.m_cr.ble = bitfield(data, 4); + v.m_alu.m_cr.irqe = bitfield(data, 5); + v.m_alu.m_cr.dir = bitfield(data, 6); + v.m_alu.m_cr.irq = bitfield(data, 7); + v.m_filter.m_lp = bitfield(data, 8, 2); + v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); + v.m_cr.cmpd = bitfield(data, 13); + v.m_cr.bs = bitfield(data, 14, 2); + break; + case 1: // FC (Frequency Control) + v.m_alu.m_fc = bitfield(data, 0, 17); + break; + case 2: // LVOL (Left Volume) + v.m_lvol = bitfield(data, 0, 16); + break; + case 3: // LVRAMP (Left Volume Ramp) + v.m_lvramp = bitfield(data, 8, 8); + break; + case 4: // RVOL (Right Volume) + v.m_rvol = bitfield(data, 0, 16); + break; + case 5: // RVRAMP (Right Volume Ramp) + v.m_rvramp = bitfield(data, 8, 8); + break; + case 6: // ECOUNT (Envelope Counter) + v.m_ecount = bitfield(data, 0, 9); + break; + case 7: // K2 (Filter Cutoff Coefficient #2) + v.m_filter.m_k2 = bitfield(data, 0, 16); + break; + case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) + v.m_k2ramp.slow = bitfield(data, 0); + v.m_k2ramp.ramp = bitfield(data, 8, 8); + break; + case 9: // K1 (Filter Cutoff Coefficient #1) + v.m_filter.m_k1 = bitfield(data, 0, 16); + break; + case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) + v.m_k1ramp.slow = bitfield(data, 0); + v.m_k1ramp.ramp = bitfield(data, 8, 8); + break; + case 11: // ACT (Number of voices) + m_active = std::min(4, bitfield(data, 0, 5)); + break; + case 12: // MODE (Global Mode) + m_mode.lrclk_en = bitfield(data, 0); + m_mode.wclk_en = bitfield(data, 1); + m_mode.bclk_en = bitfield(data, 2); + m_mode.master = bitfield(data, 3); + m_mode.dual = bitfield(data, 4); + break; + } + } + } + } +} diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp new file mode 100644 index 000000000..2232f5179 --- /dev/null +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -0,0 +1,179 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504 emulation core + + See es550x.cpp for more info +*/ + +#include "es550x.hpp" + +#ifndef _VGSOUND_EMU_ES5506_HPP +#define _VGSOUND_EMU_ES5506_HPP + +#pragma once + +// ES5506 specific +class es5506_core : public es550x_shared_core +{ +public: + // constructor + es5506_core(es550x_intf &intf) + : es550x_shared_core(intf) + , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this, + *this,*this,*this,*this,*this,*this,*this,*this} + { + } + // host interface + u8 host_r(u8 address); + void host_w(u8 address, u8 data); + + // internal state + virtual void reset() override; + virtual void tick() override; + + // less cycle accurate, but also less cpu heavy update routine + void tick_perf(); + + // clock outputs + bool bclk() { return m_bclk.current_edge(); } + bool bclk_rising_edge() { return m_bclk.rising_edge(); } + bool bclk_falling_edge() { return m_bclk.falling_edge(); } + + // 6 stereo output channels + s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_left; } + s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_right; } + + // bypass chips host interface for debug purpose only + u8 read(u8 address, bool cpu_access = false); + void write(u8 address, u8 data, bool cpu_access = false); + + u32 regs_r(u8 page, u8 address, bool cpu_access = false); + void regs_w(u8 page, u8 address, u32 data, bool cpu_access = false); + + u8 regs8_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u8 ret = read(address, false); m_page = prev; return ret; } + void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].m_mute = mute; } + +protected: + virtual inline u8 max_voices() override { return 32; } + virtual void voice_tick() override; + +private: + struct output_t + { + void reset() + { + m_left = 0; + m_right = 0; + }; + + s32 m_left = 0; + s32 m_right = 0; + }; + + // es5506 voice structs + struct voice_t : es550x_voice_t + { + // constructor + voice_t(es5506_core &host) + : es550x_voice_t(21, 11, true) + , m_host(host) {} + + // internal state + virtual void reset() override; + virtual void fetch(u8 voice, u8 cycle) override; + virtual void tick(u8 voice) override; + + // accessors, getters, setters + s16 decompress(u8 sample); + s32 volume_calc(u16 volume, s32 in); + + struct filter_ramp_t + { + filter_ramp_t() + : slow(0) + , ramp(0) + { }; + + void reset() + { + slow = 0; + ramp = 0; + }; + + u16 slow : 1; // Slow mode flag + u16 ramp = 8; // Ramp value + }; + + // registers + es5506_core &m_host; + s32 m_lvol = 0; // Left volume - 4 bit exponent, 8 bit mantissa, 4 LSBs are used for fine control of ramp increment for hardware envelope + s32 m_lvramp = 0; // Left volume ramp + s32 m_rvol = 0; // Right volume + s32 m_rvramp = 0; // Righr volume ramp + s16 m_ecount = 0; // Envelope counter + filter_ramp_t m_k2ramp; // Filter coefficient 2 Ramp + filter_ramp_t m_k1ramp; // Filter coefficient 1 Ramp + u8 m_filtcount = 0; // Internal counter for slow mode + output_t m_ch; // channel output + bool m_mute = false; // mute flag (for debug purpose) + }; + + // 5 bit mode + struct mode_t + { + mode_t() + : bclk_en(0) + , wclk_en(0) + , lrclk_en(0) + , master(0) + , dual(0) + { }; + + void reset() + { + bclk_en = 1; + wclk_en = 1; + lrclk_en = 1; + master = 0; + dual = 0; + } + + u8 bclk_en : 1; // Set BCLK to output + u8 wclk_en : 1; // Set WCLK to output + u8 lrclk_en : 1; // Set LRCLK to output + u8 master : 1; // Set memory mode to master + u8 dual : 1; // Set dual chip config + }; + + voice_t m_voice[32]; // 32 voices + + // Host interfaces + u32 m_read_latch = 0; // 32 bit register latch for host read + u32 m_write_latch = 0; // 32 bit register latch for host write + + // Serial register + u8 m_w_st = 0; // Word clock start register + u8 m_w_end = 0; // Word clock end register + u8 m_lr_end = 0; // Left/Right clock end register + mode_t m_mode; // Global mode + + // Serial related stuffs + u8 m_w_st_curr = 0; // Word clock start, current status + u8 m_w_end_curr = 0; // Word clock end register + clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock + clock_pulse_t m_lrclk; // LRCLK + s16 m_wclk = 0; // WCLK + bool m_wclk_lr = false; // WCLK, L/R output select + u8 m_output_bit = 0; // Bit position in output + output_t m_ch[6]; // 6 stereo output channels + output_t m_output[6]; // Serial outputs + output_t m_output_temp[6]; // temporary signal for serial output + output_t m_output_latch[6]; // output latch +}; + +#endif diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp new file mode 100644 index 000000000..8047e1706 --- /dev/null +++ b/src/engine/platform/sound/es550x/es550x.cpp @@ -0,0 +1,75 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 emulation core + + After ES5503 DOC's appeared, Ensoniq announces ES5504 DOC II, ES5505 OTIS, ES5506 OTTO. + + These are not just PCM chip; but with built-in 4 pole filters and variable voice limits. + + It can be trades higher sample rate and finer frequency and Tons of voices, or vice-versa. + + These are mainly used with their synthesizers, musical stuffs. It's also mainly paired with ES5510 ESP/ES5511 ESP2 for post processing. + ES5506 can be paired with itself, It's called Dual chip configuration and Both chips are can be shares same memory spaces. + + ES5505 was also mainly used on Taito's early- to late-90s arcade hardware for their PCM sample based sound system, + paired with ES5510 ESP for post processing. It's configuration is borrowed from Ensoniq's 32 Voice synths powered by these chips. + It's difference is external logic to adds per-voice bankswitching looks like what Konami doing on K007232. + + Atari Panther was will be use ES5505, but finally canceled. + + Ensoniq's ISA Sound Card for PC, Soundscape used ES5506, "Elite" model has optional daughterboard with ES5510 for digital effects. + + Related chips: + ES5530 "OPUS" variant is 2-in-one chip with built-in ES5506 and Sequoia. + ES5540 "OTTOFX" variant is ES5506 and ES5510 merged in single package. + ES5548 "OTTO48" variant is used at late-90s ensoniq synths and musical instruments, 2 ES5506s are merged in single package, or with 48 voices in chip? + + Chip difference: + ES5504 to ES5505: + Total voice amount is expanded to 32, rather than 25. + ADC and DAC is completely redesigned. it's has now voice-independent 10 bit and Sony/Burr-Brown format DAC. + Output channel and Volume is changed to 16 mono to 4 stereo, 12 bit Analog to 8 bit Stereo digital, also Floating point-ish format and independent per left and right output. + Channel 3 is can be Input/Output. + Channel output is can be accessible at host for test purpose. + Max sample memory is expanded to 2MWords (1MWords * 2 Banks) + + ES5505 to ES5506: + Frequency is more finer now: 11 bit fraction rather than 9 bit. + Output channel and Volume is changed to 4 stereo to 6 stereo, 8 bit to 16 bit, but only 12 bit is used for calculation; 4 LSB is used for envelope ramping. + Transwave flag is added - its helpful for transwave process, with interrupt per voices. + Hardware envelope is added - K1, K2, Volume value is can be modified in run-time. also K1, K2 is expanded to 16 bit for finer envelope ramping. + Filter calculation resolution is expanded to 18 bit. + All channels are output, Serial output is now partially programmable. + Max sample memory is expanded to 8MWords (2MWords * 4 Banks) + + Register format between these chips are incompatible. + +*/ + +#include "es550x.hpp" + +// Shared functions +void es550x_shared_core::reset() +{ + m_host_intf.reset(); + m_ha = 0; + m_hd = 0; + m_page = 0; + m_irqv.reset(); + m_active = max_voices() - 1; + m_voice_cycle = 0; + m_voice_fetch = 0; + m_clkin.reset(); + m_cas.reset(); + m_e.reset(); +} + +void es550x_shared_core::es550x_voice_t::reset() +{ + m_cr.reset(); + m_alu.reset(); + m_filter.reset(); +} diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp new file mode 100644 index 000000000..e3652c60a --- /dev/null +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -0,0 +1,391 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 emulation core + + See es550x.cpp for more info +*/ + +#include +#include + +#ifndef _VGSOUND_EMU_ES550X_HPP +#define _VGSOUND_EMU_ES550X_HPP + +#pragma once + +namespace es550x +{ + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + typedef signed char s8; + typedef signed short s16; + typedef signed int s32; + + // get bitfield, bitfield(input, position, len) + template T bitfield(T in, u8 pos, u8 len = 1) + { + return (in >> pos) & (len ? (T(1 << len) - 1) : 1); + } + + // get sign extended value, sign_ext(input, len) + template T sign_ext(T in, u8 len) + { + len = std::max(0, (8 * sizeof(T)) - len); + return T(T(in) << len) >> len; + } + + // std::clamp is only for C++17 or later; I use my own code + template T clamp(T in, T min, T max) + { + return (in > max) ? max : ((in < min) ? min : in); + } + + template + struct clock_pulse_t + { + void reset(T init = InitWidth) + { + m_edge.reset(); + m_width = m_width_latch = m_counter = init; + m_cycle = 0; + } + + bool tick(T width = 0) + { + bool carry = ((--m_counter) <= 0); + if (carry) + { + if (!width) + m_width = m_width_latch; + else + m_width = width; // reset width + m_counter = m_width; + m_cycle = 0; + } + else + m_cycle++; + + m_edge.tick(carry); + return carry; + } + + void set_width(T width) { m_width = width; } + void set_width_latch(T width) { m_width_latch = width; } + + // Accessors + bool current_edge() { return m_edge.m_current; } + bool rising_edge() { return m_edge.m_rising; } + bool falling_edge() { return m_edge.m_rising; } + T cycle() { return m_cycle; } + + struct edge_t + { + edge_t() + : m_current(InitEdge ^ 1) + , m_previous(InitEdge) + , m_rising(0) + , m_falling(0) + , m_changed(0) + { + set(InitEdge); + } + + void tick(bool toggle) + { + u8 current = m_current; + if (toggle) + current ^= 1; + set(current); + } + + void set(u8 edge) + { + edge &= 1; + m_rising = m_falling = m_changed = 0; + if (m_current != edge) + { + m_changed = 1; + if (m_current && (!edge)) + m_falling = 1; + else if ((!m_current) && edge) + m_rising = 1; + m_current = edge; + } + m_previous = m_current; + } + + void reset() + { + m_previous = InitEdge; + m_current = InitEdge ^ 1; + set(InitEdge); + } + + u8 m_current : 1; // current edge + u8 m_previous : 1; // previous edge + u8 m_rising : 1; // rising edge + u8 m_falling : 1; // falling edge + u8 m_changed : 1; // changed flag + }; + + edge_t m_edge; + T m_width = InitWidth; // clock pulse width + T m_width_latch = InitWidth; // clock pulse width latch + T m_counter = InitWidth; // clock counter + T m_cycle = 0; // clock cycle + }; +}; + +// ES5504/ES5505/ES5506 interface +using namespace es550x; +class es550x_intf +{ +public: + virtual void e(bool state) {} // E output + virtual void bclk(bool state) {} // BCLK output (serial specific) + virtual void lrclk(bool state) {} // LRCLK output (serial specific) + virtual void wclk(bool state) {} // WCLK output (serial specific) + + virtual void irqb(bool state) {} // IRQB output + virtual u16 adc_r() { return 0; } // ADC input + virtual void adc_w(u16 data) {} // ADC output + virtual s16 read_sample(u8 voice, u8 bank, u32 address) { return 0; } +}; + +// Shared functions for ES5504/ES5505/ES5506 +using namespace es550x; +class es550x_shared_core +{ + friend class es550x_intf; // es550x specific memory interface +public: + // constructor + es550x_shared_core(es550x_intf &intf) + : m_intf(intf) + { }; + + // internal state + virtual void reset(); + virtual void tick() {} + + // clock outputs + bool _cas() { return m_cas.current_edge(); } + bool _cas_rising_edge() { return m_cas.rising_edge(); } + bool _cas_falling_edge() { return m_cas.falling_edge(); } + + bool e() { return m_e.current_edge(); } + bool e_rising_edge() { return m_e.rising_edge(); } + bool e_falling_edge() { return m_e.falling_edge(); } + +protected: + // Constants + virtual inline u8 max_voices() { return 32; } + + // Shared registers, functions + virtual void voice_tick() {} // voice tick + + // Interrupt bits + struct es550x_irq_t + { + es550x_irq_t() + : voice(0) + , irqb(1) + { }; + + void reset() + { + voice = 0; + irqb = 1; + } + + void set(u8 index) + { + irqb = 0; + voice = index; + } + + void clear() + { + irqb = 1; + voice = 0; + } + + u8 voice : 5; + u8 irqb : 1; + }; + + // Common control bits + struct es550x_control_t + { + es550x_control_t() + : ca(0) + , adc(0) + , bs(0) + , cmpd(0) + { }; + + void reset() + { + ca = 0; + adc = 0; + bs = 0; + cmpd = 0; + } + + u8 ca : 4; // Channel assign (4 bit (16 channel or Bank) for ES5504, 2 bit (4 stereo channels) for ES5505, 3 bit (6 stereo channels) for ES5506) + // ES5504 Specific + u8 adc : 1; // Start ADC + // ES5505/ES5506 Specific + u8 bs : 2; // Bank bit (1 bit for ES5505, 2 bit for ES5506) + u8 cmpd : 1; // Use compressed sample format + }; + + // Accumulator + struct es550x_alu_t + { + es550x_alu_t(u8 integer, u8 fraction, bool transwave) + : m_integer(integer) + , m_fraction(fraction) + , m_total_bits(integer + fraction) + , m_transwave(transwave) + {} + + const u8 m_integer; + const u8 m_fraction; + const u8 m_total_bits; + const bool m_transwave; + + void reset(); + bool busy(); + bool tick(); + void loop_exec(); + s32 interpolation(); + u32 get_accum_integer(); + void irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index); + void irq_update(es550x_intf &intf, es550x_irq_t &irqv) { intf.irqb(irqv.irqb ? false : true); } + + struct es550x_alu_cr_t + { + es550x_alu_cr_t() + : stop0(0) + , stop1(0) + , lpe(0) + , ble(0) + , irqe(0) + , dir(0) + , irq(0) + , lei(0) + { }; + + void reset() + { + stop0 = 0; + stop1 = 0; + lpe = 0; + ble = 0; + irqe = 0; + dir = 0; + irq = 0; + lei = 0; + } + + u8 stop0 : 1; // Stop with ALU + u8 stop1 : 1; // Stop with processor + u8 lpe : 1; // Loop enable + u8 ble : 1; // Bidirectional loop enable + u8 irqe : 1; // IRQ enable + u8 dir : 1; // Playback direction + u8 irq : 1; // IRQ bit + u8 lei : 1; // Loop end ignore (ES5506 specific) + }; + + es550x_alu_cr_t m_cr; + u32 m_fc = 0; // Frequency - 6 integer, 9 fraction for ES5506/ES5505, 6 integer, 11 fraction for ES5506 + u32 m_start = 0; // Start register + u32 m_end = 0; // End register + u32 m_accum = 0; // Accumulator - 20 integer, 9 fraction for ES5506/ES5505, 21 integer, 11 fraction for ES5506 + s32 m_sample[2] = {0}; // Samples + }; + + // Filter + struct es550x_filter_t + { + void reset(); + void tick(s32 in); + s32 lp_exec(s32 coeff, s32 in, s32 prev_out); + s32 hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in); + + // Registers + u8 m_lp = 0; // Filter mode + // Filter coefficient registers + s32 m_k2 = 0; // Filter coefficient 2 - 12 bit for filter calculation, 4 LSBs are used for fine control of ramp increment for hardware envelope (ES5506) + s32 m_k1 = 0; // Filter coefficient 1 + // Filter storage registers + s32 m_o1_1 = 0; // First stage + s32 m_o2_1 = 0; // Second stage + s32 m_o2_2 = 0; // Second stage HP + s32 m_o3_1 = 0; // Third stage + s32 m_o3_2 = 0; // Third stage HP + s32 m_o4_1 = 0; // Final stage + }; + + // Common voice struct + struct es550x_voice_t + { + es550x_voice_t(u8 integer, u8 fraction, bool transwave) + : m_alu(integer, fraction, transwave) + {} + + // internal state + virtual void reset(); + virtual void fetch(u8 voice, u8 cycle) = 0; + virtual void tick(u8 voice) = 0; + + es550x_control_t m_cr; + es550x_alu_t m_alu; + es550x_filter_t m_filter; + }; + + + // Host interfaces + struct host_interface_flag_t + { + host_interface_flag_t() + : m_host_access(0) + , m_host_access_strobe(0) + , m_rw(0) + , m_rw_strobe(0) + {} + + void reset() + { + m_host_access = 0; + m_host_access_strobe = 0; + m_rw = 0; + m_rw_strobe = 0; + } + + u8 m_host_access : 1; // Host access trigger + u8 m_host_access_strobe : 1; // Host access strobe + u8 m_rw : 1; // R/W state + u8 m_rw_strobe : 1; // R/W strobe + }; + host_interface_flag_t m_host_intf; // Host interface flag + u8 m_ha = 0; // Host address (4 bit) + u16 m_hd = 0; // Host data (16 bit for ES5504/ES5505, 8 bit for ES5506) + u8 m_page = 0; // Page + es550x_irq_t m_irqv; // Voice interrupt vector registers + // Internal states + u8 m_active = max_voices() - 1; // Activated voices (-1, ~25 for ES5504, ~32 for ES5505/ES5506) + u8 m_voice_cycle = 0; // Voice cycle + u8 m_voice_fetch = 0; // Voice fetch cycle + es550x_intf &m_intf; // es550x specific memory interface + clock_pulse_t m_clkin; // CLKIN clock + clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock + clock_pulse_t m_e; // E clock (CLKIN / 8), falling edge of CLKIN trigger this clock +}; + +#endif diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp new file mode 100644 index 000000000..f37bb37ed --- /dev/null +++ b/src/engine/platform/sound/es550x/es550x_alu.cpp @@ -0,0 +1,116 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core + + see es550x.cpp for more info +*/ + +#include "es550x.hpp" + +// Accumulator functions +void es550x_shared_core::es550x_alu_t::reset() +{ + m_cr.reset(); + m_fc = 0; + m_start = 0; + m_end = 0; + m_accum = 0; + m_sample[0] = m_sample[1] = 0; +} + +bool es550x_shared_core::es550x_alu_t::busy() +{ + return ((!m_cr.stop0) && (!m_cr.stop1)); +} + +bool es550x_shared_core::es550x_alu_t::tick() +{ + if (m_cr.dir) + { + m_accum = bitfield(m_accum - m_fc, 0, m_total_bits); + return ((!m_cr.lei) && (m_accum < m_start)) ? true : false; + } + else + { + m_accum = bitfield(m_accum + m_fc, 0, m_total_bits); + return ((!m_cr.lei) && (m_accum > m_end)) ? true : false; + } +} + +void es550x_shared_core::es550x_alu_t::loop_exec() +{ + if (m_cr.irqe) // Set IRQ + m_cr.irq = 1; + + if (m_cr.dir) // Reverse playback + { + if (m_cr.lpe) // Loop enable + { + if (m_cr.ble) // Bidirectional + { + m_cr.dir = 0; + m_accum = m_start + (m_start - m_accum); + } + else// Normal + m_accum = (m_accum + m_start) - m_end; + } + else if (m_cr.ble && m_transwave) // m_transwave + { + m_cr.lpe = m_cr.ble = 0; + m_cr.lei = 1; // Loop end ignore + m_accum = (m_accum + m_start) - m_end; + } + else // Stop + m_cr.stop0 = 1; + } + else + { + if (m_cr.lpe) // Loop enable + { + if (m_cr.ble) // Bidirectional + { + m_cr.dir = 1; + m_accum = m_end - (m_end - m_accum); + } + else // Normal + m_accum = (m_accum - m_end) + m_start; + } + else if (m_cr.ble && m_transwave) // m_transwave + { + m_cr.lpe = m_cr.ble = 0; + m_cr.lei = 1; // Loop end ignore + m_accum = (m_accum - m_end) + m_start; + } + else // Stop + m_cr.stop0 = 1; + } +} + +s32 es550x_shared_core::es550x_alu_t::interpolation() +{ + // SF = S1 + ACCfr * (S2 - S1) + return m_sample[0] + ((bitfield(m_accum, std::min(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); +} + +u32 es550x_shared_core::es550x_alu_t::get_accum_integer() +{ + return bitfield(m_accum, m_fraction, m_integer); +} + +void es550x_shared_core::es550x_alu_t::irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index) +{ + const u8 prev = irqv.irqb; + if (m_cr.irq) + { + if (irqv.irqb) + { + irqv.set(index); + m_cr.irq = 0; + } + } + if (prev != irqv.irqb) + irq_update(intf, irqv); +} diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp new file mode 100644 index 000000000..8ef526ff3 --- /dev/null +++ b/src/engine/platform/sound/es550x/es550x_filter.cpp @@ -0,0 +1,70 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/LICENSE for more details + + Copyright holder(s): cam900 + Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core + + see es550x.cpp for more info +*/ + +#include "es550x.hpp" + +// Filter functions +void es550x_shared_core::es550x_filter_t::reset() +{ + m_lp = 0; + m_k2 = 0; + m_k1 = 0; + m_o1_1 = 0; + m_o2_1 = 0; + m_o2_2 = 0; + m_o3_1 = 0; + m_o3_2 = 0; + m_o4_1 = 0; +} + +void es550x_shared_core::es550x_filter_t::tick(s32 in) +{ + s32 coeff_k1 = s32(bitfield(m_k1,4,12)); // 12 MSB used + s32 coeff_k2 = s32(bitfield(m_k2,4,12)); // 12 MSB used + // Store previous filter data + m_o2_2 = m_o2_1; + m_o3_2 = m_o3_1; + + // First and second stage: LP/K1, LP/K1 Fixed + m_o1_1 = lp_exec(coeff_k1, in, m_o1_1); + m_o2_1 = lp_exec(coeff_k1, m_o1_1, m_o2_1); + switch (m_lp) + { + case 0: // LP3 = 0, LP4 = 0: HP/K2, HP/K2 + default: + m_o3_1 = hp_exec(coeff_k2, m_o2_1, m_o3_1, m_o2_2); + m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); + break; + case 1: // LP3 = 0, LP4 = 1: HP/K2, LP/K1 + m_o4_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); + m_o3_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); + break; + case 2: // LP3 = 1, LP4 = 0: LP/K2, LP/K2 + m_o3_1 = lp_exec(coeff_k2, m_o2_1, m_o3_1); + m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); + break; + case 3: // LP3 = 1, LP4 = 1: LP/K2, LP/K1 + m_o4_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); + m_o3_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); + break; + } +} + +s32 es550x_shared_core::es550x_filter_t::lp_exec(s32 coeff, s32 in, s32 prev_out) +{ + // Yn = K*(Xn - Yn-1) + Yn-1 + return ((coeff * (in - prev_out)) / 4096) + prev_out; +} + +s32 es550x_shared_core::es550x_filter_t::hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in) +{ + // Yn = Xn - Xn-1 + K*Yn-1 + return in - prev_in + ((coeff * prev_out) / 8192) * (prev_out / 2); +} diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 30be897be..e6e248f85 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -83,8 +83,8 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || dacPos>=s->samples) { + if (s->isLoopable()) { dacPos=s->loopStart; } else { dacSample=-1; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 7e887be80..4604438e7 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -96,8 +96,8 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (chan[16].pcm.pos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[16].pcm.pos>=s->loopEnd) || (chan[16].pcm.pos>=s->samples)) { + if (s->isLoopable()) { chan[16].pcm.pos=s->loopStart; } else { chan[16].pcm.sample=-1; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index b126deb6e..3aa208b79 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -77,8 +77,8 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (chan[i].dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].dacPos>=s->loopEnd) || (chan[i].dacPos>=s->samples)) { + if (s->isLoopable()) { chan[i].dacPos=s->loopStart; } else { chan[i].dacSample=-1; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index a1f5ea658..02340fce5 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -644,11 +644,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) { DivSample* s=parent->getSample(chan[c.chan].sample); immWrite(0x12,(s->offB>>8)&0xff); immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; + int end=((s->offB+s->lengthB+0xff)&~0xff)-1; immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && (s->loopStart>=0))?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -679,11 +679,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) { DivSample* s=parent->getSample(12*sampleBank+c.value%12); immWrite(0x12,(s->offB>>8)&0xff); immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; + int end=((s->offB+s->lengthB+0xff)&~0xff)-1; immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && (s->loopStart>=0))?0x90:0x80); // start/repeat chan[c.chan].baseFreq=(((unsigned int)s->rate)<<16)/(chipClock/144); chan[c.chan].freqChanged=true; } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 130eb29a2..04ec10aba 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -707,11 +707,11 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { DivSample* s=parent->getSample(chan[c.chan].sample); immWrite(0x12,(s->offB>>8)&0xff); immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; + int end=((s->offB+s->lengthB+0xff)&~0xff)-1; immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && (s->loopStart>=0))?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -742,11 +742,11 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { DivSample* s=parent->getSample(12*sampleBank+c.value%12); immWrite(0x12,(s->offB>>8)&0xff); immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; + int end=((s->offB+s->lengthB+0xff)&~0xff)-1; immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat + immWrite(0x10,((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && (s->loopStart>=0))?0x90:0x80); // start/repeat chan[c.chan].baseFreq=(((unsigned int)s->rate)<<16)/(chipClock/144); chan[c.chan].freqChanged=true; } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ea2213305..9c70a0bd2 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -511,6 +511,23 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe return false; } break; + case DIV_SYSTEM_ES5506: + switch (effect) { + case 0x10: // echo feedback + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_FEEDBACK,ch,effectVal)); + break; + case 0x11: // echo level + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); + break; + default: + if ((effect&0xf0)==0x30) { + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); + } else { + return false; + } + break; + } + break; default: return false; } @@ -1293,6 +1310,7 @@ void DivEngine::processRow(int i, bool afterDelay) { sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; break; } } @@ -1744,22 +1762,107 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (sPreview.pos>=s->samples) { samp_temp=0; } else { - samp_temp=s->data16[sPreview.pos++]; + samp_temp=s->data16[sPreview.pos]; + if (sPreview.dir) { + sPreview.pos--; + } else { + sPreview.pos++; + } } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); samp_prevSample=samp_temp; - if (sPreview.pos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - sPreview.pos=s->loopStart; + if (sPreview.dir) { + if (s->isLoopable() && ((int)sPreview.pos)loopStart) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOPMODE_FOWARD: + sPreview.dir=false; + sPreview.pos=s->loopStart+1; + break; + case DIV_SAMPLE_LOOPMODE_BACKWARD: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_PINGPONG: + sPreview.dir=false; + sPreview.pos=s->loopStart+1; + break; + case DIV_SAMPLE_LOOPMODE_ONESHOT: + default: + break; + } + } + } else { + if (s->isLoopable() && sPreview.pos>=s->loopEnd) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOPMODE_FOWARD: + sPreview.dir=false; + sPreview.pos=s->loopStart; + break; + case DIV_SAMPLE_LOOPMODE_BACKWARD: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_PINGPONG: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_ONESHOT: + default: + break; + } } } } - if (sPreview.pos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { - sPreview.pos=s->loopStart; - } else { + if (sPreview.dir) { + if (s->isLoopable() && ((int)sPreview.pos)loopStart) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOPMODE_FOWARD: + sPreview.dir=false; + sPreview.pos=s->loopStart+1; + break; + case DIV_SAMPLE_LOOPMODE_BACKWARD: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_PINGPONG: + sPreview.dir=false; + sPreview.pos=s->loopStart+1; + break; + case DIV_SAMPLE_LOOPMODE_ONESHOT: + default: + if (sPreview.pos<0) { + sPreview.sample=-1; + } + break; + } + } else if (sPreview.pos<0) { + sPreview.sample=-1; + } + } else { + if (s->isLoopable() && sPreview.pos>=s->loopEnd) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOPMODE_FOWARD: + sPreview.dir=false; + sPreview.pos=s->loopStart; + break; + case DIV_SAMPLE_LOOPMODE_BACKWARD: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_PINGPONG: + sPreview.dir=true; + sPreview.pos=s->loopEnd-1; + break; + case DIV_SAMPLE_LOOPMODE_ONESHOT: + default: + if (sPreview.pos>=s->samples) { + sPreview.sample=-1; + } + break; + } + } else if (sPreview.pos>=s->samples) { sPreview.sample=-1; } } diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index bd34daa5b..4be92b70a 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -36,6 +36,10 @@ DivSampleHistory::~DivSampleHistory() { if (data!=NULL) delete[] data; } +bool DivSample::isLoopable() { + return ((loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && (loopStart>=0 && loopStart<(int)samples) && loopEnd<=samples); +} + bool DivSample::save(const char* path) { SNDFILE* f; SF_INFO si; @@ -62,12 +66,12 @@ bool DivSample::save(const char* path) { inst.detune = 50 - (pitch % 100); inst.velocity_hi = 0x7f; inst.key_hi = 0x7f; - if(loopStart != -1) + if(isLoopable()) { inst.loop_count = 1; - inst.loops[0].mode = SF_LOOP_FORWARD; + inst.loops[0].mode = SF_LOOP_NONE+loopMode; inst.loops[0].start = loopStart; - inst.loops[0].end = samples; + inst.loops[0].end = loopEnd; } sf_command(f, SFC_SET_INSTRUMENT, &inst, sizeof(inst)); @@ -79,64 +83,64 @@ bool DivSample::save(const char* path) { } // 16-bit memory is padded to 512, to make things easier for ADPCM-A/B. -bool DivSample::initInternal(unsigned char d, int count) { +bool DivSample::initInternal(DivSampleDepth d, int count) { switch (d) { - case 0: // 1-bit + case DIV_SAMPLE_DEPTH_1BIT: // 1-bit if (data1!=NULL) delete[] data1; length1=(count+7)/8; data1=new unsigned char[length1]; memset(data1,0,length1); break; - case 1: // DPCM + case DIV_SAMPLE_DEPTH_1BIT_DPCM: // DPCM if (dataDPCM!=NULL) delete[] dataDPCM; lengthDPCM=(count+7)/8; dataDPCM=new unsigned char[lengthDPCM]; memset(dataDPCM,0,lengthDPCM); break; - case 4: // QSound ADPCM + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM if (dataQSoundA!=NULL) delete[] dataQSoundA; lengthQSoundA=(count+1)/2; dataQSoundA=new unsigned char[lengthQSoundA]; memset(dataQSoundA,0,lengthQSoundA); break; - case 5: // ADPCM-A + case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A if (dataA!=NULL) delete[] dataA; lengthA=(count+1)/2; dataA=new unsigned char[(lengthA+255)&(~0xff)]; memset(dataA,0,(lengthA+255)&(~0xff)); break; - case 6: // ADPCM-B + case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B if (dataB!=NULL) delete[] dataB; lengthB=(count+1)/2; dataB=new unsigned char[(lengthB+255)&(~0xff)]; memset(dataB,0,(lengthB+255)&(~0xff)); break; - case 7: // X68000 ADPCM + case DIV_SAMPLE_DEPTH_X68K_ADPCM: // X68000 ADPCM if (dataX68!=NULL) delete[] dataX68; lengthX68=(count+1)/2; dataX68=new unsigned char[lengthX68]; memset(dataX68,0,lengthX68); break; - case 8: // 8-bit + case DIV_SAMPLE_DEPTH_8BIT: // 8-bit if (data8!=NULL) delete[] data8; length8=count; // for padding X1-010 sample data8=new signed char[(count+4095)&(~0xfff)]; memset(data8,0,(count+4095)&(~0xfff)); break; - case 9: // BRR + case DIV_SAMPLE_DEPTH_BRR: // BRR if (dataBRR!=NULL) delete[] dataBRR; lengthBRR=9*((count+15)/16); dataBRR=new unsigned char[lengthBRR]; memset(dataBRR,0,lengthBRR); break; - case 10: // VOX + case DIV_SAMPLE_DEPTH_VOX: // VOX if (dataVOX!=NULL) delete[] dataVOX; lengthVOX=(count+1)/2; dataVOX=new unsigned char[lengthVOX]; memset(dataVOX,0,lengthVOX); break; - case 16: // 16-bit + case DIV_SAMPLE_DEPTH_16BIT: // 16-bit if (data16!=NULL) delete[] data16; length16=count*2; data16=new short[(count+511)&(~0x1ff)]; @@ -151,31 +155,34 @@ bool DivSample::initInternal(unsigned char d, int count) { bool DivSample::init(unsigned int count) { if (!initInternal(depth,count)) return false; samples=count; + if (loopEnd>samples) { + loopEnd=samples; + } return true; } bool DivSample::resize(unsigned int count) { - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); memcpy(data8,oldData8,MIN(count,samples)); delete[] oldData8; } else { - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); } samples=count; return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); memcpy(data16,oldData16,sizeof(short)*MIN(count,samples)); delete[] oldData16; } else { - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); } samples=count; return true; @@ -188,11 +195,11 @@ bool DivSample::strip(unsigned int begin, unsigned int end) { if (end>samples) end=samples; int count=samples-(end-begin); if (count<=0) return resize(0); - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); if (begin>0) { memcpy(data8,oldData8,begin); } @@ -206,11 +213,11 @@ bool DivSample::strip(unsigned int begin, unsigned int end) { } samples=count; return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); if (begin>0) { memcpy(data16,oldData16,sizeof(short)*begin); } @@ -232,11 +239,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) { int count=end-begin; if (count==0) return true; if (begin==0 && end==samples) return true; - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); memcpy(data8,oldData8+begin,count); delete[] oldData8; } else { @@ -245,11 +252,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) { } samples=count; return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); memcpy(data16,&(oldData16[begin]),sizeof(short)*count); delete[] oldData16; } else { @@ -264,11 +271,11 @@ bool DivSample::trim(unsigned int begin, unsigned int end) { bool DivSample::insert(unsigned int pos, unsigned int length) { unsigned int count=samples+length; - if (depth==8) { + if (depth==DIV_SAMPLE_DEPTH_8BIT) { if (data8!=NULL) { signed char* oldData8=data8; data8=NULL; - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); if (pos>0) { memcpy(data8,oldData8,pos); } @@ -277,15 +284,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { } delete[] oldData8; } else { - initInternal(8,count); + initInternal(DIV_SAMPLE_DEPTH_8BIT,count); } samples=count; return true; - } else if (depth==16) { + } else if (depth==DIV_SAMPLE_DEPTH_16BIT) { if (data16!=NULL) { short* oldData16=data16; data16=NULL; - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); if (pos>0) { memcpy(data16,oldData16,sizeof(short)*pos); } @@ -294,7 +301,7 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { } delete[] oldData16; } else { - initInternal(16,count); + initInternal(DIV_SAMPLE_DEPTH_16BIT,count); } samples=count; return true; @@ -307,15 +314,15 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { int finalCount=(double)samples*(r/(double)rate); \ signed char* oldData8=data8; \ short* oldData16=data16; \ - if (depth==16) { \ + if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ if (data16!=NULL) { \ data16=NULL; \ - initInternal(16,finalCount); \ + initInternal(DIV_SAMPLE_DEPTH_16BIT,finalCount); \ } \ - } else if (depth==8) { \ + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \ if (data8!=NULL) { \ data8=NULL; \ - initInternal(8,finalCount); \ + initInternal(DIV_SAMPLE_DEPTH_8BIT,finalCount); \ } \ } else { \ return false; \ @@ -323,19 +330,20 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { #define RESAMPLE_END \ if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \ + if (loopEnd>=0) loopEnd=(double)loopEnd*(r/(double)rate); \ centerRate=(int)((double)centerRate*(r/(double)rate)); \ rate=r; \ samples=finalCount; \ - if (depth==16) { \ + if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ delete[] oldData16; \ - } else if (depth==8) { \ + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \ delete[] oldData8; \ } bool DivSample::resampleNone(double r) { RESAMPLE_BEGIN; - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples) { @@ -344,7 +352,7 @@ bool DivSample::resampleNone(double r) { data16[i]=oldData16[pos]; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples) { @@ -366,10 +374,10 @@ bool DivSample::resampleLinear(double r) { unsigned int posInt=0; double factor=(double)rate/r; - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples)?0:oldData16[posInt]; - short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; + short s2=(posInt+1>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+1]; data16[i]=s1+(float)(s2-s1)*posFrac; @@ -379,10 +387,10 @@ bool DivSample::resampleLinear(double r) { posInt++; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples)?0:oldData8[posInt]; - short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; + short s2=(posInt+1>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+1]; data8[i]=s1+(float)(s2-s1)*posFrac; @@ -406,14 +414,14 @@ bool DivSample::resampleCubic(double r) { double factor=(double)rate/r; float* cubicTable=DivFilterTables::getCubicTable(); - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples)?0:oldData16[posInt]; - float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; - float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+2]; + float s2=(posInt+1>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+1]; + float s3=(posInt+2>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+2]; float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3]; if (result<-32768) result=-32768; @@ -426,14 +434,14 @@ bool DivSample::resampleCubic(double r) { posInt++; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples)?0:oldData8[posInt]; - float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; - float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+2]; + float s2=(posInt+1>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+1]; + float s3=(posInt+2>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+2]; float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3]; if (result<-128) result=-128; @@ -463,7 +471,7 @@ bool DivSample::resampleBlep(double r) { memset(s,0,16*sizeof(float)); - if (depth==16) { + if (depth==DIV_SAMPLE_DEPTH_16BIT) { memset(data16,0,finalCount*sizeof(short)); for (int i=0; i=samples)?0:oldData16[posInt]; } } - } else if (depth==8) { + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i>3]>>(i&7))&1)?0x7fff:-0x7fff; } break; - case 1: { // DPCM + case DIV_SAMPLE_DEPTH_1BIT_DPCM: { // DPCM int accum=0; for (unsigned int i=0; i>3]>>(i&7))&1)?1:-1; @@ -657,27 +665,27 @@ void DivSample::render() { } break; } - case 4: // QSound ADPCM + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: // QSound ADPCM bs_decode(dataQSoundA,data16,samples); break; - case 5: // ADPCM-A + case DIV_SAMPLE_DEPTH_ADPCM_A: // ADPCM-A yma_decode(dataA,data16,samples); break; - case 6: // ADPCM-B + case DIV_SAMPLE_DEPTH_ADPCM_B: // ADPCM-B ymb_decode(dataB,data16,samples); break; - case 7: // X6800 ADPCM + case DIV_SAMPLE_DEPTH_X68K_ADPCM: // X6800 ADPCM oki6258_decode(dataX68,data16,samples); break; - case 8: // 8-bit PCM + case DIV_SAMPLE_DEPTH_8BIT: // 8-bit PCM for (unsigned int i=0; i0) { data1[i>>3]|=1<<(i&7); } } } - if (depth!=1) { // DPCM - if (!initInternal(1,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_1BIT_DPCM) { // DPCM + if (!initInternal(DIV_SAMPLE_DEPTH_1BIT_DPCM,samples)) return; int accum=63; for (unsigned int i=0; i>9; @@ -709,84 +717,88 @@ void DivSample::render() { if (accum>127) accum=127; } } - if (depth!=4) { // QSound ADPCM - if (!initInternal(4,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_QSOUND_ADPCM) { // QSound ADPCM + if (!initInternal(DIV_SAMPLE_DEPTH_QSOUND_ADPCM,samples)) return; bs_encode(data16,dataQSoundA,samples); } // TODO: pad to 256. - if (depth!=5) { // ADPCM-A - if (!initInternal(5,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_ADPCM_A) { // ADPCM-A + if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_A,samples)) return; yma_encode(data16,dataA,(samples+511)&(~0x1ff)); } - if (depth!=6) { // ADPCM-B - if (!initInternal(6,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_ADPCM_B) { // ADPCM-B + if (!initInternal(DIV_SAMPLE_DEPTH_ADPCM_B,samples)) return; ymb_encode(data16,dataB,(samples+511)&(~0x1ff)); } - if (depth!=7) { // X68000 ADPCM - if (!initInternal(7,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_X68K_ADPCM) { // X68000 ADPCM + if (!initInternal(DIV_SAMPLE_DEPTH_X68K_ADPCM,samples)) return; oki6258_encode(data16,dataX68,samples); } - if (depth!=8) { // 8-bit PCM - if (!initInternal(8,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_8BIT) { // 8-bit PCM + if (!initInternal(DIV_SAMPLE_DEPTH_8BIT,samples)) return; for (unsigned int i=0; i>8; } } // TODO: BRR! - if (depth!=10) { // VOX - if (!initInternal(10,samples)) return; + if (depth!=DIV_SAMPLE_DEPTH_VOX) { // VOX + if (!initInternal(DIV_SAMPLE_DEPTH_VOX,samples)) return; oki_encode(data16,dataVOX,samples); } } void* DivSample::getCurBuf() { switch (depth) { - case 0: + case DIV_SAMPLE_DEPTH_1BIT: return data1; - case 1: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: return dataDPCM; - case 4: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: return dataQSoundA; - case 5: + case DIV_SAMPLE_DEPTH_ADPCM_A: return dataA; - case 6: + case DIV_SAMPLE_DEPTH_ADPCM_B: return dataB; - case 7: + case DIV_SAMPLE_DEPTH_X68K_ADPCM: return dataX68; - case 8: + case DIV_SAMPLE_DEPTH_8BIT: return data8; - case 9: + case DIV_SAMPLE_DEPTH_BRR: return dataBRR; - case 10: + case DIV_SAMPLE_DEPTH_VOX: return dataVOX; - case 16: + case DIV_SAMPLE_DEPTH_16BIT: return data16; + default: + break; } return NULL; } unsigned int DivSample::getCurBufLen() { switch (depth) { - case 0: + case DIV_SAMPLE_DEPTH_1BIT: return length1; - case 1: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: return lengthDPCM; - case 4: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: return lengthQSoundA; - case 5: + case DIV_SAMPLE_DEPTH_ADPCM_A: return lengthA; - case 6: + case DIV_SAMPLE_DEPTH_ADPCM_B: return lengthB; - case 7: + case DIV_SAMPLE_DEPTH_X68K_ADPCM: return lengthX68; - case 8: + case DIV_SAMPLE_DEPTH_8BIT: return length8; - case 9: + case DIV_SAMPLE_DEPTH_BRR: return lengthBRR; - case 10: + case DIV_SAMPLE_DEPTH_VOX: return lengthVOX; - case 16: + case DIV_SAMPLE_DEPTH_16BIT: return length16; + default: + break; } return 0; } @@ -801,9 +813,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); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loopMode); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart); + h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loopMode); } if (!doNotPush) { while (!redoHist.empty()) { @@ -833,7 +845,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { } \ rate=h->rate; \ centerRate=h->centerRate; \ - loopStart=h->loopStart; + loopStart=h->loopStart; \ + loopEnd=h->loopEnd; \ + loopMode=h->loopMode; int DivSample::undo() { diff --git a/src/engine/sample.h b/src/engine/sample.h index ae0c06dae..ff3e2f7b4 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -17,6 +17,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#ifndef _SAMPLE_H +#define _SAMPLE_H + +#pragma once + #include "../ta-utils.h" #include @@ -26,16 +31,41 @@ enum DivResampleFilters { DIV_RESAMPLE_CUBIC, DIV_RESAMPLE_BLEP, DIV_RESAMPLE_SINC, - DIV_RESAMPLE_BEST + DIV_RESAMPLE_BEST, + DIV_RESAMPLE_MAX // for identify boundary +}; + +enum DivSampleDepth: unsigned char { + DIV_SAMPLE_DEPTH_1BIT=0, + DIV_SAMPLE_DEPTH_1BIT_DPCM=1, + DIV_SAMPLE_DEPTH_QSOUND_ADPCM=4, + DIV_SAMPLE_DEPTH_ADPCM_A=5, + DIV_SAMPLE_DEPTH_ADPCM_B=6, + DIV_SAMPLE_DEPTH_X68K_ADPCM=7, + DIV_SAMPLE_DEPTH_8BIT=8, + DIV_SAMPLE_DEPTH_BRR=9, + DIV_SAMPLE_DEPTH_VOX=10, + DIV_SAMPLE_DEPTH_16BIT=16, + DIV_SAMPLE_DEPTH_MAX // for identify boundary +}; + +enum DivSampleLoopMode: unsigned char { + DIV_SAMPLE_LOOPMODE_ONESHOT=0, + DIV_SAMPLE_LOOPMODE_FOWARD, + DIV_SAMPLE_LOOPMODE_BACKWARD, + DIV_SAMPLE_LOOPMODE_PINGPONG, + DIV_SAMPLE_LOOPMODE_MAX // for identify boundary }; struct DivSampleHistory { unsigned char* data; unsigned int length, samples; - unsigned char depth; + DivSampleDepth depth; int rate, centerRate, loopStart; + unsigned int loopEnd; + DivSampleLoopMode loopMode; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, unsigned char de, int r, int cr, int ls): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, unsigned int le, DivSampleLoopMode lm): data((unsigned char*)d), length(l), samples(s), @@ -43,8 +73,10 @@ struct DivSampleHistory { rate(r), centerRate(cr), loopStart(ls), + loopEnd(le), + loopMode(lm), hasSample(true) {} - DivSampleHistory(unsigned char de, int r, int cr, int ls): + DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, unsigned int le, DivSampleLoopMode lm): data(NULL), length(0), samples(0), @@ -52,6 +84,8 @@ struct DivSampleHistory { rate(r), centerRate(cr), loopStart(ls), + loopEnd(le), + loopMode(lm), hasSample(false) {} ~DivSampleHistory(); }; @@ -59,6 +93,13 @@ struct DivSampleHistory { struct DivSample { String name; int rate, centerRate, loopStart, loopOffP; + unsigned int loopEnd; + // valid values are: + // - 0: One Shot (Loop disable) + // - 1: Foward loop + // - 2: Backward loop + // - 3: Pingpong loop + DivSampleLoopMode loopMode; // valid values are: // - 0: ZX Spectrum overlay drum (1-bit) // - 1: 1-bit NES DPCM (1-bit) @@ -70,7 +111,7 @@ struct DivSample { // - 9: BRR (SNES) // - 10: VOX // - 16: 16-bit PCM - unsigned char depth; + DivSampleDepth depth; // these are the new data structures. signed char* data8; // 8 @@ -86,7 +127,7 @@ struct DivSample { unsigned int length8, length16, length1, lengthDPCM, lengthQSoundA, lengthA, lengthB, lengthX68, lengthBRR, lengthVOX; unsigned int off8, off16, off1, offDPCM, offQSoundA, offA, offB, offX68, offBRR, offVOX; - unsigned int offSegaPCM, offQSound, offX1_010; + unsigned int offSegaPCM, offQSound, offX1_010, offES5506; unsigned int samples; @@ -102,6 +143,12 @@ struct DivSample { bool resampleBlep(double rate); bool resampleSinc(double rate); + /** + * check if sample is loopable. + * @return whether it was loopable. + */ + bool isLoopable(); + /** * save this sample to a file. * @param path a path. @@ -116,7 +163,7 @@ struct DivSample { * @param count number of samples. * @return whether it was successful. */ - bool initInternal(unsigned char d, int count); + bool initInternal(DivSampleDepth d, int count); /** * initialize sample data. make sure you have set `depth` before doing so. @@ -211,9 +258,11 @@ struct DivSample { name(""), rate(32000), centerRate(8363), - loopStart(-1), + loopStart(0), loopOffP(0), - depth(16), + loopEnd(~0), + loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT), + depth(DIV_SAMPLE_DEPTH_16BIT), data8(NULL), data16(NULL), data1(NULL), @@ -250,3 +299,5 @@ struct DivSample { samples(0) {} ~DivSample(); }; + +#endif diff --git a/src/engine/song.h b/src/engine/song.h index 6cda7c533..9f223d002 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -95,7 +95,8 @@ enum DivSystem { DIV_SYSTEM_YM2610B_EXT, DIV_SYSTEM_SEGAPCM_COMPAT, DIV_SYSTEM_X1_010, - DIV_SYSTEM_BUBSYS_WSG + DIV_SYSTEM_BUBSYS_WSG, + DIV_SYSTEM_ES5506 }; struct DivSong { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 084504fe1..f6fd36ef7 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -140,6 +140,8 @@ DivSystem DivEngine::systemFromFileFur(unsigned char val) { return DIV_SYSTEM_BUBSYS_WSG; case 0xb0: return DIV_SYSTEM_X1_010; + case 0xb1: + return DIV_SYSTEM_ES5506; case 0xde: return DIV_SYSTEM_YM2610B_EXT; case 0xe0: @@ -270,6 +272,8 @@ unsigned char DivEngine::systemToFileFur(DivSystem val) { return 0xad; case DIV_SYSTEM_X1_010: return 0xb0; + case DIV_SYSTEM_ES5506: + return 0xb1; case DIV_SYSTEM_YM2610B_EXT: return 0xde; case DIV_SYSTEM_QSOUND: @@ -475,6 +479,8 @@ int DivEngine::getChannelCount(DivSystem sys) { return 17; case DIV_SYSTEM_BUBSYS_WSG: return 2; + case DIV_SYSTEM_ES5506: + return 32; } return 0; } @@ -760,6 +766,8 @@ const char* DivEngine::getSystemName(DivSystem sys) { return "Seta/Allumer X1-010"; case DIV_SYSTEM_BUBSYS_WSG: return "Konami Bubble System WSG"; + case DIV_SYSTEM_ES5506: + return "Ensoniq ES5506 OTTO"; } return "Unknown"; } @@ -892,6 +900,8 @@ const char* DivEngine::getSystemChips(DivSystem sys) { return "Seta/Allumer X1-010"; case DIV_SYSTEM_BUBSYS_WSG: return "Konami Bubble System WSG"; + case DIV_SYSTEM_ES5506: + return "Ensoniq ES5506"; } return "Unknown"; } @@ -1002,7 +1012,7 @@ const char* chanNames[40][32]={ {"FM 1", "FM 2", "FM 3", "PSG 1", "PSG 2", "PSG 3"}, // OPN {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, // PC-98 {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"}, // OPL3 - {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28"}, // MultiPCM + {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, // MultiPCM/ES5506 {"Square"}, // PC Speaker/Pokémon Mini {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Noise"}, // Virtual Boy/SCC {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, // YM2610B @@ -1045,7 +1055,7 @@ const char* chanShortNames[38][32]={ {"F1", "F2", "F3", "S1", "S2", "S3"}, // OPN {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, // PC-98 {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"}, // OPL3 - {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"}, // MultiPCM + {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, // MultiPCM/ES5506 {"SQ"}, // PC Speaker/Pokémon Mini {"CH1", "CH2", "CH3", "CH4", "CH5", "NO"}, // Virtual Boy/SCC {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, // YM2610B @@ -1086,7 +1096,7 @@ const int chanTypes[41][32]={ {0, 0, 0, 1, 1, 1}, // OPN {0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4}, // PC-98 {5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0}, // OPL3 - {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // MultiPCM/QSound + {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // MultiPCM/QSound/ES5506 {1}, // PC Speaker/Pokémon Mini {3, 3, 3, 3, 3, 2}, // Virtual Boy/SCC {0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4}, // YM2610B @@ -1101,7 +1111,7 @@ const int chanTypes[41][32]={ {3, 4, 3, 2}, // Swan }; -const DivInstrumentType chanPrefType[47][28]={ +const DivInstrumentType chanPrefType[48][32]={ {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, // YMU759 {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, // Genesis {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, // Genesis (extended channel 3) @@ -1149,6 +1159,7 @@ const DivInstrumentType chanPrefType[47][28]={ {DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_AMIGA}, // VERA {DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010}, // X1-010 {DIV_INS_SCC, DIV_INS_SCC}, // Bubble System WSG + {DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506}, // ES5506 }; const char* DivEngine::getChannelName(int chan) { @@ -1258,6 +1269,7 @@ const char* DivEngine::getChannelName(int chan) { case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: case DIV_SYSTEM_X1_010: + case DIV_SYSTEM_ES5506: return chanNames[28][dispatchChanOfChan[chan]]; break; case DIV_SYSTEM_PCSPKR: @@ -1403,6 +1415,7 @@ const char* DivEngine::getChannelShortName(int chan) { case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: case DIV_SYSTEM_X1_010: + case DIV_SYSTEM_ES5506: return chanShortNames[28][dispatchChanOfChan[chan]]; break; case DIV_SYSTEM_PCSPKR: @@ -1544,6 +1557,7 @@ int DivEngine::getChannelType(int chan) { case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: case DIV_SYSTEM_QSOUND: + case DIV_SYSTEM_ES5506: return chanTypes[28][dispatchChanOfChan[chan]]; break; case DIV_SYSTEM_PCSPKR: @@ -1748,6 +1762,9 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) { case DIV_SYSTEM_BUBSYS_WSG: return chanPrefType[46][dispatchChanOfChan[chan]]; break; + case DIV_SYSTEM_ES5506: + return chanPrefType[47][dispatchChanOfChan[chan]]; + break; } return DIV_INS_FM; } diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index b20813489..781435e23 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -317,6 +317,40 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(0xd6+i); } break; + case DIV_SYSTEM_ES5506: + for (int i=0; i<32; i++) { + for (int b=0; b<4; b++) { + w->writeC(0xbe); + w->writeC((0xf<<2)+b); + w->writeC(i); + } + unsigned int init_cr=0x0303; + for (int b=0; b<4; b++) { + w->writeC(0xbe); + w->writeC(b); + w->writeC(init_cr>>(24-(b<<3))); + } + for (int r=1; r<11; r++) { + for (int b=0; b<4; b++) { + w->writeC(0xbe); + w->writeC((r<<2)+b); + w->writeC(((r==7 || r==9) && b&2)?0xff:0); + } + } + for (int b=0; b<4; b++) { + w->writeC(0xbe); + w->writeC((0xf<<2)+b); + w->writeC(0x20|i); + } + for (int r=1; r<10; r++) { + for (int b=0; b<4; b++) { + w->writeC(0xbe); + w->writeC((r<<2)+b); + w->writeC(0); + } + } + } + break; // TODO: it's 3:35am case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL_DRUMS: @@ -425,7 +459,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeS(write.val); // sample number w->writeC((sample->loopStart==0)); // flags if (sample->loopStart>0) { - loopTimer[streamID]=sample->length8; + loopTimer[streamID]=(double)sample->loopEnd; loopSample[streamID]=write.val; } } @@ -571,6 +605,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(write.val&0xff); } break; + case DIV_SYSTEM_ES5506: + w->writeC(0xbe); + w->writeC(write.addr&0xff); + w->writeC(write.val&0xff); + break; case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL_DRUMS: w->writeC(0x0b|baseAddr1); @@ -717,6 +756,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { bool writeSegaPCM=false; bool writeX1010=false; bool writeQSound=false; + bool writeES5506=false; for (int i=0; ichipClock; + willExport[i]=true; + writeES5506=true; + } else if (!(hasES5505&0x40000000)) { + isSecond[i]=true; + willExport[i]=false; + hasES5505|=0xc0000000; + howManyChips++; + } + break; case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL_DRUMS: if (!hasOPL) { @@ -1120,7 +1173,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { w->writeI(hasES5503); w->writeI(hasES5505); w->writeC(0); // 5503 chans - w->writeC(0); // 5505 chans + w->writeC(hasES5505?1:0); // 5505 chans w->writeC(0); // C352 clock divider w->writeC(0); // reserved w->writeI(hasX1); @@ -1215,8 +1268,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { unsigned int readPos=0; if (alignedSize>65536) alignedSize=65536; for (unsigned int j=0; j=sample->length8) { - if (sample->loopStart>=0 && sample->loopStart<(int)sample->length8) { + if ((sample->loopMode && readPos>=sample->loopEnd) || readPos>=sample->length8) { + if (sample->isLoopable()) { readPos=sample->loopStart; pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); } else { @@ -1288,6 +1341,16 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { w->write(x1_010Mem,x1_010MemLen); } + if (writeES5506 && es5506MemLen>0) { + w->writeC(0x67); + w->writeC(0x66); + w->writeC(0x8F); + w->writeI(es5506MemLen+8); + w->writeI(es5506MemLen); + w->writeI(0); + w->write(es5506Mem,es5506MemLen); + } + // initialize streams int streamID=0; for (int i=0; iloopStart<(int)sample->length8) { + if (sample->loopStart<(int)sample->loopEnd) { w->writeC(0x93); w->writeC(nextToTouch); w->writeI(sample->off8+sample->loopStart); w->writeC(0x81); - w->writeI(sample->length8-sample->loopStart); + w->writeI(sample->loopEnd-sample->loopStart); } } loopSample[nextToTouch]=-1; diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 8a02c40e3..cdc3157b6 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -184,6 +184,10 @@ void FurnaceGUI::drawInsList() { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_X1_010]); name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_ES5506: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ES5506]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; default: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 808d57a0c..87040bc2d 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -578,6 +578,8 @@ void FurnaceGUI::doAction(int what) { sample->centerRate=prevSample->centerRate; sample->name=prevSample->name; sample->loopStart=prevSample->loopStart; + sample->loopEnd=prevSample->loopEnd; + sample->loopMode=prevSample->loopMode; sample->depth=prevSample->depth; if (sample->init(prevSample->samples)) { if (prevSample->getCurBuf()!=NULL) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 67d084a47..84c300770 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -144,6 +144,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_VERA, GUI_COLOR_INSTR_X1_010, GUI_COLOR_INSTR_VRC6_SAW, + GUI_COLOR_INSTR_ES5506, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 10b004421..64135cdba 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -106,10 +106,11 @@ const char* insTypes[DIV_INS_MAX]={ "Atari Lynx", "VERA", "X1-010", - "VRC6 (saw)" + "VRC6 (saw)", + "ES5506" }; -const char* sampleDepths[17]={ +const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={ "1-bit PCM", "1-bit DPCM", NULL, @@ -129,7 +130,7 @@ const char* sampleDepths[17]={ "16-bit PCM" }; -const char* resampleStrats[]={ +const char* resampleStrats[DIV_RESAMPLE_MAX]={ "none", "linear", "cubic spline", @@ -138,6 +139,13 @@ const char* resampleStrats[]={ "best possible" }; +const char* loopMode[DIV_SAMPLE_LOOPMODE_MAX]={ + "Disable", + "Foward", + "Backward", + "Pingpong" +}; + #define D FurnaceGUIActionDef #define NOT_AN_ACTION -1 @@ -449,6 +457,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_VERA,"",ImVec4(0.4f,0.6f,1.0f,1.0f)), D(GUI_COLOR_INSTR_X1_010,"",ImVec4(0.3f,0.5f,1.0f,1.0f)), D(GUI_COLOR_INSTR_VRC6_SAW,"",ImVec4(0.8f,0.3f,0.0f,1.0f)), + D(GUI_COLOR_INSTR_ES5506,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), @@ -552,6 +561,7 @@ const int availableSystems[]={ DIV_SYSTEM_VRC6, DIV_SYSTEM_FDS, DIV_SYSTEM_MMC5, + DIV_SYSTEM_ES5506, 0 // don't remove this last one! }; diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index 93dd143a0..60c16d5ec 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -40,8 +40,9 @@ extern const char* noteNames[180]; extern const char* noteNamesG[180]; extern const char* pitchLabel[11]; extern const char* insTypes[]; -extern const char* sampleDepths[17]; +extern const char* sampleDepths[]; extern const char* resampleStrats[]; +extern const char* loopMode[]; extern const int availableSystems[]; extern const FurnaceGUIActionDef guiActions[]; extern const FurnaceGUIColorDef guiColors[]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 50f93de2e..2b327d339 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -175,6 +175,10 @@ const char* n163UpdateBits[8]={ "now", "every waveform changed", NULL }; +const char* es5506FilterModes[4]={ + "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", +}; + const char* oneBit[2]={ "on", NULL }; @@ -2319,7 +2323,7 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Absolute Duty Macro",&ins->c64.dutyIsAbs)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA) if (ImGui::BeginTabItem("Amiga/Sample")) { + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("Amiga/Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { sName="none selected"; @@ -2368,32 +2372,32 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i]<0 || ins->amiga.noteMap[i]>=e->song.sampleLen) { + if (ins->amiga.noteMap[i].ind<0 || ins->amiga.noteMap[i].ind>=e->song.sampleLen) { sName="-- empty --"; - ins->amiga.noteMap[i]=-1; + ins->amiga.noteMap[i].ind=-1; } else { - sName=e->song.sample[ins->amiga.noteMap[i]]->name; + sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SM",sName.c_str())) { String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i]==-1)) { PARAMETER - ins->amiga.noteMap[i]=-1; + if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER + ins->amiga.noteMap[i].ind=-1; } for (int j=0; jsong.sampleLen; j++) { id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i]==j)) { PARAMETER - ins->amiga.noteMap[i]=j; - if (ins->amiga.noteFreq[i]<=0) ins->amiga.noteFreq[i]=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].ind==j)) { PARAMETER + ins->amiga.noteMap[i].ind=j; + if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); } } ImGui::EndCombo(); } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SF",&ins->amiga.noteFreq[i],50,500)) { PARAMETER - if (ins->amiga.noteFreq[i]<0) ins->amiga.noteFreq[i]=0; - if (ins->amiga.noteFreq[i]>262144) ins->amiga.noteFreq[i]=262144; + if (ImGui::InputInt("##SF",&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER + if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; + if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; } ImGui::PopID(); } @@ -2468,6 +2472,48 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) { + if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + // volume + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Left volume",ImGuiDataType_S32,&ins->es5506.lVol,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Right volume",ImGuiDataType_S32,&ins->es5506.rVol,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + // filter + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2",ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + // envelope + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Envelope count",ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Left Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Right Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("K1 Ramp Slowdown",&ins->es5506.envelope.k1Slow); + ImGui::TableNextColumn(); + ImGui::Checkbox("K2 Ramp Slowdown",&ins->es5506.envelope.k2Slow); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || ins->type==DIV_INS_X1_010 || @@ -2611,6 +2657,9 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FDS) { volMax=32; } + if (ins->type==DIV_INS_ES5506) { + volMax=65535; + } bool arpMode=ins->std.arpMacro.mode; @@ -2665,6 +2714,10 @@ void FurnaceGUI::drawInsEdit() { dutyLabel="Duty"; dutyMax=7; } + if (ins->type==DIV_INS_ES5506) { + dutyLabel="Filter Mode"; + dutyMax=3; + } bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->c64.dutyIsAbs); const char* waveLabel="Waveform"; @@ -2679,6 +2732,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SAA1099) waveMax=2; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; + if (ins->type==DIV_INS_ES5506) waveMax=255; if (ins->type==DIV_INS_PET) { waveMax=8; bitMode=true; diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 9c7f53b94..93829e356 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -30,6 +30,9 @@ const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; const int _TWO_HUNDRED_FIFTY_FIVE=255; +const int _FIVE_HUNDRED_ELEVEN=511; const int _TWO_THOUSAND_FORTY_SEVEN=2047; const int _FOUR_THOUSAND_NINETY_FIVE=4095; +const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE=65535; const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127; +const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT=-128; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index c6b13b9af..6ff97e57e 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -32,6 +32,9 @@ extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; extern const int _ONE_HUNDRED_TWENTY_SEVEN; extern const int _TWO_HUNDRED_FIFTY_FIVE; +extern const int _FIVE_HUNDRED_ELEVEN; extern const int _TWO_THOUSAND_FORTY_SEVEN; extern const int _FOUR_THOUSAND_NINETY_FIVE; +extern const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE; extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN; +extern const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5dd3b693d..1c9b655b3 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -178,6 +178,12 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Ensoniq ES5506", { + DIV_SYSTEM_ES5506, 64, 0, 31, + 0 + } + )); sysCategories.push_back(cat); cat=FurnaceGUISysCategory("Game consoles"); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 9919c069f..05d6f2ba6 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -41,7 +41,7 @@ void FurnaceGUI::drawSampleEdit() { } else { DivSample* sample=e->song.sample[curSample]; String sampleType="Invalid"; - if (sample->depth<17) { + if (sample->depthdepth]!=NULL) { sampleType=sampleDepths[sample->depth]; } @@ -61,11 +61,11 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { - for (int i=0; i<17; i++) { + for (int i=0; iprepareUndo(true); - sample->depth=i; + sample->depth=DivSampleDepth(i); e->renderSamplesP(); updateSampleTex=true; MARK_MODIFIED; @@ -93,22 +93,54 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::TableNextColumn(); - bool doLoop=(sample->loopStart>=0); - if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED - if (doLoop) { + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + int mode=(int)sample->loopMode; + if (ImGui::Combo("##LoopMode",&mode,loopMode,DIV_SAMPLE_LOOPMODE_MAX,DIV_SAMPLE_LOOPMODE_MAX)) { MARK_MODIFIED + if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { sample->loopStart=0; - } else { - sample->loopStart=-1; } + if (sample->loopEnd>sample->samples) { + sample->loopEnd=sample->samples; + } + sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Length: %d",sample->samples); + bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { + ImGui::TableNextColumn(); + ImGui::Text("Loop start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED + if (ImGui::InputInt("##LoopStart",&sample->loopStart,1,10)) { MARK_MODIFIED if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { sample->loopStart=0; } + if (sample->loopStart>=(int)sample->loopEnd) { + sample->loopStart=sample->loopEnd; + } + updateSampleTex=true; + } + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + int end=(int)sample->loopEnd; + if (ImGui::InputInt("##LoopEnd",&end,1,10)) { MARK_MODIFIED + if (end<0) { + end=0; + } + if (endloopStart) { + end=sample->loopStart; + } + if (end>sample->samples) { + end=sample->samples; + } + sample->loopEnd=end; updateSampleTex=true; } } @@ -123,7 +155,7 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { @@ -275,14 +307,14 @@ void FurnaceGUI::drawSampleEdit() { SAMPLE_OP_BEGIN; float vol=amplifyVol/100.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*vol; if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*vol; if (val<-128) val=-128; @@ -466,7 +498,7 @@ void FurnaceGUI::drawSampleEdit() { double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; irate))*M_PI); @@ -482,7 +514,7 @@ void FurnaceGUI::drawSampleEdit() { if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; irate))*M_PI); @@ -574,11 +606,11 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo("##SampleType",sampleType.c_str())) { - for (int i=0; i<17; i++) { + for (int i=0; iprepareUndo(true); - sample->depth=i; + sample->depth=DivSampleDepth(i); e->renderSamplesP(); updateSampleTex=true; MARK_MODIFIED; @@ -607,22 +639,55 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::TableNextColumn(); - bool doLoop=(sample->loopStart>=0); - if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED - if (doLoop) { + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + int mode=(int)sample->loopMode; + if (ImGui::Combo("##LoopMode",&mode,loopMode,DIV_SAMPLE_LOOPMODE_MAX,DIV_SAMPLE_LOOPMODE_MAX)) { MARK_MODIFIED + if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { sample->loopStart=0; - } else { - sample->loopStart=-1; } + if (sample->loopEnd>sample->samples) { + sample->loopEnd=sample->samples; + } + sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Length: %d",sample->samples); + bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Loop start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED + if (ImGui::InputInt("##LoopStart",&sample->loopStart,1,10)) { MARK_MODIFIED if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { sample->loopStart=0; } + if (sample->loopStart>=(int)sample->loopEnd) { + sample->loopStart=loopEnd; + } + updateSampleTex=true; + } + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + int end=(int)sample->loopEnd; + if (ImGui::InputInt("##LoopEnd",&end,1,10)) { MARK_MODIFIED + if (end<0) { + end=0; + } + if (endloopStart) { + end=sample->loopStart; + } + if (end>sample->samples) { + end=sample->samples; + } + sample->loopEnd=end; updateSampleTex=true; } } @@ -637,7 +702,7 @@ void FurnaceGUI::drawSampleEdit() { */ ImGui::Separator(); - ImGui::BeginDisabled(sample->depth!=8 && sample->depth!=16); + ImGui::BeginDisabled(sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(!sampleDragMode)); if (ImGui::Button(ICON_FA_I_CURSOR "##SSelect")) { @@ -820,7 +885,7 @@ void FurnaceGUI::drawSampleEdit() { double power=(sampleFilterCutStart>sampleFilterCutEnd)?0.5:2.0; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; irate))*M_PI); @@ -836,7 +901,7 @@ void FurnaceGUI::drawSampleEdit() { if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; irate))*M_PI); @@ -890,14 +955,14 @@ void FurnaceGUI::drawSampleEdit() { SAMPLE_OP_BEGIN; float vol=amplifyVol/100.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*vol; if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*vol; if (val<-128) val=-128; @@ -1137,7 +1202,8 @@ void FurnaceGUI::drawSampleEdit() { ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25)); for (int i=0; iloopStart>=0 && sample->loopStart<(int)sample->samples && ((j+samplePos)*sampleZoom)>sample->loopStart) { + int scaledPos=samplePos+(j*sampleZoom); + if (sample->isLoopable() && ((scaledPos>=sample->loopStart) && (scaledPosloopEnd))) { data[i*availX+j]=bgColorLoop; } else { data[i*availX+j]=bgColor; @@ -1157,7 +1223,7 @@ void FurnaceGUI::drawSampleEdit() { if (xCoarse>=sample->samples) break; int y1, y2; int totalAdvance=0; - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { y1=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; } else { y1=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; @@ -1170,7 +1236,7 @@ void FurnaceGUI::drawSampleEdit() { totalAdvance+=xAdvanceCoarse; if (xCoarse>=sample->samples) break; do { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { y2=((unsigned char)sample->data8[xCoarse]^0x80)*availY/256; } else { y2=((unsigned short)sample->data16[xCoarse]^0x8000)*availY/65536; @@ -1208,11 +1274,11 @@ void FurnaceGUI::drawSampleEdit() { sampleSelStart=0; sampleSelEnd=sample->samples; } else { - if (sample->samples>0 && (sample->depth==16 || sample->depth==8)) { + if (sample->samples>0 && (sample->depth==DIV_SAMPLE_DEPTH_16BIT || sample->depth==DIV_SAMPLE_DEPTH_8BIT)) { sampleDragStart=rectMin; sampleDragAreaSize=rectSize; - sampleDrag16=(sample->depth==16); - sampleDragTarget=(sample->depth==16)?((void*)sample->data16):((void*)sample->data8); + sampleDrag16=(sample->depth==DIV_SAMPLE_DEPTH_16BIT); + sampleDragTarget=(sample->depth==DIV_SAMPLE_DEPTH_16BIT)?((void*)sample->data16):((void*)sample->data8); sampleDragLen=sample->samples; sampleDragActive=true; sampleSelStart=-1; @@ -1277,7 +1343,7 @@ void FurnaceGUI::drawSampleEdit() { posX=samplePos+pos.x*sampleZoom; if (posX>(int)sample->samples) posX=-1; } - posY=(0.5-pos.y/rectSize.y)*((sample->depth==8)?255:32767); + posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:32767); if (posX>=0) { statusBar+=fmt::sprintf(" | (%d, %d)",posX,posY); } @@ -1325,7 +1391,7 @@ void FurnaceGUI::drawSampleEdit() { } } - if (sample->depth!=8 && sample->depth!=16) { + if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { statusBar="Non-8/16-bit samples cannot be edited without prior conversion."; } diff --git a/src/gui/stats.cpp b/src/gui/stats.cpp index 274be2eda..ed8cbab52 100644 --- a/src/gui/stats.cpp +++ b/src/gui/stats.cpp @@ -32,6 +32,7 @@ void FurnaceGUI::drawStats() { String adpcmBUsage=fmt::sprintf("%d/16384KB",e->adpcmBMemLen/1024); String qsoundUsage=fmt::sprintf("%d/16384KB",e->qsoundMemLen/1024); String x1_010Usage=fmt::sprintf("%d/1024KB",e->x1_010MemLen/1024); + String es5506Usage=fmt::sprintf("%d/16384KB",e->es5506MemLen/1024); ImGui::Text("ADPCM-A"); ImGui::SameLine(); ImGui::ProgressBar(((float)e->adpcmAMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmAUsage.c_str()); @@ -44,6 +45,9 @@ void FurnaceGUI::drawStats() { ImGui::Text("X1-010"); ImGui::SameLine(); ImGui::ProgressBar(((float)e->x1_010MemLen)/1048576.0f,ImVec2(-FLT_MIN,0),x1_010Usage.c_str()); + ImGui::Text("ES5506"); + ImGui::SameLine(); + ImGui::ProgressBar(((float)e->es5506MemLen)/16777216.0f,ImVec2(-FLT_MIN,0),es5506Usage.c_str()); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_STATS; ImGui::End(); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 40cc67a35..d19dc7d5c 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -366,7 +366,7 @@ void FurnaceGUI::drawSysConf(int i) { } ImGui::Text("Initial channel limit:"); int initialChannelLimit=((flags>>4)&7)+1; - if (CWSliderInt("##InitialChannelLimit",&initialChannelLimit,1,8)) { + if (CWSliderInt("##N163_InitialChannelLimit",&initialChannelLimit,1,8)) { if (initialChannelLimit<1) initialChannelLimit=1; if (initialChannelLimit>8) initialChannelLimit=8; e->setSysFlags(i,(flags & ~(7 << 4)) | (((initialChannelLimit-1) & 7) << 4),restart); @@ -379,6 +379,17 @@ void FurnaceGUI::drawSysConf(int i) { } break; } + case DIV_SYSTEM_ES5506: { + ImGui::Text("Initial channel limit:"); + int initialChannelLimit=(flags&31)+1; + if (CWSliderInt("##OTTO_InitialChannelLimit",&initialChannelLimit,5,32)) { + if (initialChannelLimit<5) initialChannelLimit=5; + if (initialChannelLimit>32) initialChannelLimit=32; + e->setSysFlags(i,(flags & ~31) | ((initialChannelLimit-1) & 31),restart); + updateWindowTitle(); + } rightClickable + break; + } case DIV_SYSTEM_GB: case DIV_SYSTEM_SWAN: case DIV_SYSTEM_VERA: From 7fbd239b8572a932db504bee1205862de43ae02e Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 27 Apr 2022 00:47:01 +0900 Subject: [PATCH 02/74] emulation core related fix, reversed loop and volume --- src/engine/platform/es5506.cpp | 2 +- src/engine/platform/sound/es550x/es5506.cpp | 6 +++--- src/engine/platform/sound/es550x/es550x.hpp | 2 +- src/engine/platform/sound/es550x/es550x_alu.cpp | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 66e60d420..c94fdf416 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -217,7 +217,7 @@ void DivPlatformES5506::e(bool state) if ((irqv&0x80)==0) { unsigned char ch=irqv&0x1f; if (chan[ch].isReverseLoop) { // Reversed loop - pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0040:0x0000)|0x08,0x78); + pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); chan[ch].isReverseLoop=false; } } diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 1bbee0e17..d1ac89bb0 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -261,8 +261,8 @@ void es5506_core::voice_t::tick(u8 voice) if (!m_mute) { // Send to output - m_ch.m_left = volume_calc(sign_ext(m_filter.m_o4_1, 16), m_lvol); - m_ch.m_right = volume_calc(sign_ext(m_filter.m_o4_1, 16), m_rvol); + m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); + m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); } // ALU execute @@ -307,7 +307,7 @@ s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in) { u8 exponent = bitfield(volume, 12, 4); u8 mantissa = bitfield(volume, 4, 8); - return (in * s32(0x100 | mantissa)) >> (20 - exponent); + return (in * s32(0x100 | mantissa)) >> (19 - exponent); } void es5506_core::reset() diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index c92c0db2e..eb3eaf255 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -42,7 +42,7 @@ namespace es550x // std::clamp is only for C++17 or later; I use my own code template T clamp(T in, T min, T max) { - return (in > max) ? max : ((in < min) ? min : in); + return (in < max) ? max : ((in > min) ? min : in); } template diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp index 55ab40214..c00638c27 100644 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ b/src/engine/platform/sound/es550x/es550x_alu.cpp @@ -54,13 +54,13 @@ void es550x_shared_core::es550x_alu_t::loop_exec() m_accum = m_start + (m_start - m_accum); } else// Normal - m_accum = (m_accum + m_start) - m_end; + m_accum = m_end - (m_start - m_accum); } else if (m_cr.ble && m_transwave) // m_transwave { m_cr.lpe = m_cr.ble = 0; m_cr.lei = 1; // Loop end ignore - m_accum = (m_accum + m_start) - m_end; + m_accum = m_end - (m_start - m_accum); } else // Stop m_cr.stop0 = 1; @@ -91,7 +91,7 @@ void es550x_shared_core::es550x_alu_t::loop_exec() s32 es550x_shared_core::es550x_alu_t::interpolation() { // SF = S1 + ACCfr * (S2 - S1) - return m_sample[0] + ((bitfield(m_accum, std::min(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); + return m_sample[0] + ((bitfield(m_accum, std::min(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); } u32 es550x_shared_core::es550x_alu_t::get_accum_integer() From 482dbf8dd55237cd6e800cce6c4a57aa080941ec Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 27 Apr 2022 14:29:53 +0900 Subject: [PATCH 03/74] Checkpoint Addressing reviews, Fix GCC/Clang builds, Core updates --- src/engine/fileOps.cpp | 4 ++-- src/engine/platform/es5506.cpp | 10 ++++++---- src/engine/platform/es5506.h | 2 +- src/engine/platform/sound/es550x/es5504.cpp | 10 +++++----- src/engine/platform/sound/es550x/es5505.cpp | 12 ++++++------ src/engine/platform/sound/es550x/es5505.hpp | 2 +- src/engine/platform/sound/es550x/es5506.cpp | 12 ++++++------ src/engine/platform/sound/es550x/es5506.hpp | 2 +- src/engine/platform/sound/es550x/es550x.hpp | 2 +- src/engine/platform/sound/es550x/es550x_filter.cpp | 14 +++++++------- src/engine/playback.cpp | 12 ++++++------ src/engine/sample.cpp | 3 ++- src/engine/sample.h | 2 +- src/gui/insEdit.cpp | 4 ++-- src/gui/sampleEdit.cpp | 4 ++-- 15 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8d3dd4764..c689fdc8f 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1476,7 +1476,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { sample->loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; sample->loopStart=0; } else { - sample->loopMode=DIV_SAMPLE_LOOPMODE_FOWARD; + sample->loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; } } else { reader.readI(); @@ -1714,7 +1714,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { sample->loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; sample->loopStart=0; } else { - sample->loopMode=DIV_SAMPLE_LOOPMODE_FOWARD; + sample->loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; } } sample->init(slen); diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index c94fdf416..ee3f45e87 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -168,7 +168,7 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l } } -void DivPlatformES5506::e(bool state) +void DivPlatformES5506::e_pin(bool state) { if (es5506.e_rising_edge()) { if (cycle) { // wait until delay @@ -292,6 +292,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].k1Offs=chan[i].std.ex1.val; chan[i].filterChanged.k1=1; } + break; case 1: // absolute if (chan[i].filter.k1!=(chan[i].std.ex1.val&0xffff)) { chan[i].filter.k1=chan[i].std.ex1.val&0xffff; @@ -317,6 +318,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].k2Offs=chan[i].std.ex1.val; chan[i].filterChanged.k2=1; } + break; case 1: // absolute if (chan[i].filter.k2!=(chan[i].std.ex2.val&0xffff)) { chan[i].filter.k2=chan[i].std.ex2.val&0xffff; @@ -472,7 +474,7 @@ void DivPlatformES5506::tick(bool sysTick) { case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) default: break; - case DIV_SAMPLE_LOOPMODE_FOWARD: // Foward loop + case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop loopFlag|=0x0008; break; case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable @@ -728,8 +730,8 @@ void DivPlatformES5506::forceIns() { chan[i].insChanged=true; chan[i].freqChanged=true; chan[i].volChanged=true; - chan[i].filterChanged.changed=(unsigned char)(~0); - chan[i].envChanged.changed=(unsigned char)(~0); + chan[i].filterChanged.changed=0xff; + chan[i].envChanged.changed=0xff; chan[i].sample=-1; } } diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index d378a19f9..fc49525f7 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -165,7 +165,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { friend void putDispatchChan(void*,int,int); public: - virtual void e(bool state) override; // E output + virtual void e_pin(bool state) override; // E output virtual void irqb(bool state) override; // IRQB output virtual s16 read_sample(u8 voice, u8 bank, u32 address) override { diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp index d9750b7f1..00707d4f7 100644 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -32,7 +32,7 @@ void es5504_core::tick() { if (m_e.tick()) { - m_intf.e(m_e.current_edge()); + m_intf.e_pin(m_e.current_edge()); if (m_e.rising_edge()) // Host access { m_host_intf.m_rw = m_host_intf.m_rw_strobe; @@ -77,24 +77,24 @@ void es5504_core::tick_perf() // update // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; } diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index ca5fb8902..d2d4731cf 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -63,7 +63,7 @@ void es5505_core::tick() for (int i = 0; i < 4; i++) { if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_right, output_bit); + m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); else // Left output m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); } @@ -89,7 +89,7 @@ void es5505_core::tick() // E if (m_e.tick()) { - m_intf.e(m_e.current_edge()); + m_intf.e_pin(m_e.current_edge()); if (m_e.rising_edge()) // Host access { m_host_intf.m_rw = m_host_intf.m_rw_strobe; @@ -141,24 +141,24 @@ void es5505_core::tick_perf() // update // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; } diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp index be6505f66..1803e7d8d 100644 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -131,7 +131,7 @@ private: clock_pulse_t m_lrclk; // LRCLK s16 m_wclk = 0; // WCLK bool m_wclk_lr = false; // WCLK, L/R output select - u8 m_output_bit = 0; // Bit position in output + s8 m_output_bit = 0; // Bit position in output output_t m_ch[4]; // 4 stereo output channels output_t m_output[4]; // Serial outputs output_t m_output_temp[4]; // temporary signal for serial output diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index d1ac89bb0..133611eee 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -83,7 +83,7 @@ void es5506_core::tick() for (int i = 0; i < 6; i++) { if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_right, output_bit); + m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); else // Left output m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); } @@ -124,7 +124,7 @@ void es5506_core::tick() // E if (m_e.tick()) { - m_intf.e(m_e.current_edge()); + m_intf.e_pin(m_e.current_edge()); if (m_e.rising_edge()) { m_host_intf.m_rw = m_host_intf.m_rw_strobe; @@ -190,24 +190,24 @@ void es5506_core::tick_perf() // update // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; // falling edge m_e.m_edge.set(false); - m_intf.e(false); + m_intf.e_pin(false); m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); voice_tick(); // rising edge m_e.m_edge.set(true); - m_intf.e(true); + m_intf.e_pin(true); m_host_intf.m_rw = m_host_intf.m_rw_strobe; m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; } diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp index 2232f5179..f46941ed5 100644 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -169,7 +169,7 @@ private: clock_pulse_t m_lrclk; // LRCLK s16 m_wclk = 0; // WCLK bool m_wclk_lr = false; // WCLK, L/R output select - u8 m_output_bit = 0; // Bit position in output + s8 m_output_bit = 0; // Bit position in output output_t m_ch[6]; // 6 stereo output channels output_t m_output[6]; // Serial outputs output_t m_output_temp[6]; // temporary signal for serial output diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index eb3eaf255..4c7a8fa77 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -146,7 +146,7 @@ using namespace es550x; class es550x_intf { public: - virtual void e(bool state) {} // E output + virtual void e_pin(bool state) {} // E output virtual void bclk(bool state) {} // BCLK output (serial specific) virtual void lrclk(bool state) {} // LRCLK output (serial specific) virtual void wclk(bool state) {} // WCLK output (serial specific) diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp index 8ef526ff3..abf16b4d5 100644 --- a/src/engine/platform/sound/es550x/es550x_filter.cpp +++ b/src/engine/platform/sound/es550x/es550x_filter.cpp @@ -26,8 +26,8 @@ void es550x_shared_core::es550x_filter_t::reset() void es550x_shared_core::es550x_filter_t::tick(s32 in) { - s32 coeff_k1 = s32(bitfield(m_k1,4,12)); // 12 MSB used - s32 coeff_k2 = s32(bitfield(m_k2,4,12)); // 12 MSB used + s32 coeff_k1 = s32(bitfield(m_k1, 4, 12)); // 12 MSB used + s32 coeff_k2 = s32(bitfield(m_k2, 4, 12)); // 12 MSB used // Store previous filter data m_o2_2 = m_o2_1; m_o3_2 = m_o3_1; @@ -43,16 +43,16 @@ void es550x_shared_core::es550x_filter_t::tick(s32 in) m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); break; case 1: // LP3 = 0, LP4 = 1: HP/K2, LP/K1 - m_o4_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o3_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); + m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); + m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); break; case 2: // LP3 = 1, LP4 = 0: LP/K2, LP/K2 m_o3_1 = lp_exec(coeff_k2, m_o2_1, m_o3_1); m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); break; case 3: // LP3 = 1, LP4 = 1: LP/K2, LP/K1 - m_o4_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o3_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); + m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); + m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); break; } } @@ -66,5 +66,5 @@ s32 es550x_shared_core::es550x_filter_t::lp_exec(s32 coeff, s32 in, s32 prev_out s32 es550x_shared_core::es550x_filter_t::hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in) { // Yn = Xn - Xn-1 + K*Yn-1 - return in - prev_in + ((coeff * prev_out) / 8192) * (prev_out / 2); + return in - prev_in + ((coeff * prev_out) / 8192) + (prev_out / 2); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0f7779cf9..35201cae2 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1808,7 +1808,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (sPreview.dir) { if (s->isLoopable() && ((int)sPreview.pos)loopStart) { switch (s->loopMode) { - case DIV_SAMPLE_LOOPMODE_FOWARD: + case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; sPreview.pos=s->loopStart+1; break; @@ -1828,7 +1828,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else { if (s->isLoopable() && sPreview.pos>=s->loopEnd) { switch (s->loopMode) { - case DIV_SAMPLE_LOOPMODE_FOWARD: + case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; sPreview.pos=s->loopStart; break; @@ -1851,7 +1851,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (sPreview.dir) { if (s->isLoopable() && ((int)sPreview.pos)loopStart) { switch (s->loopMode) { - case DIV_SAMPLE_LOOPMODE_FOWARD: + case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; sPreview.pos=s->loopStart+1; break; @@ -1865,18 +1865,18 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi break; case DIV_SAMPLE_LOOPMODE_ONESHOT: default: - if (sPreview.pos<0) { + if (((int)sPreview.pos)<0) { sPreview.sample=-1; } break; } - } else if (sPreview.pos<0) { + } else if (((int)sPreview.pos)<0) { sPreview.sample=-1; } } else { if (s->isLoopable() && sPreview.pos>=s->loopEnd) { switch (s->loopMode) { - case DIV_SAMPLE_LOOPMODE_FOWARD: + case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; sPreview.pos=s->loopStart; break; diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index c971f9973..fcbc370c3 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -330,10 +330,11 @@ bool DivSample::insert(unsigned int pos, unsigned int length) { #define RESAMPLE_END \ if (loopStart>=0) loopStart=(double)loopStart*(r/(double)rate); \ - if (loopEnd>=0) loopEnd=(double)loopEnd*(r/(double)rate); \ + if (loopEndsamples) loopEnd=samples; \ if (depth==DIV_SAMPLE_DEPTH_16BIT) { \ delete[] oldData16; \ } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { \ diff --git a/src/engine/sample.h b/src/engine/sample.h index ff3e2f7b4..d14ae9526 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -51,7 +51,7 @@ enum DivSampleDepth: unsigned char { enum DivSampleLoopMode: unsigned char { DIV_SAMPLE_LOOPMODE_ONESHOT=0, - DIV_SAMPLE_LOOPMODE_FOWARD, + DIV_SAMPLE_LOOPMODE_FORWARD, DIV_SAMPLE_LOOPMODE_BACKWARD, DIV_SAMPLE_LOOPMODE_PINGPONG, DIV_SAMPLE_LOOPMODE_MAX // for identify boundary diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 3c22a17c3..a5de2f29a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1111,7 +1111,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s if (macro.len>127) macro.len=127; \ } \ if (macroMode && macroModeMax>0) { \ - for (int m=0; m<=macroModeMax; m++) { \ + for (unsigned int m=0; m<=macroModeMax; m++) { \ if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \ macro.mode=m; \ } \ @@ -1206,7 +1206,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s if (macro.len>127) macro.len=127; \ } \ if (macroMode && macroModeMax>0) { \ - for (int m=0; m<=macroModeMax; m++) { \ + for (unsigned int m=0; m<=macroModeMax; m++) { \ if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \ macro.mode=m; \ } \ diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 0021294e0..779185af7 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -137,8 +137,8 @@ void FurnaceGUI::drawSampleEdit() { if (endloopStart) { end=sample->loopStart; } - if (end>sample->samples) { - end=sample->samples; + if (end>(int)sample->samples) { + end=(int)sample->samples; } sample->loopEnd=end; updateSampleTex=true; From 8c214d40e1bda55d6e5809d07ac43ee22487e019 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 27 Apr 2022 22:08:18 +0900 Subject: [PATCH 04/74] Fix build, Core update --- src/engine/platform/sound/es550x/es550x_alu.cpp | 2 +- src/gui/sampleEdit.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp index c00638c27..7e1ec05c4 100644 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ b/src/engine/platform/sound/es550x/es550x_alu.cpp @@ -91,7 +91,7 @@ void es550x_shared_core::es550x_alu_t::loop_exec() s32 es550x_shared_core::es550x_alu_t::interpolation() { // SF = S1 + ACCfr * (S2 - S1) - return m_sample[0] + ((bitfield(m_accum, std::min(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); + return m_sample[0] + ((bitfield(m_accum, std::max(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); } u32 es550x_shared_core::es550x_alu_t::get_accum_integer() diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 779185af7..42f9cb8f8 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -684,7 +684,7 @@ void FurnaceGUI::drawSampleEdit() { if (endloopStart) { end=sample->loopStart; } - if (end>sample->samples) { + if (end>(int)(sample->samples)) { end=sample->samples; } sample->loopEnd=end; @@ -1203,7 +1203,7 @@ void FurnaceGUI::drawSampleEdit() { for (int i=0; iisLoopable() && ((scaledPos>=sample->loopStart) && (scaledPosloopEnd))) { + if (sample->isLoopable() && ((scaledPos>=sample->loopStart) && (scaledPos<(int)(sample->loopEnd)))) { data[i*availX+j]=bgColorLoop; } else { data[i*availX+j]=bgColor; From d0c55e495136cf8f9870a523d540a5ab649f50e4 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 28 Apr 2022 23:58:35 +0900 Subject: [PATCH 05/74] Fix build --- src/engine/platform/es5506.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index a0f98613c..22a3d709d 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -272,7 +272,7 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; - CLAMP_VAL(chan[i].pitch2,-2048,2048); + CLAMP_VAR(chan[i].pitch2,-2048,2048); } else { chan[i].pitch2=chan[i].std.pitch.val; } From ee7633ba7a615a33ed46d0fd8c23f2b88e4229eb Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 30 Apr 2022 02:06:16 +0900 Subject: [PATCH 06/74] Add dummy sample for reduce phase accumulator wraparound related issue --- src/engine/engine.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 3270e7d35..751870434 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -618,23 +618,23 @@ void DivEngine::renderSamples() { if (es5506Mem==NULL) es5506Mem=new signed short[16777216/sizeof(short)]; // 2Mword * 4 banks memset(es5506Mem,0,16777216); - memPos=0; + memPos=128; for (int i=0; ilength16; // fit sample size to single bank size - if (length>2097152*sizeof(short)) { - length=2097152*sizeof(short); + if (length>(2097152-64)*sizeof(short)) { + length=(2097152-64)*sizeof(short); } - if ((memPos&0xc00000)!=((memPos+length)&0xc00000)) { - memPos=(memPos+0x3fffff)&0xc00000; + if ((memPos&0xc00000)!=((memPos+length+128)&0xc00000)) { + memPos=((memPos+0x3fffff)&0xc00000)+128; } - if (memPos>=16777216) { + if (memPos>=(16777216-128)) { logW("out of ES5506 memory for sample %d!",i); break; } - if (memPos+length>=16777216) { - memcpy(es5506Mem+(memPos/sizeof(short)),s->data16,16777216-memPos); + if (memPos+length>=(16777216-128)) { + memcpy(es5506Mem+(memPos/sizeof(short)),s->data16,16777216-memPos-128); logW("out of ES5506 memory for sample %d!",i); } else { memcpy(es5506Mem+(memPos/sizeof(short)),s->data16,length); From 53a52788e2f569a2bd5b09f8e1f06942c789a1f2 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 30 Apr 2022 23:45:05 +0900 Subject: [PATCH 07/74] Add per-note map reversed playback support Prepare for pcm changed flag, 8 bit panning command Reduce register spamming in volume update routine Progress report: * Emulation core update, Dispatch update: * Volume is unsigned like original chip, for reduce overflow. * Add multi-mode macro support for radio button --- src/engine/instrument.h | 4 +- src/engine/platform/es5506.cpp | 110 +++++++++++++++++++++++---------- src/engine/platform/es5506.h | 25 ++++++-- src/gui/debug.cpp | 4 +- src/gui/insEdit.cpp | 7 ++- 5 files changed, 109 insertions(+), 41 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 09efbd6c0..9ad6793fd 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -300,10 +300,12 @@ struct DivInstrumentAmiga { struct NoteMap { int freq; short ind; + bool reversed; NoteMap(): freq(0), - ind(-1) {} + ind(-1), + reversed(false) {} }; short initSample; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 22a3d709d..3205586f0 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -236,21 +236,30 @@ void DivPlatformES5506::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins); // volume/panning macros if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; + if (chan[i].outVol!=nextVol) { + chan[i].outVol=nextVol; + if (!isMuted[i]) { + chan[i].volChanged.changed=0xff; + } } } if (chan[i].std.panL.had) { - chan[i].outLVol=(((ins->es5506.lVol*(chan[i].lVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panL.val))/0xffff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panL.val))/0xffff; + if (chan[i].outLVol!=nextLVol) { + chan[i].outLVol=nextLVol; + if (!isMuted[i]) { + chan[i].volChanged.lVol=1; + } } } if (chan[i].std.panR.had) { - chan[i].outRVol=(((ins->es5506.rVol*(chan[i].rVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panR.val))/0xffff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panR.val))/0xffff; + if (chan[i].outRVol!=nextRVol) { + chan[i].outRVol=nextRVol; + if (!isMuted[i]) { + chan[i].volChanged.rVol=1; + } } } // arpeggio/pitch macros, frequency related @@ -306,7 +315,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k1=CLAMP_VAL(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); + const signed int next_k1=CLAMP_VAL(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); if (chan[i].k1Offs!=next_k1) { chan[i].k1Offs=next_k1; chan[i].filterChanged.k1=1; @@ -332,7 +341,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k2=CLAMP_VAL(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); + const signed int next_k2=CLAMP_VAL(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); if (chan[i].k2Offs!=next_k2) { chan[i].k2Offs=next_k2; chan[i].filterChanged.k2=1; @@ -385,19 +394,54 @@ void DivPlatformES5506::tick(bool sysTick) { } } // update registers - if (chan[i].volChanged) { + if (chan[i].volChanged.changed) { if (!isMuted[i]) { // calculate volume (16 bit) - chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; - chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; - if (!chan[i].keyOn) { - pageWrite(0x00|i,0x02,chan[i].resLVol); - pageWrite(0x00|i,0x04,chan[i].resRVol); + if (chan[i].volChanged.lVol) { + chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x02,chan[i].resLVol); + } + } + if (chan[i].volChanged.rVol) { + chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x04,chan[i].resRVol); + } } } else { // mute pageWrite(0x00|i,0x02,0); pageWrite(0x00|i,0x04,0); } - chan[i].volChanged=false; + chan[i].volChanged.changed=0; + } + if (chan[i].pcmChanged) { + DivInstrument* ins=parent->getIns(chan[i].ins); + if (!ins->amiga.useNoteMap) { + double off=1.0; + if (chan[i].pcm.next>=0 && chan[i].pcm.nextsong.sampleLen) { + chan[i].pcm.index=chan[i].pcm.next; + DivSample* s=parent->getSample(chan[i].pcm.next); + if (s->centerRate<1) { + off=1.0; + } else { + off=(double)s->centerRate/8363.0; + } + const unsigned int start=s->offES5506<<10; + const unsigned int length=s->samples-1; + const unsigned int end=start+(length<<11); + chan[i].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + chan[i].pcm.freqOffs=off; + chan[i].pcm.reversed=ins->amiga.reversed; + chan[i].pcm.bank=(s->offES5506>>22)&3; + chan[i].pcm.start=start; + chan[i].pcm.end=end; + chan[i].pcm.length=length; + chan[i].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; + chan[i].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; + chan[i].keyOn=true; + } + } + chan[i].pcmChanged=false; } if (chan[i].filterChanged.changed) { if (!chan[i].keyOn) { @@ -527,7 +571,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { const unsigned int end=start+(length<<11); chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; chan[c.chan].pcm.freqOffs=off; - chan[c.chan].pcm.reversed=ins->amiga.reversed; + chan[c.chan].pcm.reversed=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].reversed:ins->amiga.reversed; chan[c.chan].pcm.bank=(s->offES5506>>22)&3; chan[c.chan].pcm.start=start; chan[c.chan].pcm.end=end; @@ -545,17 +589,17 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value); chan[c.chan].freqChanged=true; - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.changed=0xff; chan[c.chan].note=c.value; } if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=(0xffff*chan[c.chan].vol)/0xff; } if (!chan[c.chan].std.panL.will) { - chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xf; + chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xff; } if (!chan[c.chan].std.panR.will) { - chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xf; + chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xff; } chan[c.chan].active=true; chan[c.chan].keyOn=true; @@ -580,12 +624,12 @@ int DivPlatformES5506::dispatch(DivCommand c) { } break; case DIV_CMD_VOLUME: - if (chan[c.chan].vol!=c.value) { + if (chan[c.chan].vol!=(unsigned int)(c.value)) { chan[c.chan].vol=c.value; if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=(0xffff*c.value)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.changed=0xff; } } } @@ -600,24 +644,24 @@ int DivPlatformES5506::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); // 08LR, each nibble means volume multipler for each channels // Left volume - unsigned char lVol=(c.value>>4)&0xf; + const unsigned int lVol=(0xff*((c.value>>4)&0xf))/0xf; if (chan[c.chan].lVol!=lVol) { chan[c.chan].lVol=lVol; if (!chan[c.chan].std.panL.has) { - chan[c.chan].outLVol=(ins->es5506.lVol*lVol)/0xf; + chan[c.chan].outLVol=(ins->es5506.lVol*lVol)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.lVol=1; } } } // Right volume - unsigned char rVol=(c.value>>0)&0xf; + const unsigned int rVol=(0xff*((c.value>>0)&0xf))/0xf; if (chan[c.chan].rVol!=rVol) { chan[c.chan].rVol=rVol; if (!chan[c.chan].std.panR.has) { - chan[c.chan].outRVol=(ins->es5506.rVol*rVol)/0xf; + chan[c.chan].outRVol=(ins->es5506.rVol*rVol)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.rVol=1; } } } @@ -667,7 +711,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.k2Ramp=1; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_ES5506(c.chan,c.value2); + const int destFreq=NOTE_ES5506(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -704,7 +748,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_POS: { if (chan[c.chan].useWave) break; if (chan[c.chan].active) { - unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value; + const unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value; if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && posactive?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); - ImGui::TextColored(ch->volChanged?colorOn:colorOff,">> VolChanged"); + ImGui::TextColored(ch->volChanged.lVol?colorOn:colorOff,">> LVolChanged"); + ImGui::TextColored(ch->volChanged.rVol?colorOn:colorOff,">> RVolChanged"); ImGui::TextColored(ch->filterChanged.mode?colorOn:colorOff,">> FilterModeChanged"); ImGui::TextColored(ch->filterChanged.k1?colorOn:colorOff,">> FilterK1Changed"); ImGui::TextColored(ch->filterChanged.k2?colorOn:colorOff,">> FilterK2Changed"); @@ -387,6 +388,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->envChanged.rVRamp?colorOn:colorOff,">> EnvRVRampChanged"); ImGui::TextColored(ch->envChanged.k1Ramp?colorOn:colorOff,">> EnvK1RampChanged"); ImGui::TextColored(ch->envChanged.k2Ramp?colorOn:colorOff,">> EnvK2RampChanged"); + ImGui::TextColored(ch->pcmChanged?colorOn:colorOff,">> PCMChanged"); ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index cc1c6f49d..c979093a1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2513,10 +2513,11 @@ void FurnaceGUI::drawInsEdit() { ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { - if (ImGui::BeginTable("NoteMap",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + if (ImGui::BeginTable("NoteMap",4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupScrollFreeze(0,1); @@ -2526,6 +2527,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Sample"); ImGui::TableNextColumn(); ImGui::Text("Frequency"); + ImGui::TableNextColumn(); + ImGui::Text("Reversed"); for (int i=0; i<120; i++) { ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); @@ -2559,6 +2562,8 @@ void FurnaceGUI::drawInsEdit() { if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; } + ImGui::TableNextColumn(); + P(ImGui::Checkbox("##SR",&ins->amiga.noteMap[i].reversed)); ImGui::PopID(); } ImGui::EndTable(); From 83405dcb4f538ccd3c6623a1bbb2de055372ecbc Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 1 May 2022 00:44:29 +0900 Subject: [PATCH 08/74] Sync with master * Add boundary for system enum * Add ES5506 VGM version (not support yet) --- src/engine/song.h | 3 ++- src/engine/sysDef.cpp | 2 +- src/gui/sysConf.cpp | 46 +------------------------------------------ 3 files changed, 4 insertions(+), 47 deletions(-) diff --git a/src/engine/song.h b/src/engine/song.h index 8e67cce83..9bff554e5 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -105,7 +105,8 @@ enum DivSystem { DIV_SYSTEM_SOUND_UNIT, DIV_SYSTEM_MSM6295, DIV_SYSTEM_MSM6258, - DIV_SYSTEM_DUMMY + DIV_SYSTEM_DUMMY, + DIV_SYSTEM_MAX // boundary for max system number }; struct DivSong { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1f7920d7c..86500283d 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -832,7 +832,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( - "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false, + "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0/*0x171*/, false, {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 8ded3eb11..cacc93b48 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -48,41 +48,32 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool ImGui::Text("Clock rate:"); if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) { copyOfFlags=(flags&(~3))|0; - } if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) { copyOfFlags=(flags&(~3))|1; - } if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) { copyOfFlags=(flags&(~3))|2; - } if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) { copyOfFlags=(flags&(~3))|3; - } ImGui::Text("Chip type:"); if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) { copyOfFlags=(flags&(~12))|0; - } if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) { copyOfFlags=(flags&(~12))|4; - } if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) { copyOfFlags=(flags&(~12))|8; - } /*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) { copyOfFlags=(flags&3)|12); }*/ - bool noPhaseReset=flags&16; if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) { copyOfFlags=(flags&(~16))|(noPhaseReset<<4); - } break; } @@ -92,37 +83,29 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool ImGui::Text("Clock rate:"); if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&15)==0)) { copyOfFlags=(flags&(~15))|0; - } if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; - } if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; - } if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) { copyOfFlags=(flags&(~15))|3; - } if (type!=DIV_SYSTEM_VRC7) { ImGui::Text("Patch set:"); if (ImGui::RadioButton("Yamaha YM2413",((flags>>4)&15)==0)) { copyOfFlags=(flags&(~0xf0))|0; - } if (ImGui::RadioButton("Yamaha YMF281",((flags>>4)&15)==1)) { copyOfFlags=(flags&(~0xf0))|0x10; - } if (ImGui::RadioButton("Yamaha YM2423",((flags>>4)&15)==2)) { copyOfFlags=(flags&(~0xf0))|0x20; - } if (ImGui::RadioButton("Konami VRC7",((flags>>4)&15)==3)) { copyOfFlags=(flags&(~0xf0))|0x30; - } } break; @@ -130,15 +113,12 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_YM2151: if (ImGui::RadioButton("NTSC/X16 (3.58MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("X1/X68000 (4MHz)",flags==2)) { copyOfFlags=2; - } break; case DIV_SYSTEM_NES: @@ -147,30 +127,24 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool case DIV_SYSTEM_MMC5: if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) { copyOfFlags=2; - } break; case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: if (ImGui::RadioButton("NTSC (1.02MHz)",flags==0)) { copyOfFlags=0; - } if (ImGui::RadioButton("PAL (0.99MHz)",flags==1)) { copyOfFlags=1; - } if (ImGui::RadioButton("SSI 2001 (0.89MHz)",flags==2)) { copyOfFlags=2; - } break; case DIV_SYSTEM_AY8910: @@ -178,72 +152,56 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool ImGui::Text("Clock rate:"); if (ImGui::RadioButton("1.79MHz (ZX Spectrum NTSC/MSX)",(flags&15)==0)) { copyOfFlags=(flags&(~15))|0; - } if (ImGui::RadioButton("1.77MHz (ZX Spectrum)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; - } if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; - } if (ImGui::RadioButton("2MHz (Atari ST/Sharp X1)",(flags&15)==3)) { copyOfFlags=(flags&(~15))|3; - } if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) { copyOfFlags=(flags&(~15))|4; - } if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) { copyOfFlags=(flags&(~15))|5; - } if (ImGui::RadioButton("0.89MHz (Sunsoft 5B)",(flags&15)==6)) { copyOfFlags=(flags&(~15))|6; - } if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) { copyOfFlags=(flags&(~15))|7; - } if (ImGui::RadioButton("0.83MHz (Sunsoft 5B on PAL)",(flags&15)==8)) { copyOfFlags=(flags&(~15))|8; - } if (ImGui::RadioButton("1.10MHz (Gamate/VIC-20 PAL)",(flags&15)==9)) { copyOfFlags=(flags&(~15))|9; - } if (ImGui::RadioButton("2^21Hz (Game Boy)",(flags&15)==10)) { copyOfFlags=(flags&(~15))|10; - } if (type==DIV_SYSTEM_AY8910) { ImGui::Text("Chip type:"); if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) { copyOfFlags=(flags&(~0x30))|0; - } if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) { copyOfFlags=(flags&(~0x30))|16; - } if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) { copyOfFlags=(flags&(~0x30))|32; - } if (ImGui::RadioButton("AY-3-8914",(flags&0x30)==48)) { copyOfFlags=(flags&(~0x30))|48; - } } bool stereo=flags&0x40; ImGui::BeginDisabled((flags&0x30)==32); if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) { copyOfFlags=(flags&(~0x40))|(stereo?0x40:0); - } ImGui::EndDisabled(); break; @@ -347,7 +305,6 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (initialChannelLimit<1) initialChannelLimit=1; if (initialChannelLimit>8) initialChannelLimit=8; copyOfFlags=(flags & ~(7 << 4)) | (((initialChannelLimit-1) & 7) << 4); - } rightClickable bool n163Multiplex=flags&128; if (ImGui::Checkbox("Disable hissing",&n163Multiplex)) { @@ -361,8 +318,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (CWSliderInt("##OTTO_InitialChannelLimit",&initialChannelLimit,5,32)) { if (initialChannelLimit<5) initialChannelLimit=5; if (initialChannelLimit>32) initialChannelLimit=32; - e->setSysFlags(i,(flags & ~31) | ((initialChannelLimit-1) & 31),restart); - updateWindowTitle(); + copyOfFlags=(flags & ~31) | ((initialChannelLimit-1) & 31); } rightClickable break; } From e246697928c76f9a22814d15bde5c9cc88025295 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 1 May 2022 21:26:10 +0900 Subject: [PATCH 09/74] Prepare for per-channel osc view, ES550X core update --- src/engine/platform/es5506.cpp | 34 +++++++++++++++++++-- src/engine/platform/es5506.h | 9 +++++- src/engine/platform/sound/es550x/es5504.cpp | 10 +++++- src/engine/platform/sound/es550x/es5504.hpp | 9 ++++++ src/engine/platform/sound/es550x/es5505.cpp | 8 ++++- src/engine/platform/sound/es550x/es5505.hpp | 10 ++++++ src/engine/platform/sound/es550x/es5506.cpp | 8 ++++- src/engine/platform/sound/es550x/es5506.hpp | 10 ++++++ src/engine/platform/sound/es550x/es550x.cpp | 2 ++ src/engine/platform/sound/es550x/es550x.hpp | 15 +++++++++ src/gui/debug.cpp | 3 ++ 11 files changed, 112 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 248bc24bf..180c0d3fb 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -162,14 +162,34 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l } hostIntf32.pop(); } + prevChanCycle=es5506.voice_cycle(); es5506.tick_perf(); bufL[h]=es5506.lout(0); bufR[h]=es5506.rout(0); + for (int i=0; i<32; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=chan[i].oscOut; + } } } void DivPlatformES5506::e_pin(bool state) { + // get channel outputs + if (es5506.e_falling_edge()) { + if (es5506.voice_update()) { + chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); + chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); + chan[prevChanCycle].oscOut=(chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5; + if (es5506.voice_end()) { + if (prevChanCycle<31) { + for (int c=31; c>prevChanCycle; c--) { + chan[c].lOut=chan[c].rOut=chan[c].oscOut=0; + } + } + } + } + } + // host interface if (es5506.e_rising_edge()) { if (cycle) { // wait until delay cycle--; @@ -803,6 +823,7 @@ void DivPlatformES5506::reset() { isMasked=false; isReaded=false; irqTrigger=false; + prevChanCycle=0; chanMax=initChanMax; pageWriteMask(0x00,0x60,0x0b,chanMax); @@ -855,6 +876,10 @@ void DivPlatformES5506::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) immWrite(i.addr,i.val); } +DivDispatchOscBuffer* DivPlatformES5506::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformES5506::getRegisterPool() { unsigned char* regPoolPtr = regPool; for (unsigned char p=0; p<128; p++) { @@ -877,16 +902,21 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned in dumpWrites=false; skipRegisterWrites=false; + chipClock=16000000; + rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice for (int i=0; i<32; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; + oscBuf[i]->rate=rate; } setFlags(flags); - chipClock=16000000; - rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice reset(); return 32; } void DivPlatformES5506::quit() { + for (int i=0; i<32; i++) { + delete oscBuf[i]; + } } diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 7066f06cd..d57a8234d 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -108,6 +108,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned int vol, lVol, rVol; unsigned int outVol, outLVol, outRVol; unsigned int resLVol, resRVol; + signed int lOut, rOut, oscOut; DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; DivMacroInt std; @@ -148,9 +149,13 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { outLVol(0xffff), outRVol(0xffff), resLVol(0xffff), - resRVol(0xffff) {} + resRVol(0xffff), + lOut(0), + rOut(0), + oscOut(0) {} }; Channel chan[32]; + DivDispatchOscBuffer* oscBuf[32]; bool isMuted[32]; struct QueuedHostIntf { unsigned char step; @@ -184,6 +189,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned int irqv; bool isMasked, isReaded; bool irqTrigger; + unsigned char prevChanCycle; unsigned char initChanMax, chanMax; @@ -204,6 +210,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override; virtual int dispatch(DivCommand c) override; virtual void* getChanState(int chan) override; + virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; virtual unsigned char* getRegisterPool() override; virtual int getRegisterPoolSize() override; virtual void reset() override; diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp index 00707d4f7..b7b808ac5 100644 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -13,6 +13,8 @@ // Internal functions void es5504_core::tick() { + m_voice_update = false; + m_voice_end = false; // /CAS, E if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock { @@ -74,6 +76,8 @@ void es5504_core::tick() // less cycle accurate, but less CPU heavy routine void es5504_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // update // falling edge m_e.m_edge.set(false); @@ -102,7 +106,8 @@ void es5504_core::tick_perf() void es5504_core::voice_tick() { // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -111,7 +116,10 @@ void es5504_core::voice_tick() m_ch[m_voice[m_voice_cycle].m_cr.ca] = m_voice[m_voice_cycle].m_ch; if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices + { + m_voice_end = true; m_voice_cycle = 0; + } m_voice_fetch = 0; } diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp index f6743e18b..b9423dfc0 100644 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ b/src/engine/platform/sound/es550x/es5504.hpp @@ -43,6 +43,12 @@ public: // 16 analog output channels s32 out(u8 ch) { return m_ch[ch & 0xf]; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u16 read(u8 address, bool cpu_access = false); void write(u8 address, u16 data, bool cpu_access = false); @@ -52,6 +58,9 @@ public: u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + // per-voice outputs + s32 voice_out(u8 voice) { return (voice < 25) ? m_voice[voice].m_ch : 0; } + protected: virtual inline u8 max_voices() override { return 25; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index 0b460f773..7ab2321ea 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -13,6 +13,8 @@ // Internal functions void es5505_core::tick() { + m_voice_update = false; + m_voice_end = false; // CLKIN if (m_clkin.tick()) { @@ -131,6 +133,8 @@ void es5505_core::tick() // less cycle accurate, but less CPU heavy routine void es5505_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // output for (int c = 0; c < 4; c++) { @@ -166,7 +170,8 @@ void es5505_core::tick_perf() void es5505_core::voice_tick() { // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -174,6 +179,7 @@ void es5505_core::voice_tick() // Refresh output if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices { + m_voice_end = true; m_voice_cycle = 0; for (auto & elem : m_ch) elem.reset(); diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp index 1803e7d8d..25c06beeb 100644 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -52,6 +52,12 @@ public: s32 lout(u8 ch) { return m_ch[ch & 0x3].m_left; } s32 rout(u8 ch) { return m_ch[ch & 0x3].m_right; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u16 read(u8 address, bool cpu_access = false); void write(u8 address, u16 data, bool cpu_access = false); @@ -61,6 +67,10 @@ public: u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + // per-voice outputs + s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } + s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } + protected: virtual inline u8 max_voices() override { return 32; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 85245f408..41f62b317 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -13,6 +13,8 @@ // Internal functions void es5506_core::tick() { + m_voice_update = false; + m_voice_end = false; // CLKIN if (m_clkin.tick()) { @@ -165,6 +167,8 @@ void es5506_core::tick() // less cycle accurate, but less CPU heavy routine void es5506_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // output if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.wclk_en)) && (m_w_st < m_w_end)) { @@ -215,7 +219,8 @@ void es5506_core::tick_perf() void es5506_core::voice_tick() { // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -223,6 +228,7 @@ void es5506_core::voice_tick() // Refresh output if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices { + m_voice_end = true; m_voice_cycle = 0; for (auto & elem : m_ch) elem.reset(); diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp index f46941ed5..3940fea49 100644 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -48,6 +48,12 @@ public: s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_left; } s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_right; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u8 read(u8 address, bool cpu_access = false); void write(u8 address, u8 data, bool cpu_access = false); @@ -58,6 +64,10 @@ public: u8 regs8_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u8 ret = read(address, false); m_page = prev; return ret; } void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].m_mute = mute; } + // per-voice outputs + s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } + s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } + protected: virtual inline u8 max_voices() override { return 32; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp index 8047e1706..c65a1ea69 100644 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ b/src/engine/platform/sound/es550x/es550x.cpp @@ -62,6 +62,8 @@ void es550x_shared_core::reset() m_active = max_voices() - 1; m_voice_cycle = 0; m_voice_fetch = 0; + m_voice_update = false; + m_voice_end = false; m_clkin.reset(); m_cas.reset(); m_e.reset(); diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index d1dae9e3d..52aba0f82 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -181,6 +181,19 @@ public: bool e_rising_edge() { return m_e.rising_edge(); } bool e_falling_edge() { return m_e.falling_edge(); } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + + // voice cycle + u8 voice_cycle() { return m_voice_cycle; } + + // voice update flag + bool voice_update() { return m_voice_update; } + bool voice_end() { return m_voice_end; } + protected: // Constants virtual inline u8 max_voices() { return 32; } @@ -385,6 +398,8 @@ protected: u8 m_active = max_voices() - 1; // Activated voices (-1, ~25 for ES5504, ~32 for ES5505/ES5506) u8 m_voice_cycle = 0; // Voice cycle u8 m_voice_fetch = 0; // Voice fetch cycle + bool m_voice_update = false; // Voice update flag + bool m_voice_end = false; // End of one voice cycle flag es550x_intf &m_intf; // es550x specific memory interface clock_pulse_t m_clkin; // CLKIN clock clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index a3bcf4117..79fb1f397 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -375,6 +375,9 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- outRVol: %.2x",ch->outRVol); ImGui::Text("- ResLVol: %.2x",ch->resLVol); ImGui::Text("- ResRVol: %.2x",ch->resRVol); + ImGui::Text("- LOut: %d",ch->lOut); + ImGui::Text("- ROut: %d",ch->rOut); + ImGui::Text("- oscOut: %d",ch->oscOut); ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); From 8283d46e7d379a3c274eeed6642c4473837c3792 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 2 May 2022 21:19:10 +0900 Subject: [PATCH 10/74] Disable reversed playback checkbox when using sample map Clamp per-channel OSC output, Reduce warning --- src/engine/platform/es5506.cpp | 8 ++++---- src/gui/insEdit.cpp | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 180c0d3fb..5b84c14cb 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -167,7 +167,7 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l bufL[h]=es5506.lout(0); bufR[h]=es5506.rout(0); for (int i=0; i<32; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=chan[i].oscOut; + oscBuf[i]->data[oscBuf[i]->needle++]=(short)(chan[i].oscOut&0xffff); } } } @@ -179,7 +179,7 @@ void DivPlatformES5506::e_pin(bool state) if (es5506.voice_update()) { chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); - chan[prevChanCycle].oscOut=(chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5; + chan[prevChanCycle].oscOut=CLAMP_VAL((chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5,-32768,32767); if (es5506.voice_end()) { if (prevChanCycle<31) { for (int c=31; c>prevChanCycle; c--) { @@ -404,11 +404,11 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.ex8.had) { - if (chan[i].envelope.k1Slow!=(chan[i].std.ex8.val&1)) { + if (chan[i].envelope.k1Slow!=(bool)(chan[i].std.ex8.val&1)) { chan[i].envelope.k1Slow=chan[i].std.ex8.val&1; chan[i].envChanged.k1Ramp=1; } - if (chan[i].envelope.k2Slow!=(chan[i].std.ex8.val&2)) { + if (chan[i].envelope.k2Slow!=(bool)(chan[i].std.ex8.val&2)) { chan[i].envelope.k2Slow=chan[i].std.ex8.val&2; chan[i].envChanged.k2Ramp=1; } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index c979093a1..0cb74591f 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2499,7 +2499,9 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndCombo(); } + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave); P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); + ImGui::EndDisabled(); P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); if (ins->amiga.useWave) { int len=ins->amiga.waveLen+1; From a601d0eea50f97bd13b01dcfc48977b4602c1a1b Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 3 May 2022 12:39:17 +0900 Subject: [PATCH 11/74] Match previous filter coefficient value to current value in debug menu Progress state: Filter slide up/down, both for K1, K2 --- src/gui/debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 122415a22..b4bf6e764 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -369,8 +369,8 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - K2Offs: %d",ch->k2Offs); ImGui::Text(" - K1Slide: %d",ch->k1Slide); ImGui::Text(" - K2Slide: %d",ch->k2Slide); - ImGui::Text(" - K1Prev: %d",ch->k1Prev); - ImGui::Text(" - K2Prev: %d",ch->k2Prev); + ImGui::Text(" - K1Prev: %.4x",ch->k1Prev); + ImGui::Text(" - K2Prev: %.4x",ch->k2Prev); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- LVol: %.2x",ch->lVol); ImGui::Text("- RVol: %.2x",ch->rVol); From 83e58e02050cfa418aa0a10f362476bf9a672cb5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 3 May 2022 12:55:36 +0900 Subject: [PATCH 12/74] Fix GCC --- src/engine/platform/es5506.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 0bace273a..b0b53b094 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -963,13 +963,13 @@ size_t DivPlatformES5506::getSampleMemUsage(int index) { void DivPlatformES5506::renderSamples() { memset(sampleMem,0,getSampleMemCapacity()); - int memPos=128; + size_t memPos=128; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; unsigned int length=s->length16; // fit sample size to single bank size - if (length>(2097152-64)*sizeof(short)) { - length=(2097152-64)*sizeof(short); + if (length>(4194304-128)) { + length=4194304-128; } if ((memPos&0xc00000)!=((memPos+length+128)&0xc00000)) { memPos=((memPos+0x3fffff)&0xc00000)+128; @@ -979,7 +979,7 @@ void DivPlatformES5506::renderSamples() { break; } if (memPos+length>=(getSampleMemCapacity()-128)) { - memcpy(sampleMem+(memPos/sizeof(short)),s->data16,getSampleMemCapacity()-memPos-128); + memcpy(sampleMem+(memPos/sizeof(short)),s->data16,(getSampleMemCapacity()-128)-memPos); logW("out of ES5506 memory for sample %d!",i); } else { memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length); From 317c4b4f82b54ebcd803c6601bd8c518bea0947a Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 4 May 2022 03:09:58 +0900 Subject: [PATCH 13/74] Prepare for transwave --- src/engine/instrument.h | 34 +++++++++- src/gui/insEdit.cpp | 138 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 166 insertions(+), 6 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 9ad6793fd..0b853c256 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -19,6 +19,8 @@ #ifndef _INSTRUMENT_H #define _INSTRUMENT_H +#include +#include "sample.h" #include "safeWriter.h" #include "dataErrors.h" #include "../ta-utils.h" @@ -308,19 +310,49 @@ struct DivInstrumentAmiga { reversed(false) {} }; + struct TransWave { + bool enable; + bool sliceEnable; + int ind; + unsigned short slice; + + TransWave(): + enable(false), + sliceEnable(false), + ind(0), + slice(0) {} + }; + + struct TransWaveMap { + short ind; + bool reversed; + int loopStart, loopEnd; + DivSampleLoopMode loopMode; + + TransWaveMap(): + ind(-1), + reversed(0), + loopStart(-1), + loopEnd(-1), + loopMode(DIV_SAMPLE_LOOPMODE_FORWARD) {} + }; + short initSample; bool reversed; bool useNoteMap; bool useWave; unsigned char waveLen; NoteMap noteMap[120]; + TransWave transWave; + std::vector transWaveMap; DivInstrumentAmiga(): initSample(0), reversed(false), useNoteMap(false), useWave(false), - waveLen(31) {} + waveLen(31), + transWaveMap(1) {} }; struct DivInstrumentN163 { diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 0cb74591f..2ab9d5230 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2499,9 +2499,11 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndCombo(); } - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave); + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.transWave.enable); P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); ImGui::EndDisabled(); + // Wavetable + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.transWave.enable); P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); if (ins->amiga.useWave) { int len=ins->amiga.waveLen+1; @@ -2512,7 +2514,9 @@ void FurnaceGUI::drawInsEdit() { PARAMETER } } - ImGui::BeginDisabled(ins->amiga.useWave); + ImGui::EndDisabled(); + // Note map + ImGui::BeginDisabled(ins->amiga.useWave||ins->amiga.transWave.enable); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { if (ImGui::BeginTable("NoteMap",4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { @@ -2544,7 +2548,7 @@ void FurnaceGUI::drawInsEdit() { sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##SM",sName.c_str())) { + if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { String id; if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER ins->amiga.noteMap[i].ind=-1; @@ -2560,12 +2564,136 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SF",&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER + if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; } ImGui::TableNextColumn(); - P(ImGui::Checkbox("##SR",&ins->amiga.noteMap[i].reversed)); + P(ImGui::Checkbox(fmt::sprintf("##SampleMap_Reversed_%d",i).c_str(),&ins->amiga.noteMap[i].reversed)); + ImGui::PopID(); + } + ImGui::EndTable(); + } + } + ImGui::EndDisabled(); + // Transwave + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.useNoteMap); + P(ImGui::Checkbox("Use Transwave##UseTransWave",&ins->amiga.transWave.enable)); + if (ins->amiga.transWave.enable) { + int size=ins->amiga.transWaveMap.size(); + if (ImGui::InputInt("Transwave Map Size##TransWaveSize",&size,1,16)) { PARAMETER + if (size<=ins->amiga.transWave.ind) size=ins->amiga.transWave.ind+1; + if (size<1) size=1; + if (size>256) size=256; + if (ins->amiga.transWaveMap.size()!=size) { + ins->amiga.transWaveMap.resize(size,DivInstrumentAmiga::TransWaveMap()); + if (ins->amiga.transWaveMap.capacity()>size) { + ins->amiga.transWaveMap.shrink_to_fit(); + } + } + } + if (ImGui::InputInt("Initial Transwave Index##TransWaveInit",&ins->amiga.transWave.ind,1,16)) { PARAMETER + if (ins->amiga.transWave.ind<1) ins->amiga.transWave.ind=0; + if (ins->amiga.transWave.ind>=ins->amiga.transWaveMap.size()) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; + } + P(ImGui::Checkbox("Use Transwave Slice##UseTransWaveSlice",&ins->amiga.transWave.sliceEnable)); + DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; + if (ins->amiga.transWave.sliceEnable && (ind.ind>=0 && ind.indsong.sampleLen)) { + DivSample* s=e->song.sample[ind.ind]; + double sliceSize=(double)(ind.loopEnd)-(double)(ind.loopStart); + double sliceBound=((double)(s->samples)-sliceSize); + double slicePos=sliceBound*((double)(ins->amiga.transWave.slice)/4095.0); + double sliceStart=slicePos; + double sliceEnd=sliceSize+slicePos; + P(CWSliderScalar("Initial Transwave Slice##TransWaveSliceInit",ImGuiDataType_U16,&ins->amiga.transWave.slice,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE,fmt::sprintf("%d: %.6f - %.6f",ins->amiga.transWave.slice,sliceStart,sliceEnd).c_str())); rightClickable + } + if (ImGui::BeginTable("TransWaveMap",6,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // Number + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); // Sample index + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); // Loop start + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); // Loop end + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); // Loop mode + ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch); // Reversed + + ImGui::TableSetupScrollFreeze(0,1); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + ImGui::Text("Sample"); + ImGui::TableNextColumn(); + ImGui::Text("Loop Start"); + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::TableNextColumn(); + ImGui::Text("Reversed"); + for (int i=0; iamiga.transWaveMap.size(); i++) { + DivInstrumentAmiga::TransWaveMap& transWaveMap=ins->amiga.transWaveMap[i]; + ImGui::TableNextRow(); + ImGui::PushID(fmt::sprintf("TransWaveMap_%d",i).c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%d",i); + ImGui::TableNextColumn(); + if (transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen) { + sName="-- empty --"; + transWaveMap.ind=-1; + } else { + sName=e->song.sample[transWaveMap.ind]->name; + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo(fmt::sprintf("##TransWaveMap_Index_%d",i).c_str(),sName.c_str())) { + String id; + if (ImGui::Selectable("-- empty --",transWaveMap.ind==-1)) { PARAMETER + transWaveMap.ind=-1; + } + for (int j=0; jsong.sampleLen; j++) { + DivSample* s=e->song.sample[j]; + id=fmt::sprintf("%d: %s",j,s->name); + if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER + transWaveMap.ind=j; + if (transWaveMap.loopStart<0 || transWaveMap.loopStart>s->samples) { + transWaveMap.loopStart=s->loopStart; + } + if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>s->samples) { + transWaveMap.loopEnd=s->loopEnd; + } + } + } + ImGui::EndCombo(); + } + ImGui::BeginDisabled(transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopStart_%d",i).c_str(),&transWaveMap.loopStart,256,4096)) { PARAMETER + if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { + if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; + if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; + } + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopEnd_%d",i).c_str(),&transWaveMap.loopEnd,256,4096)) { PARAMETER + if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { + DivSample* s=e->song.sample[transWaveMap.ind]; + if (transWaveMap.loopEnds->samples) transWaveMap.loopEnd=s->samples; + } + } + ImGui::TableNextColumn(); + if (ImGui::RadioButton(fmt::sprintf("Forward##TransWaveMap_LoopMode_Forward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_FORWARD)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; + } + if (ImGui::RadioButton(fmt::sprintf("Backward##TransWaveMap_LoopMode_Backward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_BACKWARD)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_BACKWARD; + } + if (ImGui::RadioButton(fmt::sprintf("Pingpong##TransWaveMap_LoopMode_Pingpong_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_PINGPONG)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } + ImGui::TableNextColumn(); + P(ImGui::Checkbox(fmt::sprintf("##TransWaveMap_Reversed_%d",i).c_str(),&transWaveMap.reversed)); + ImGui::EndDisabled(); ImGui::PopID(); } ImGui::EndTable(); From 4595e18aea70e1d01a3ddf29bf0e19ebe962f441 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 4 May 2022 10:28:30 +0900 Subject: [PATCH 14/74] Oops --- src/engine/playback.cpp | 340 ---------------------------------------- 1 file changed, 340 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ff3926423..4cb224ed6 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -263,348 +263,8 @@ int DivEngine::dispatchCmd(DivCommand c) { } bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { -<<<<<<< HEAD - switch (sysOfChan[ch]) { - case DIV_SYSTEM_YM2612: - case DIV_SYSTEM_YM2612_EXT: - switch (effect) { - case 0x17: // DAC enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_YM2151: - case DIV_SYSTEM_YM2610: - case DIV_SYSTEM_YM2610_EXT: - case DIV_SYSTEM_YM2610B: - case DIV_SYSTEM_YM2610B_EXT: - case DIV_SYSTEM_OPZ: - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_SMS: - switch (effect) { - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_GB: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // sweep params - dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_TIME,ch,effectVal)); - break; - case 0x14: // sweep direction - dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_DIR,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_PCE: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x12: // LFO mode - dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_MODE,ch,effectVal)); - break; - case 0x13: // LFO speed - dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_SPEED,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - break; - case DIV_SYSTEM_NES: - case DIV_SYSTEM_MMC5: - switch (effect) { - case 0x11: // DMC write - dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); - break; - case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // sweep up - dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,0,effectVal)); - break; - case 0x14: // sweep down - dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,1,effectVal)); - break; - case 0x18: // DPCM mode - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_FDS: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // modulation depth - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_DEPTH,ch,effectVal)); - break; - case 0x12: // modulation enable/high - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_HIGH,ch,effectVal)); - break; - case 0x13: // modulation low - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_LOW,ch,effectVal)); - break; - case 0x14: // modulation pos - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_POS,ch,effectVal)); - break; - case 0x15: // modulation wave - dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_WAVE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_OPLL_DRUMS: - case DIV_SYSTEM_OPL_DRUMS: - case DIV_SYSTEM_OPL2_DRUMS: - case DIV_SYSTEM_OPL3_DRUMS: - switch (effect) { - case 0x18: // drum mode toggle - dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); - break; - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_OPLL: - case DIV_SYSTEM_VRC7: - case DIV_SYSTEM_OPL: - case DIV_SYSTEM_OPL2: - case DIV_SYSTEM_OPL3: - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_N163: - switch (effect) { - case 0x10: // select instrument waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // select instrument waveform position in RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_POSITION,ch,effectVal)); - break; - case 0x12: // select instrument waveform length in RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LENGTH,ch,effectVal)); - break; - case 0x13: // change instrument waveform update mode - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_MODE,ch,effectVal)); - break; - case 0x14: // select waveform for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOAD,ch,effectVal)); - break; - case 0x15: // select waveform position for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADPOS,ch,effectVal)); - break; - case 0x16: // select waveform length for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADLEN,ch,effectVal)); - break; - case 0x17: // change waveform load mode - dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADMODE,ch,effectVal)); - break; - case 0x18: // change channel limits - dispatchCmd(DivCommand(DIV_CMD_N163_CHANNEL_LIMIT,ch,effectVal)); - break; - case 0x20: // (global) select waveform for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOAD,ch,effectVal)); - break; - case 0x21: // (global) select waveform position for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADPOS,ch,effectVal)); - break; - case 0x22: // (global) select waveform length for load to RAM - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,ch,effectVal)); - break; - case 0x23: // (global) change waveform load mode - dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_QSOUND: - switch (effect) { - case 0x10: // echo feedback - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_FEEDBACK,ch,effectVal)); - break; - case 0x11: // echo level - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); - break; - case 0x12: // surround - dispatchCmd(DivCommand(DIV_CMD_QSOUND_SURROUND,ch,effectVal)); - break; - default: - if ((effect&0xf0)==0x30) { - dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); - } else { - return false; - } - break; - } - break; - case DIV_SYSTEM_X1_010: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // select envelope shape - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SHAPE,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - break; - case DIV_SYSTEM_SWAN: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x12: // sweep period - dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_TIME,ch,effectVal)); - break; - case 0x13: // sweep amount - dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_AMOUNT,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - break; - case DIV_SYSTEM_VERA: - switch (effect) { - case 0x20: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x22: // duty - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_BUBSYS_WSG: - case DIV_SYSTEM_PET: - case DIV_SYSTEM_VIC20: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_VRC6: - switch (effect) { - case 0x12: // duty or noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x17: // PCM enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - default: - return false; - } - break; - case DIV_SYSTEM_ES5506: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // filter mode - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_MODE,ch,effectVal&3)); - break; - case 0x20: - case 0x21: // envelope ECOUNT - dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_COUNT,ch,((effect&0x01)<<8)|effectVal)); - break; - case 0x22: // envelope LVRAMP - dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_LVRAMP,ch,effectVal)); - break; - case 0x23: // envelope RVRAMP - dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_RVRAMP,ch,effectVal)); - break; - case 0x24: - case 0x25: // envelope K1RAMP - dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K1RAMP,ch,effectVal,effect&0x01)); - break; - case 0x26: - case 0x27: // envelope K2RAMP - dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K2RAMP,ch,effectVal,effect&0x01)); - break; - case 0x28: // filter K1 slide up - case 0x29: // filter K1 slide down - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1_SLIDE,ch,effectVal,effect&0x01)); - break; - case 0x2a: // filter K2 slide up - case 0x2b: // filter K2 slide down - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2_SLIDE,ch,effectVal,effect&0x01)); - break; - default: - if ((effect&0xf0)==0x30) { - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,((effect&0x0f)<<8)|effectVal)); - } else if ((effect&0xf0)==0x40) { - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,((effect&0x0f)<<8)|effectVal)); - } else { - return false; - } - } - break; - default: - return false; - } - return true; -======= if (sysDefs[sysOfChan[ch]]==NULL) return false; return sysDefs[sysOfChan[ch]]->effectFunc(ch,effect,effectVal); ->>>>>>> 4c9b172b50a240efc37aec8bdd4a59972fbf10c4 } bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) { From ab1ac51d68740449242a2177ae50a1646064c63c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 8 May 2022 17:56:52 +0900 Subject: [PATCH 15/74] Fix build, Transwave Checkpoint --- src/engine/instrument.h | 30 ++++++++++++++++++++--- src/engine/platform/es5506.cpp | 25 +++++++------------ src/engine/sysDef.cpp | 3 ++- src/gui/insEdit.cpp | 45 +++++++++++++++++++++++----------- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 0b853c256..a46686a6d 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -302,7 +302,7 @@ struct DivInstrumentAmiga { struct NoteMap { int freq; short ind; - bool reversed; + unsigned char reversed; NoteMap(): freq(0), @@ -316,16 +316,38 @@ struct DivInstrumentAmiga { int ind; unsigned short slice; + // states + double sliceSize; + double sliceBound; + double sliceStart; + double sliceEnd; + + // inlines + inline double slicePos(double slice) { + double pos=sliceBound*slice; + if (sliceStart!=pos) { + sliceStart=pos; + } + if (sliceEnd!=(sliceSize+pos)) + sliceEnd=(sliceSize+pos); + } + return pos; + } + TransWave(): enable(false), sliceEnable(false), ind(0), - slice(0) {} + slice(0), + sliceSize(0), + sliceBound(0), + sliceStart(0), + sliceEnd(0) {} }; struct TransWaveMap { short ind; - bool reversed; + unsigned char reversed; int loopStart, loopEnd; DivSampleLoopMode loopMode; @@ -334,7 +356,7 @@ struct DivInstrumentAmiga { reversed(0), loopStart(-1), loopEnd(-1), - loopMode(DIV_SAMPLE_LOOPMODE_FORWARD) {} + loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} }; short initSample; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index a85a806ae..7aa2a4989 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -622,7 +622,9 @@ int DivPlatformES5506::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins); - chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample; + DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; + chan[c.chan].sample=ins->amiga.useTransWave?transWaveInd.ind: + (ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample); double off=1.0; if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { chan[c.chan].pcm.index=chan[c.chan].sample; @@ -635,31 +637,22 @@ int DivPlatformES5506::dispatch(DivCommand c) { const unsigned int start=s->offES5506<<10; const unsigned int length=s->samples-1; const unsigned int end=start+(length<<11); - chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + chan[c.chan].pcm.loopMode=(ins->amiga.useTransWave&&transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT)?transWaveInd.loopMode:(s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT); chan[c.chan].pcm.freqOffs=off; - chan[c.chan].pcm.reversed=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].reversed:ins->amiga.reversed; + chan[c.chan].pcm.reversed=(ins->amiga.useTransWave&&transWaveInd.reversed!=2)?transWaveInd.reversed:ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].reversed:ins->amiga.reversed; chan[c.chan].pcm.bank=(s->offES5506>>22)&3; chan[c.chan].pcm.start=start; chan[c.chan].pcm.end=end; chan[c.chan].pcm.length=length; chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; - if (ins->type==DIV_INS_ES5506) { // Native format - chan[c.chan].volMacroMax=0xffff; - chan[c.chan].panMacroMax=0xffff; - chan[c.chan].filter=ins->es5506.filter; - chan[c.chan].envelope=ins->es5506.envelope; - } else { // Amiga format - chan[c.chan].volMacroMax=64; - chan[c.chan].panMacroMax=127; - chan[c.chan].filter=DivInstrumentES5506::Filter(); - chan[c.chan].envelope=DivInstrumentES5506::Envelope(); - } + chan[c.chan].volMacroMax=ins->type==DIV_INS_AMIGA?64:0xffff; + chan[c.chan].panMacroMax=ins->type==DIV_INS_AMIGA?127:0xffff; + chan[c.chan].filter=ins->es5506.filter; + chan[c.chan].envelope=ins->es5506.envelope; } else { chan[c.chan].sample=-1; chan[c.chan].pcm.index=-1; - chan[c.chan].volMacroMax=0xffff; - chan[c.chan].panMacroMax=0xffff; chan[c.chan].filter=DivInstrumentES5506::Filter(); chan[c.chan].envelope=DivInstrumentES5506::Envelope(); } diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 405f39d9e..3386b1967 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1755,8 +1755,9 @@ void DivEngine::registerSystems() { } else { return false; } + break; } - break; + return true; } ); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2ab9d5230..b33754a67 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2499,7 +2499,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndCombo(); } - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.transWave.enable); + ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); ImGui::EndDisabled(); // Wavetable @@ -2585,26 +2585,25 @@ void FurnaceGUI::drawInsEdit() { if (size<=ins->amiga.transWave.ind) size=ins->amiga.transWave.ind+1; if (size<1) size=1; if (size>256) size=256; - if (ins->amiga.transWaveMap.size()!=size) { + if (ins->amiga.transWaveMap.size()!=(size_t)(size)) { ins->amiga.transWaveMap.resize(size,DivInstrumentAmiga::TransWaveMap()); - if (ins->amiga.transWaveMap.capacity()>size) { + if (ins->amiga.transWaveMap.capacity()>(size_t)(size)) { ins->amiga.transWaveMap.shrink_to_fit(); } } } if (ImGui::InputInt("Initial Transwave Index##TransWaveInit",&ins->amiga.transWave.ind,1,16)) { PARAMETER if (ins->amiga.transWave.ind<1) ins->amiga.transWave.ind=0; - if (ins->amiga.transWave.ind>=ins->amiga.transWaveMap.size()) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; + if (ins->amiga.transWave.ind>=(int)(ins->amiga.transWaveMap.size())) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; } P(ImGui::Checkbox("Use Transwave Slice##UseTransWaveSlice",&ins->amiga.transWave.sliceEnable)); DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; if (ins->amiga.transWave.sliceEnable && (ind.ind>=0 && ind.indsong.sampleLen)) { DivSample* s=e->song.sample[ind.ind]; - double sliceSize=(double)(ind.loopEnd)-(double)(ind.loopStart); - double sliceBound=((double)(s->samples)-sliceSize); - double slicePos=sliceBound*((double)(ins->amiga.transWave.slice)/4095.0); - double sliceStart=slicePos; - double sliceEnd=sliceSize+slicePos; + double sliceInit=(double)(ins->amiga.transWave.slice)/4095.0; + double slicePos=ins->amiga.transWave.slicePos(sliceInit); + double sliceStart=ins->amiga.transWave.sliceStart; + double sliceEnd=ins->amiga.transWave.sliceEnd; P(CWSliderScalar("Initial Transwave Slice##TransWaveSliceInit",ImGuiDataType_U16,&ins->amiga.transWave.slice,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE,fmt::sprintf("%d: %.6f - %.6f",ins->amiga.transWave.slice,sliceStart,sliceEnd).c_str())); rightClickable } if (ImGui::BeginTable("TransWaveMap",6,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { @@ -2629,7 +2628,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Loop Mode"); ImGui::TableNextColumn(); ImGui::Text("Reversed"); - for (int i=0; iamiga.transWaveMap.size(); i++) { + for (size_t i=0; iamiga.transWaveMap.size(); i++) { DivInstrumentAmiga::TransWaveMap& transWaveMap=ins->amiga.transWaveMap[i]; ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("TransWaveMap_%d",i).c_str()); @@ -2653,12 +2652,14 @@ void FurnaceGUI::drawInsEdit() { id=fmt::sprintf("%d: %s",j,s->name); if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER transWaveMap.ind=j; - if (transWaveMap.loopStart<0 || transWaveMap.loopStart>s->samples) { + if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { transWaveMap.loopStart=s->loopStart; } - if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>s->samples) { + if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { transWaveMap.loopEnd=s->loopEnd; } + transWaveMap.sliceSize=(double)(transWaveMap.loopEnd)-(double)(transWaveMap.loopStart); + transWaveMap.sliceBound=((double)(s->samples)-transWaveMap.sliceSize); } } ImGui::EndCombo(); @@ -2668,8 +2669,11 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopStart_%d",i).c_str(),&transWaveMap.loopStart,256,4096)) { PARAMETER if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { + DivSample* s=e->song.sample[transWaveMap.ind]; if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; + transWaveMap.sliceSize=(double)(transWaveMap.loopEnd)-(double)(transWaveMap.loopStart); + transWaveMap.sliceBound=((double)(s->samples)-transWaveMap.sliceSize); } } ImGui::TableNextColumn(); @@ -2678,7 +2682,9 @@ void FurnaceGUI::drawInsEdit() { if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { DivSample* s=e->song.sample[transWaveMap.ind]; if (transWaveMap.loopEnds->samples) transWaveMap.loopEnd=s->samples; + if (transWaveMap.loopEnd>(int)(s->samples)) transWaveMap.loopEnd=s->samples; + transWaveMap.sliceSize=(double)(transWaveMap.loopEnd)-(double)(transWaveMap.loopStart); + transWaveMap.sliceBound=((double)(s->samples)-transWaveMap.sliceSize); } } ImGui::TableNextColumn(); @@ -2691,8 +2697,19 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::RadioButton(fmt::sprintf("Pingpong##TransWaveMap_LoopMode_Pingpong_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_PINGPONG)) { MARK_MODIFIED transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; } + if (ImGui::RadioButton(fmt::sprintf("Use sample setting##TransWaveMap_LoopMode_Default_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; + } ImGui::TableNextColumn(); - P(ImGui::Checkbox(fmt::sprintf("##TransWaveMap_Reversed_%d",i).c_str(),&transWaveMap.reversed)); + if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==0)) { MARK_MODIFIED + transWaveMap.reversed=0; + } + if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==1)) { MARK_MODIFIED + transWaveMap.reversed=1; + } + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==2)) { MARK_MODIFIED + transWaveMap.reversed=2; + } ImGui::EndDisabled(); ImGui::PopID(); } From 23f086fda6384fe5d76809628fa5be29ba58ea68 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 11 May 2022 15:10:21 +0900 Subject: [PATCH 16/74] Allow 8 bit filter write, Linear pitch support --- src/engine/dispatch.h | 4 +-- src/engine/platform/es5506.cpp | 63 ++++++++++++++++++++-------------- src/engine/sysDef.cpp | 36 ++++++++++++------- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index d212b0900..4bedf6abf 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -170,8 +170,8 @@ enum DivDispatchCmds { DIV_CMD_N163_GLOBAL_WAVE_LOADMODE, DIV_CMD_ES5506_FILTER_MODE, // (value) - DIV_CMD_ES5506_FILTER_K1, // (value) - DIV_CMD_ES5506_FILTER_K2, // (value) + DIV_CMD_ES5506_FILTER_K1, // (value, mask) + DIV_CMD_ES5506_FILTER_K2, // (value, mask) DIV_CMD_ES5506_FILTER_K1_SLIDE, // (value, negative) DIV_CMD_ES5506_FILTER_K2_SLIDE, // (value, negative) DIV_CMD_ES5506_ENVELOPE_COUNT, // (count) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 6129bfe46..7e74caeea 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -23,8 +23,8 @@ #include #include -#define CHIP_FREQBASE (16*2048*(chanMax+1)) -#define NOTE_ES5506(c,note) (chan[c].pcm.freqOffs*NOTE_FREQUENCY(note)) +#define PITCH_OFFSET ((double)(16*2048*(chanMax+1))) +#define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) #define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }} #define rRead(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} @@ -111,6 +111,30 @@ const char* DivPlatformES5506::getEffectName(unsigned char effect) { case 0x11: return "11xx: Set filter mode (00 to 03)"; break; + case 0x14: + return "14xx: Set filter coefficient K1 low byte"; + break; + case 0x15: + return "15xx: Set filter coefficient K1 high byte"; + break; + case 0x16: + return "16xx: Set filter coefficient K2 low byte"; + break; + case 0x17: + return "17xx: Set filter coefficient K2 high byte"; + break; + case 0x18: + return "18xx: Set filter coefficient K1 slide up"; + break; + case 0x19: + return "19xx: Set filter coefficient K1 slide down"; + break; + case 0x1a: + return "1axx: Set filter coefficient K2 slide up"; + break; + case 0x1b: + return "1bxx: Set filter coefficient K2 slide down"; + break; case 0x20: return "20xx: Set envelope count (000 to 0FF)"; break; @@ -124,35 +148,24 @@ const char* DivPlatformES5506::getEffectName(unsigned char effect) { return "23xx: Set envelope right volume ramp (signed)"; break; case 0x24: - return "24xx: Set envelope k1 ramp (signed)"; + return "24xx: Set envelope filter coefficient k1 ramp (signed)"; break; case 0x25: - return "25xx: Set envelope k1 ramp (signed, slower)"; + return "25xx: Set envelope filter coefficient k1 ramp (signed, slower)"; break; case 0x26: - return "26xx: Set envelope k2 ramp (signed)"; + return "26xx: Set envelope filter coefficient k2 ramp (signed)"; break; case 0x27: - return "27xx: Set envelope k2 ramp (signed, slower)"; - break; - case 0x28: - return "28xx: Set filter K1 slide up"; - break; - case 0x29: - return "29xx: Set filter K1 slide down"; - break; - case 0x2a: - return "28xx: Set filter K2 slide up"; - break; - case 0x2b: - return "29xx: Set filter K2 slide down"; + return "27xx: Set envelope filter coefficient k2 ramp (signed, slower)"; break; default: if ((effect&0xf0)==0x30) { - return "3xxx: Set filter K1"; + return "3xxx: Set filter coefficient K1"; } else if ((effect&0xf0)==0x40) { - return "4xxx: Set filter K2"; + return "4xxx: Set filter coefficient K2"; } + break; } return NULL; } @@ -480,7 +493,7 @@ void DivPlatformES5506::tick(bool sysTick) { const unsigned int length=s->samples-1; const unsigned int end=start+(length<<11); chan[i].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - chan[i].pcm.freqOffs=off; + chan[i].pcm.freqOffs=PITCH_OFFSET*off; chan[i].pcm.reversed=ins->amiga.reversed; chan[i].pcm.bank=(s->offES5506>>22)&3; chan[i].pcm.start=start; @@ -565,7 +578,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].noteChanged.changed=0; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=CLAMP_VAL(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2),0,0x1ffff); + chan[i].freq=CLAMP_VAL(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,chan[c].pcm.freqOffs),0,0x1ffff); if (chan[i].keyOn) { if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { chan[i].k1Prev=0xffff; @@ -707,7 +720,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { const unsigned int length=s->samples-1; const unsigned int end=start+(length<<11); chan[c.chan].pcm.loopMode=loopMode; - chan[c.chan].pcm.freqOffs=off; + chan[c.chan].pcm.freqOffs=PITCH_OFFSET*off; chan[c.chan].pcm.reversed=reversed; chan[c.chan].pcm.bank=(s->offES5506>>22)&3; chan[c.chan].pcm.start=start; @@ -815,11 +828,11 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].filterChanged.mode=1; break; case DIV_CMD_ES5506_FILTER_K1: - chan[c.chan].filter.k1=(chan[c.chan].filter.k1&0xf)|((c.value&0xfff)<<4); + chan[c.chan].filter.k1=(chan[c.chan].filter.k1&~c.value2)|(c.value&c.value2); chan[c.chan].filterChanged.k1=1; break; case DIV_CMD_ES5506_FILTER_K2: - chan[c.chan].filter.k2=(chan[c.chan].filter.k2&0xf)|((c.value&0xfff)<<4); + chan[c.chan].filter.k2=(chan[c.chan].filter.k2&~c.value2)|(c.value&c.value2); chan[c.chan].filterChanged.k2=1; break; case DIV_CMD_ES5506_FILTER_K1_SLIDE: diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 5fe705fbd..bd2e81539 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1730,6 +1730,26 @@ void DivEngine::registerSystems() { case 0x11: // filter mode dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_MODE,ch,effectVal&3)); break; + case 0x14: // filter coefficient K1, 8 bit LSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,effectVal&0xff,0x00ff)); + break; + case 0x15: // filter coefficient K1, 8 bit MSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,(effectVal&0xff)<<8,0xff00)); + break; + case 0x16: // filter coefficient K2, 8 bit LSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,effectVal&0xff,0x00ff)); + break; + case 0x17: // filter coefficient K2, 8 bit MSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,(effectVal&0xff)<<8,0xff00)); + break; + case 0x18: // filter coefficient K1 slide up + case 0x19: // filter coefficient K1 slide down + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1_SLIDE,ch,effectVal,effect&0x01)); + break; + case 0x1a: // filter coefficient K2 slide up + case 0x1b: // filter coefficient K2 slide down + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2_SLIDE,ch,effectVal,effect&0x01)); + break; case 0x20: case 0x21: // envelope ECOUNT dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_COUNT,ch,((effect&0x01)<<8)|effectVal)); @@ -1748,19 +1768,11 @@ void DivEngine::registerSystems() { case 0x27: // envelope K2RAMP dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K2RAMP,ch,effectVal,effect&0x01)); break; - case 0x28: // filter K1 slide up - case 0x29: // filter K1 slide down - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1_SLIDE,ch,effectVal,effect&0x01)); - break; - case 0x2a: // filter K2 slide up - case 0x2b: // filter K2 slide down - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2_SLIDE,ch,effectVal,effect&0x01)); - break; default: - if ((effect&0xf0)==0x30) { - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,((effect&0x0f)<<8)|effectVal)); - } else if ((effect&0xf0)==0x40) { - dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,((effect&0x0f)<<8)|effectVal)); + if ((effect&0xf0)==0x30) { // filter coefficient K1, 12 bit MSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,((effect&0x0f)<<12)|((effectVal&0xff)<<4),0xfff0)); + } else if ((effect&0xf0)==0x40) { // filter coefficient K2, 12 bit MSB + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,((effect&0x0f)<<12)|((effectVal&0xff)<<4),0xfff0)); } else { return false; } From 3b411cd14fe2b01662e2a748706c774ef746577c Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 31 May 2022 13:48:35 +0900 Subject: [PATCH 17/74] Fix dead link, Frequency, Instrument editor related issue --- src/engine/platform/es5506.cpp | 18 +- src/engine/platform/es5506.h | 4 +- src/engine/platform/sound/es550x/es5504.cpp | 2 +- src/engine/platform/sound/es550x/es5504.hpp | 2 +- src/engine/platform/sound/es550x/es5505.cpp | 2 +- src/engine/platform/sound/es550x/es5505.hpp | 2 +- src/engine/platform/sound/es550x/es5506.cpp | 2 +- src/engine/platform/sound/es550x/es5506.hpp | 2 +- src/engine/platform/sound/es550x/es550x.cpp | 2 +- src/engine/platform/sound/es550x/es550x.hpp | 134 +---- .../platform/sound/es550x/es550x_alu.cpp | 2 +- .../platform/sound/es550x/es550x_filter.cpp | 2 +- src/engine/platform/sound/es550x/util.hpp | 139 ++++++ src/engine/platform/sound/k005289/k005289.cpp | 2 +- src/engine/platform/sound/k005289/k005289.hpp | 2 +- src/engine/platform/sound/n163/n163.cpp | 2 +- src/engine/platform/sound/n163/n163.hpp | 2 +- src/engine/platform/sound/oki/msm6295.cpp | 2 +- src/engine/platform/sound/oki/msm6295.hpp | 2 +- src/engine/platform/sound/oki/util.hpp | 4 +- src/engine/platform/sound/oki/vox.hpp | 2 +- src/engine/platform/sound/scc/scc.cpp | 2 +- src/engine/platform/sound/scc/scc.hpp | 2 +- src/engine/platform/sound/vrcvi/vrcvi.cpp | 2 +- src/engine/platform/sound/vrcvi/vrcvi.hpp | 2 +- src/engine/platform/sound/x1_010/x1_010.cpp | 4 +- src/engine/platform/sound/x1_010/x1_010.hpp | 4 +- src/engine/platform/su.cpp | 4 +- src/gui/debug.cpp | 2 +- src/gui/insEdit.cpp | 463 ++++++++++-------- 30 files changed, 432 insertions(+), 384 deletions(-) create mode 100644 src/engine/platform/sound/es550x/util.hpp diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index a9e5d4397..12f15740f 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -296,7 +296,7 @@ void DivPlatformES5506::e_pin(bool state) DivSample* s=parent->getSample(sample); // get frequency offset double off=1.0; - double center=s->centerRate; + double center=(double)s->centerRate; if (center<1) { off=1.0; } else { @@ -710,7 +710,7 @@ void DivPlatformES5506::tick(bool sysTick) { DivSample* s=parent->getSample(sample); // get frequency offset double off=1.0; - double center=s->centerRate; + double center=(double)s->centerRate; if (center<1) { off=1.0; } else { @@ -884,33 +884,30 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].noteChanged.offs) { if (chan[i].pcm.freqOffs!=chan[i].pcm.nextFreqOffs) { chan[i].pcm.freqOffs=chan[i].pcm.nextFreqOffs; - const int nextFreq=NOTE_ES5506(i,chan[i].prevNote); + const int nextFreq=NOTE_ES5506(i,chan[i].currNote); if (chan[i].nextFreq!=nextFreq) { chan[i].nextFreq=nextFreq; chan[i].noteChanged.freq=1; } } - chan[i].noteChanged.offs=0; } if (chan[i].noteChanged.note) { - if (chan[i].prevNote!=chan[i].nextNote) { - chan[i].prevNote=chan[i].nextNote; + if (chan[i].currNote!=chan[i].nextNote) { + chan[i].currNote=chan[i].nextNote; const int nextFreq=NOTE_ES5506(i,chan[i].nextNote); if (chan[i].nextFreq!=nextFreq) { chan[i].nextFreq=nextFreq; chan[i].noteChanged.freq=1; } } - chan[i].noteChanged.note=0; } if (chan[i].noteChanged.freq) { if (chan[i].baseFreq!=chan[i].nextFreq) { chan[i].baseFreq=chan[i].nextFreq; chan[i].freqChanged=true; } - chan[i].noteChanged.freq=0; } - chan[i].noteChanged.dummy=0; + chan[i].noteChanged.changed=0; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=CLAMP_VAL(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,chan[i].pcm.freqOffs),0,0x1ffff); @@ -1023,7 +1020,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { DivSample* s=parent->getSample(sample); // get frequency offset double off=1.0; - double center=s->centerRate; + double center=(double)s->centerRate; if (center<1) { off=1.0; } else { @@ -1087,6 +1084,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].nextNote=chan[c.chan].note; + chan[c.chan].pcm.nextFreqOffs=chan[c.chan].pcm.freqOffs; chan[c.chan].freqChanged=true; chan[c.chan].noteChanged.changed=0xff; chan[c.chan].volChanged.changed=0xff; diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 4c4ad341b..c5c5487da 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -62,7 +62,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { loopEnd(0), loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} } pcm; - int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, prevNote, ins, wave; + int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, currNote, ins, wave; unsigned int volMacroMax, panMacroMax; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop, isTranswave, transwaveIRQ; unsigned int cr; @@ -173,7 +173,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { pitch2(0), note(0), nextNote(0), - prevNote(0), + currNote(0), ins(-1), wave(-1), volMacroMax(0xffff), diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp index b7b808ac5..2ffc7ab5c 100644 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504 emulation core diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp index b9423dfc0..bbf74b2cb 100644 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ b/src/engine/platform/sound/es550x/es5504.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504 emulation core diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index 7ab2321ea..4a6ab8988 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5505 emulation core diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp index 25c06beeb..b42322f62 100644 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504 emulation core diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 41f62b317..251b158a2 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5506 emulation core diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp index 3940fea49..9aaee75b2 100644 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504 emulation core diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp index c65a1ea69..5d83fd522 100644 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ b/src/engine/platform/sound/es550x/es550x.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504/ES5505/ES5506 emulation core diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index 52aba0f82..ad02c2ff1 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504/ES5505/ES5506 emulation core @@ -8,141 +8,16 @@ See es550x.cpp for more info */ -#include -#include - #ifndef _VGSOUND_EMU_ES550X_HPP #define _VGSOUND_EMU_ES550X_HPP #pragma once -namespace es550x -{ - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned int u32; - typedef unsigned long long u64; - typedef signed char s8; - typedef signed short s16; - typedef signed int s32; - - // get bitfield, bitfield(input, position, len) - template T bitfield(T in, u8 pos, u8 len = 1) - { - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); - } - - // get sign extended value, sign_ext(input, len) - template T sign_ext(T in, u8 len) - { - len = std::max(0, (8 * sizeof(T)) - len); - return T(T(in) << len) >> len; - } - - // std::clamp is only for C++17 or later; I use my own code - template T clamp(T in, T min, T max) - { - return std::min(std::max(in, min), max); - } - - template - struct clock_pulse_t - { - void reset(T init = InitWidth) - { - m_edge.reset(); - m_width = m_width_latch = m_counter = init; - m_cycle = 0; - } - - bool tick(T width = 0) - { - bool carry = ((--m_counter) <= 0); - if (carry) - { - if (!width) - m_width = m_width_latch; - else - m_width = width; // reset width - m_counter = m_width; - m_cycle = 0; - } - else - m_cycle++; - - m_edge.tick(carry); - return carry; - } - - void set_width(T width) { m_width = width; } - void set_width_latch(T width) { m_width_latch = width; } - - // Accessors - bool current_edge() { return m_edge.m_current; } - bool rising_edge() { return m_edge.m_rising; } - bool falling_edge() { return m_edge.m_rising; } - T cycle() { return m_cycle; } - - struct edge_t - { - edge_t() - : m_current(InitEdge ^ 1) - , m_previous(InitEdge) - , m_rising(0) - , m_falling(0) - , m_changed(0) - { - set(InitEdge); - } - - void tick(bool toggle) - { - u8 current = m_current; - if (toggle) - current ^= 1; - set(current); - } - - void set(u8 edge) - { - edge &= 1; - m_rising = m_falling = m_changed = 0; - if (m_current != edge) - { - m_changed = 1; - if (m_current && (!edge)) - m_falling = 1; - else if ((!m_current) && edge) - m_rising = 1; - m_current = edge; - } - m_previous = m_current; - } - - void reset() - { - m_previous = InitEdge; - m_current = InitEdge ^ 1; - set(InitEdge); - } - - u8 m_current : 1; // current edge - u8 m_previous : 1; // previous edge - u8 m_rising : 1; // rising edge - u8 m_falling : 1; // falling edge - u8 m_changed : 1; // changed flag - }; - - edge_t m_edge; - T m_width = InitWidth; // clock pulse width - T m_width_latch = InitWidth; // clock pulse width latch - T m_counter = InitWidth; // clock counter - T m_cycle = 0; // clock cycle - }; -}; +#include +#include +#include "util.hpp" // ES5504/ES5505/ES5506 interface -using namespace es550x; class es550x_intf { public: @@ -158,7 +33,6 @@ public: }; // Shared functions for ES5504/ES5505/ES5506 -using namespace es550x; class es550x_shared_core { friend class es550x_intf; // es550x specific memory interface diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp index 7e1ec05c4..cf22517ec 100644 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ b/src/engine/platform/sound/es550x/es550x_alu.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp index abf16b4d5..45fd0571f 100644 --- a/src/engine/platform/sound/es550x/es550x_filter.cpp +++ b/src/engine/platform/sound/es550x/es550x_filter.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core diff --git a/src/engine/platform/sound/es550x/util.hpp b/src/engine/platform/sound/es550x/util.hpp new file mode 100644 index 000000000..a66f4ca8e --- /dev/null +++ b/src/engine/platform/sound/es550x/util.hpp @@ -0,0 +1,139 @@ +/* + License: BSD-3-Clause + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details + + Copyright holder(s): cam900 + Various core utilities for vgsound_emu +*/ + +#ifndef _VGSOUND_EMU_CORE_UTIL_HPP +#define _VGSOUND_EMU_CORE_UTIL_HPP + +#pragma once + +#include +#include + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; + +// get bitfield, bitfield(input, position, len) +template T bitfield(T in, u8 pos, u8 len = 1) +{ + return (in >> pos) & (len ? (T(1 << len) - 1) : 1); +} + +// get sign extended value, sign_ext(input, len) +template T sign_ext(T in, u8 len) +{ + len = std::max(0, (8 * sizeof(T)) - len); + return T(T(in) << len) >> len; +} + +// std::clamp is only for C++17 or later; I use my own code +template T clamp(T in, T min, T max) +{ + return std::min(std::max(in, min), max); +} + +template +struct clock_pulse_t +{ + void reset(T init = InitWidth) + { + m_edge.reset(); + m_width = m_width_latch = m_counter = init; + m_cycle = 0; + } + + bool tick(T width = 0) + { + bool carry = ((--m_counter) <= 0); + if (carry) + { + if (!width) + m_width = m_width_latch; + else + m_width = width; // reset width + m_counter = m_width; + m_cycle = 0; + } + else + m_cycle++; + + m_edge.tick(carry); + return carry; + } + + void set_width(T width) { m_width = width; } + void set_width_latch(T width) { m_width_latch = width; } + + // Accessors + bool current_edge() { return m_edge.m_current; } + bool rising_edge() { return m_edge.m_rising; } + bool falling_edge() { return m_edge.m_rising; } + T cycle() { return m_cycle; } + + struct edge_t + { + edge_t() + : m_current(InitEdge ^ 1) + , m_previous(InitEdge) + , m_rising(0) + , m_falling(0) + , m_changed(0) + { + set(InitEdge); + } + + void tick(bool toggle) + { + u8 current = m_current; + if (toggle) + current ^= 1; + set(current); + } + + void set(u8 edge) + { + edge &= 1; + m_rising = m_falling = m_changed = 0; + if (m_current != edge) + { + m_changed = 1; + if (m_current && (!edge)) + m_falling = 1; + else if ((!m_current) && edge) + m_rising = 1; + m_current = edge; + } + m_previous = m_current; + } + + void reset() + { + m_previous = InitEdge; + m_current = InitEdge ^ 1; + set(InitEdge); + } + + u8 m_current : 1; // current edge + u8 m_previous : 1; // previous edge + u8 m_rising : 1; // rising edge + u8 m_falling : 1; // falling edge + u8 m_changed : 1; // changed flag + }; + + edge_t m_edge; + T m_width = InitWidth; // clock pulse width + T m_width_latch = InitWidth; // clock pulse width latch + T m_counter = InitWidth; // clock counter + T m_cycle = 0; // clock cycle +}; + +#endif diff --git a/src/engine/platform/sound/k005289/k005289.cpp b/src/engine/platform/sound/k005289/k005289.cpp index 4763b63f0..6c7164683 100644 --- a/src/engine/platform/sound/k005289/k005289.cpp +++ b/src/engine/platform/sound/k005289/k005289.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami K005289 emulation core diff --git a/src/engine/platform/sound/k005289/k005289.hpp b/src/engine/platform/sound/k005289/k005289.hpp index fe5d50ac9..69c48eebb 100644 --- a/src/engine/platform/sound/k005289/k005289.hpp +++ b/src/engine/platform/sound/k005289/k005289.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami K005289 emulation core diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp index e6801fc1f..7ece05f6c 100644 --- a/src/engine/platform/sound/n163/n163.cpp +++ b/src/engine/platform/sound/n163/n163.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Namco 163 Sound emulation core diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp index aa059206b..921d9cc6f 100644 --- a/src/engine/platform/sound/n163/n163.hpp +++ b/src/engine/platform/sound/n163/n163.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Namco 163 Sound emulation core diff --git a/src/engine/platform/sound/oki/msm6295.cpp b/src/engine/platform/sound/oki/msm6295.cpp index 7a455e1b5..4ae9541a9 100644 --- a/src/engine/platform/sound/oki/msm6295.cpp +++ b/src/engine/platform/sound/oki/msm6295.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 OKI MSM6295 emulation core diff --git a/src/engine/platform/sound/oki/msm6295.hpp b/src/engine/platform/sound/oki/msm6295.hpp index f5684a29b..172c01947 100644 --- a/src/engine/platform/sound/oki/msm6295.hpp +++ b/src/engine/platform/sound/oki/msm6295.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 OKI MSM6295 emulation core diff --git a/src/engine/platform/sound/oki/util.hpp b/src/engine/platform/sound/oki/util.hpp index 71e10cbe7..fa7d36083 100644 --- a/src/engine/platform/sound/oki/util.hpp +++ b/src/engine/platform/sound/oki/util.hpp @@ -1,8 +1,8 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - Copyright holders: cam900 + Copyright holder(s): cam900 Various core utilities for vgsound_emu */ diff --git a/src/engine/platform/sound/oki/vox.hpp b/src/engine/platform/sound/oki/vox.hpp index b1fc6e236..b4ea7d090 100644 --- a/src/engine/platform/sound/oki/vox.hpp +++ b/src/engine/platform/sound/oki/vox.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Dialogic ADPCM core diff --git a/src/engine/platform/sound/scc/scc.cpp b/src/engine/platform/sound/scc/scc.cpp index b9758fae4..b045c6372 100644 --- a/src/engine/platform/sound/scc/scc.cpp +++ b/src/engine/platform/sound/scc/scc.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami SCC emulation core diff --git a/src/engine/platform/sound/scc/scc.hpp b/src/engine/platform/sound/scc/scc.hpp index e696c403d..e5b737bec 100644 --- a/src/engine/platform/sound/scc/scc.hpp +++ b/src/engine/platform/sound/scc/scc.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami SCC emulation core diff --git a/src/engine/platform/sound/vrcvi/vrcvi.cpp b/src/engine/platform/sound/vrcvi/vrcvi.cpp index a6561db80..d0b491869 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.cpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.cpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami VRC VI sound emulation core diff --git a/src/engine/platform/sound/vrcvi/vrcvi.hpp b/src/engine/platform/sound/vrcvi/vrcvi.hpp index d88ba7cf9..cec160dae 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.hpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.hpp @@ -1,6 +1,6 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 Konami VRC VI sound emulation core diff --git a/src/engine/platform/sound/x1_010/x1_010.cpp b/src/engine/platform/sound/x1_010/x1_010.cpp index 150928e66..b667008d1 100644 --- a/src/engine/platform/sound/x1_010/x1_010.cpp +++ b/src/engine/platform/sound/x1_010/x1_010.cpp @@ -1,8 +1,8 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - Copyright holders: cam900 + Copyright holder(s): cam900 Seta/Allumer X1-010 Emulation core the chip has 16 voices, all voices can be switchable to Wavetable or PCM sample playback mode. diff --git a/src/engine/platform/sound/x1_010/x1_010.hpp b/src/engine/platform/sound/x1_010/x1_010.hpp index f208611da..59e33e39d 100644 --- a/src/engine/platform/sound/x1_010/x1_010.hpp +++ b/src/engine/platform/sound/x1_010/x1_010.hpp @@ -1,8 +1,8 @@ /* License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/LICENSE for more details + see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - Copyright holders: cam900 + Copyright holder(s): cam900 Seta/Allumer X1-010 Emulation core See x1_010.cpp for more info. diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index b9e7f319a..c294e179f 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -213,7 +213,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); if (sample!=NULL) { - unsigned int sampleEnd=sample->offSU+(s->isLoopable()?sample->loopEnd:sample->samples); + unsigned int sampleEnd=sample->offSU+(sample->isLoopable()?sample->loopEnd:sample->samples); unsigned int off=sample->offSU+chan[i].hasOffset; chan[i].hasOffset=0; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; @@ -221,7 +221,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chWrite(i,0x0b,off>>8); chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0d,sampleEnd>>8); - if (s->isLoopable()) { + if (sample->isLoopable()) { unsigned int sampleLoop=sample->offSU+sample->loopStart; if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1; chWrite(i,0x0e,sampleLoop&0xff); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 269b4284a..991fc7f7d 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -344,7 +344,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("* note: %d",ch->note); ImGui::Text(" - next: %d",ch->nextNote); - ImGui::Text(" - prev: %d",ch->prevNote); + ImGui::Text(" - curr: %d",ch->currNote); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- VolMacroMax: %d",ch->volMacroMax); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 279d1c576..3bf6befbb 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2587,252 +2587,289 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("Sample")) { - String sName; - if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { - sName="none selected"; - } else { - sName=e->song.sample[ins->amiga.initSample]->name; - } - if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { - String id; - for (int i=0; isong.sampleLen; i++) { - id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER - ins->amiga.initSample=i; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ES5506) { + if (ImGui::BeginTabItem("Sample")) { + String sName; + if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { + sName="none selected"; + } else { + sName=e->song.sample[ins->amiga.initSample]->name; + } + if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { + String id; + for (int i=0; isong.sampleLen; i++) { + id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); + if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER + ins->amiga.initSample=i; + } + } + ImGui::EndCombo(); + } + ImGui::BeginDisabled(ins->amiga.useWave); + P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); + ImGui::EndDisabled(); + // Wavetable + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.transWave.enable); + P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); + if (ins->amiga.useWave) { + int len=ins->amiga.waveLen+1; + if (ImGui::InputInt("Width",&len,2,16)) { + if (len<2) len=2; + if (len>256) len=256; + ins->amiga.waveLen=(len&(~1))-1; + PARAMETER } } - ImGui::EndCombo(); - } - ImGui::BeginDisabled(ins->amiga.useWave); - P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); - ImGui::EndDisabled(); - // Wavetable - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.transWave.enable); - P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); - if (ins->amiga.useWave) { - int len=ins->amiga.waveLen+1; - if (ImGui::InputInt("Width",&len,2,16)) { - if (len<2) len=2; - if (len>256) len=256; - ins->amiga.waveLen=(len&(~1))-1; - PARAMETER - } - } - ImGui::EndDisabled(); - // Note map - ImGui::BeginDisabled(ins->amiga.useWave||ins->amiga.transWave.enable); - P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); - if (ins->amiga.useNoteMap) { - if (ImGui::BeginTable("NoteMap",4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); + ImGui::EndDisabled(); + // Note map + ImGui::BeginDisabled(ins->amiga.useWave||ins->amiga.transWave.enable); + P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); + if (ins->amiga.useNoteMap) { + if (ImGui::BeginTable("NoteMap",4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupScrollFreeze(0,1); + ImGui::TableSetupScrollFreeze(0,1); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::Text("Sample"); - ImGui::TableNextColumn(); - ImGui::Text("Frequency"); - ImGui::TableNextColumn(); - ImGui::Text("Reversed"); - for (int i=0; i<120; i++) { - ImGui::TableNextRow(); - ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); - ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i].ind<0 || ins->amiga.noteMap[i].ind>=e->song.sampleLen) { - sName="-- empty --"; - ins->amiga.noteMap[i].ind=-1; - } else { - sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { - String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER + ImGui::Text("Sample"); + ImGui::TableNextColumn(); + ImGui::Text("Frequency"); + ImGui::TableNextColumn(); + ImGui::Text("Reversed"); + for (int i=0; i<120; i++) { + ImGui::TableNextRow(); + ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%s",noteNames[60+i]); + ImGui::TableNextColumn(); + if (ins->amiga.noteMap[i].ind<0 || ins->amiga.noteMap[i].ind>=e->song.sampleLen) { + sName="-- empty --"; ins->amiga.noteMap[i].ind=-1; + } else { + sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; } - for (int j=0; jsong.sampleLen; j++) { - id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].ind==j)) { PARAMETER - ins->amiga.noteMap[i].ind=j; - if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { + String id; + if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER + ins->amiga.noteMap[i].ind=-1; + } + for (int j=0; jsong.sampleLen; j++) { + id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); + if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].ind==j)) { PARAMETER + ins->amiga.noteMap[i].ind=j; + if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + } + } + ImGui::EndCombo(); + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER + if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; + if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; + } + ImGui::TableNextColumn(); + if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==0)) { MARK_MODIFIED + ins->amiga.noteMap[i].reversed=0; + } + if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==1)) { MARK_MODIFIED + ins->amiga.noteMap[i].reversed=1; + } + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),ins->amiga.noteMap[i].reversed==2)) { MARK_MODIFIED + ins->amiga.noteMap[i].reversed=2; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + } + ImGui::EndDisabled(); + // Transwave + ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.useNoteMap); + P(ImGui::Checkbox("Use Transwave##UseTransWave",&ins->amiga.transWave.enable)); + if (ins->amiga.transWave.enable) { + int size=ins->amiga.transWaveMap.size(); + if (ImGui::InputInt("Transwave Map Size##TransWaveSize",&size,1,16)) { PARAMETER + if (size<=ins->amiga.transWave.ind) size=ins->amiga.transWave.ind+1; + if (size<1) size=1; + if (size>256) size=256; + if (ins->amiga.transWaveMap.size()!=(size_t)(size)) { + ins->amiga.transWaveMap.resize(size,DivInstrumentAmiga::TransWaveMap()); + if (ins->amiga.transWaveMap.capacity()>(size_t)(size)) { + ins->amiga.transWaveMap.shrink_to_fit(); + } + } + } + if (ImGui::InputInt("Initial Transwave Index##TransWaveInit",&ins->amiga.transWave.ind,1,16)) { PARAMETER + if (ins->amiga.transWave.ind<1) ins->amiga.transWave.ind=0; + if (ins->amiga.transWave.ind>=(int)(ins->amiga.transWaveMap.size())) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; + if (ins->amiga.transWave.sliceEnable) { + DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; + if (ind.ind>=0 && ind.ind<(short)(e->song.sampleLen)) { + DivSample* s=e->song.sample[ind.ind]; + ins->amiga.transWave.updateSize(s->samples,ind.loopStart,ind.loopEnd); + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + } + } + } + if (ImGui::Checkbox("Use Transwave Slice##UseTransWaveSlice",&ins->amiga.transWave.sliceEnable)) { PARAMETER + if (ins->amiga.transWave.sliceEnable) { + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + if (ins->amiga.transWave.sliceEnable) { + DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; + if (ind.ind>=0 && ind.ind<(short)(e->song.sampleLen)) { + DivSample* s=e->song.sample[ind.ind]; + ins->amiga.transWave.updateSize(s->samples,ind.loopStart,ind.loopEnd); + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); } } - ImGui::EndCombo(); - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER - if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; - if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; - } - ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==0)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=0; - } - if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==1)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=1; - } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),ins->amiga.noteMap[i].reversed==2)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=2; - } - ImGui::PopID(); - } - ImGui::EndTable(); - } - } - ImGui::EndDisabled(); - // Transwave - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.useNoteMap); - P(ImGui::Checkbox("Use Transwave##UseTransWave",&ins->amiga.transWave.enable)); - if (ins->amiga.transWave.enable) { - int size=ins->amiga.transWaveMap.size(); - if (ImGui::InputInt("Transwave Map Size##TransWaveSize",&size,1,16)) { PARAMETER - if (size<=ins->amiga.transWave.ind) size=ins->amiga.transWave.ind+1; - if (size<1) size=1; - if (size>256) size=256; - if (ins->amiga.transWaveMap.size()!=(size_t)(size)) { - ins->amiga.transWaveMap.resize(size,DivInstrumentAmiga::TransWaveMap()); - if (ins->amiga.transWaveMap.capacity()>(size_t)(size)) { - ins->amiga.transWaveMap.shrink_to_fit(); } } - } - if (ImGui::InputInt("Initial Transwave Index##TransWaveInit",&ins->amiga.transWave.ind,1,16)) { PARAMETER - if (ins->amiga.transWave.ind<1) ins->amiga.transWave.ind=0; - if (ins->amiga.transWave.ind>=(int)(ins->amiga.transWaveMap.size())) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; - } - P(ImGui::Checkbox("Use Transwave Slice##UseTransWaveSlice",&ins->amiga.transWave.sliceEnable)); - DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; - if (ins->amiga.transWave.sliceEnable && (ind.ind>=0 && ind.indsong.sampleLen)) { - double sliceInit=(double)(ins->amiga.transWave.slice)/4095.0; - double slicePos=ins->amiga.transWave.slicePos(sliceInit); - double sliceStart=ins->amiga.transWave.sliceStart; - double sliceEnd=ins->amiga.transWave.sliceEnd; - P(CWSliderScalar("Initial Transwave Slice##TransWaveSliceInit",ImGuiDataType_U16,&ins->amiga.transWave.slice,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE,fmt::sprintf("%d: %.6f - %.6f",ins->amiga.transWave.slice,sliceStart,sliceEnd).c_str())); rightClickable - ImGui::Text("Position: %.6f", slicePos); - } - if (ImGui::BeginTable("TransWaveMap",6,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // Number - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); // Sample index - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); // Loop start - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); // Loop end - ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); // Loop mode - ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch); // Reversed + DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; + if (ins->amiga.transWave.sliceEnable && (ind.ind>=0 && ind.indsong.sampleLen)) { + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + double sliceStart=ins->amiga.transWave.sliceStart; + double sliceEnd=ins->amiga.transWave.sliceEnd; + if (CWSliderScalar("Initial Transwave Slice##TransWaveSliceInit",ImGuiDataType_U16,&ins->amiga.transWave.slice,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE,fmt::sprintf("%d: %.6f - %.6f",ins->amiga.transWave.slice,sliceStart,sliceEnd).c_str())) { PARAMETER + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + } rightClickable + } + if (ImGui::BeginTable("TransWaveMap",6,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // Number + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); // Sample index + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); // Loop start + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); // Loop end + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); // Loop mode + ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch); // Reversed - ImGui::TableSetupScrollFreeze(0,1); + ImGui::TableSetupScrollFreeze(0,1); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::Text("Sample"); - ImGui::TableNextColumn(); - ImGui::Text("Loop Start"); - ImGui::TableNextColumn(); - ImGui::Text("Loop End"); - ImGui::TableNextColumn(); - ImGui::Text("Loop Mode"); - ImGui::TableNextColumn(); - ImGui::Text("Reversed"); - for (size_t i=0; iamiga.transWaveMap.size(); i++) { - DivInstrumentAmiga::TransWaveMap& transWaveMap=ins->amiga.transWaveMap[i]; - ImGui::TableNextRow(); - ImGui::PushID(fmt::sprintf("TransWaveMap_%d",i).c_str()); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); - ImGui::Text("%d",(int)(i)); ImGui::TableNextColumn(); - if (transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen) { - sName="-- empty --"; - transWaveMap.ind=-1; - } else { - sName=e->song.sample[transWaveMap.ind]->name; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo(fmt::sprintf("##TransWaveMap_Index_%d",i).c_str(),sName.c_str())) { - String id; - if (ImGui::Selectable("-- empty --",transWaveMap.ind==-1)) { PARAMETER + ImGui::Text("Sample"); + ImGui::TableNextColumn(); + ImGui::Text("Loop Start"); + ImGui::TableNextColumn(); + ImGui::Text("Loop End"); + ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::TableNextColumn(); + ImGui::Text("Reversed"); + for (size_t i=0; iamiga.transWaveMap.size(); i++) { + DivInstrumentAmiga::TransWaveMap& transWaveMap=ins->amiga.transWaveMap[i]; + ImGui::TableNextRow(); + ImGui::PushID(fmt::sprintf("TransWaveMap_%d",i).c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%d",(int)(i)); + ImGui::TableNextColumn(); + if (transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen) { + sName="-- empty --"; transWaveMap.ind=-1; + } else { + sName=e->song.sample[transWaveMap.ind]->name; } - for (int j=0; jsong.sampleLen; j++) { - DivSample* s=e->song.sample[j]; - id=fmt::sprintf("%d: %s",j,s->name); - if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER - transWaveMap.ind=j; - if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { - transWaveMap.loopStart=s->loopStart; - } - if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { - transWaveMap.loopEnd=s->loopEnd; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo(fmt::sprintf("##TransWaveMap_Index_%d",i).c_str(),sName.c_str())) { + String id; + if (ImGui::Selectable("-- empty --",transWaveMap.ind==-1)) { PARAMETER + transWaveMap.ind=-1; + } + for (int j=0; jsong.sampleLen; j++) { + DivSample* s=e->song.sample[j]; + id=fmt::sprintf("%d: %s",j,s->name); + if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER + transWaveMap.ind=j; + if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { + transWaveMap.loopStart=s->loopStart; + } + if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { + transWaveMap.loopEnd=s->loopEnd; + } + transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + if (ins->amiga.transWave.sliceEnable && i==ins->amiga.transWave.ind) { + ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + } } + } + ImGui::EndCombo(); + } + ImGui::BeginDisabled(transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopStart_%d",i).c_str(),&transWaveMap.loopStart,256,4096)) { PARAMETER + if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { + DivSample* s=e->song.sample[transWaveMap.ind]; + if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; + if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + if (ins->amiga.transWave.sliceEnable && i==ins->amiga.transWave.ind) { + ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + } } } - ImGui::EndCombo(); - } - ImGui::BeginDisabled(transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopStart_%d",i).c_str(),&transWaveMap.loopStart,256,4096)) { PARAMETER - if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { - DivSample* s=e->song.sample[transWaveMap.ind]; - if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; - if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; - transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopEnd_%d",i).c_str(),&transWaveMap.loopEnd,256,4096)) { PARAMETER + if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { + DivSample* s=e->song.sample[transWaveMap.ind]; + if (transWaveMap.loopEnd(int)(s->samples)) transWaveMap.loopEnd=s->samples; + transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + if (ins->amiga.transWave.sliceEnable) { + ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); + } + } } - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopEnd_%d",i).c_str(),&transWaveMap.loopEnd,256,4096)) { PARAMETER - if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { - DivSample* s=e->song.sample[transWaveMap.ind]; - if (transWaveMap.loopEnd(int)(s->samples)) transWaveMap.loopEnd=s->samples; - transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); + ImGui::TableNextColumn(); + if (ImGui::RadioButton(fmt::sprintf("Forward##TransWaveMap_LoopMode_Forward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_FORWARD)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; } + if (ImGui::RadioButton(fmt::sprintf("Backward##TransWaveMap_LoopMode_Backward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_BACKWARD)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_BACKWARD; + } + if (ImGui::RadioButton(fmt::sprintf("Pingpong##TransWaveMap_LoopMode_Pingpong_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_PINGPONG)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } + if (ImGui::RadioButton(fmt::sprintf("Use sample setting##TransWaveMap_LoopMode_Default_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)) { MARK_MODIFIED + transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; + } + ImGui::TableNextColumn(); + if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==0)) { MARK_MODIFIED + transWaveMap.reversed=0; + } + if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==1)) { MARK_MODIFIED + transWaveMap.reversed=1; + } + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==2)) { MARK_MODIFIED + transWaveMap.reversed=2; + } + ImGui::EndDisabled(); + ImGui::PopID(); } - ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Forward##TransWaveMap_LoopMode_Forward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_FORWARD)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; - } - if (ImGui::RadioButton(fmt::sprintf("Backward##TransWaveMap_LoopMode_Backward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_BACKWARD)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_BACKWARD; - } - if (ImGui::RadioButton(fmt::sprintf("Pingpong##TransWaveMap_LoopMode_Pingpong_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_PINGPONG)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; - } - if (ImGui::RadioButton(fmt::sprintf("Use sample setting##TransWaveMap_LoopMode_Default_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOPMODE_ONESHOT; - } - ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==0)) { MARK_MODIFIED - transWaveMap.reversed=0; - } - if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==1)) { MARK_MODIFIED - transWaveMap.reversed=1; - } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==2)) { MARK_MODIFIED - transWaveMap.reversed=2; - } - ImGui::EndDisabled(); - ImGui::PopID(); + ImGui::EndTable(); } - ImGui::EndTable(); } + ImGui::EndDisabled(); + ImGui::EndTabItem(); + } + if (ins->amiga.transWave.enable) { if (ImGui::BeginTabItem("Transwave Macros")) { macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,transwaveControlModes)); macroList.push_back(FurnaceGUIMacroDesc("Transwave slice",&ins->std.fmsMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); + drawMacros(macroList); ImGui::EndTabItem(); } } - ImGui::EndDisabled(); - ImGui::EndTabItem(); } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("Namco 163")) { if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER From 3ab3774f928bd76a54cc53169f6ffaea40a663ec Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 31 May 2022 14:15:47 +0900 Subject: [PATCH 18/74] Don't trim when set loop point --- src/gui/doAction.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 50956bc24..897e29067 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1240,8 +1240,11 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - sample->trim(0,end); + if (sample->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) { + sample->loopMode=DIV_SAMPLE_LOOPMODE_FORWARD; + } sample->loopStart=start; + sample->loopEnd=end; updateSampleTex=true; e->renderSamples(); From 0f414f17d7ba71f168f1949fc0042bd391fedf90 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 31 May 2022 14:18:40 +0900 Subject: [PATCH 19/74] Add Modifier and Contributor disclaimer --- src/engine/platform/sound/es550x/es5504.cpp | 1 + src/engine/platform/sound/es550x/es5504.hpp | 1 + src/engine/platform/sound/es550x/es5505.cpp | 1 + src/engine/platform/sound/es550x/es5505.hpp | 1 + src/engine/platform/sound/es550x/es5506.cpp | 1 + src/engine/platform/sound/es550x/es5506.hpp | 1 + src/engine/platform/sound/es550x/es550x.cpp | 1 + src/engine/platform/sound/es550x/es550x.hpp | 1 + src/engine/platform/sound/es550x/es550x_alu.cpp | 1 + src/engine/platform/sound/es550x/es550x_filter.cpp | 1 + src/engine/platform/sound/es550x/util.hpp | 1 + 11 files changed, 11 insertions(+) diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp index 2ffc7ab5c..c2644fbdb 100644 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504 emulation core see es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp index bbf74b2cb..be6e44d11 100644 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ b/src/engine/platform/sound/es550x/es5504.hpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504 emulation core See es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index 4a6ab8988..fae6b3930 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5505 emulation core see es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp index b42322f62..6498ddff0 100644 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504 emulation core See es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 251b158a2..c401a4b63 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5506 emulation core see es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp index 9aaee75b2..b16be3672 100644 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504 emulation core See es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp index 5d83fd522..10d1d9a90 100644 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ b/src/engine/platform/sound/es550x/es550x.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504/ES5505/ES5506 emulation core After ES5503 DOC's appeared, Ensoniq announces ES5504 DOC II, ES5505 OTIS, ES5506 OTTO. diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index ad02c2ff1..e5106b78a 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504/ES5505/ES5506 emulation core See es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp index cf22517ec..6b11d9ec9 100644 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ b/src/engine/platform/sound/es550x/es550x_alu.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core see es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp index 45fd0571f..bf0b260c1 100644 --- a/src/engine/platform/sound/es550x/es550x_filter.cpp +++ b/src/engine/platform/sound/es550x/es550x_filter.cpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core see es550x.cpp for more info diff --git a/src/engine/platform/sound/es550x/util.hpp b/src/engine/platform/sound/es550x/util.hpp index a66f4ca8e..63d082ac0 100644 --- a/src/engine/platform/sound/es550x/util.hpp +++ b/src/engine/platform/sound/es550x/util.hpp @@ -3,6 +3,7 @@ see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details Copyright holder(s): cam900 + Modifiers and Contributors for Furnace: cam900 Various core utilities for vgsound_emu */ From e8c672f91e3146da03eb9bda9c6ed4e36fcc6fe1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 31 May 2022 14:20:15 +0900 Subject: [PATCH 20/74] Fix preview --- src/engine/playback.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 9555c5507..ac1c555b9 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1173,8 +1173,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) { DivSample* s=song.sample[sPreview.sample]; - const bool pBeginVaild=sPreview.pBegin>=0 && sPreview.pBeginsamples; - const bool pEndVaild=sPreview.pEnd>=0 && sPreview.pEndsamples; + const bool pBeginVaild=sPreview.pBegin>=0 && sPreview.pBegin<(int)s->samples; + const bool pEndVaild=sPreview.pEnd>=0 && sPreview.pEnd<(int)s->samples; const int loopStart=pBeginVaild?sPreview.pBegin:s->loopStart; const int loopEnd=pEndVaild?sPreview.pEnd:(int)s->loopEnd; for (size_t i=0; iisLoopable() && sPreview.posloopEnd) && ((int)sPreview.pos)isLoopable() && ((int)sPreview.pos)loopMode) { case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; @@ -1212,7 +1212,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } else { - if ((s->isLoopable() && (int)sPreview.pos>=s->loopStart) && ((int)sPreview.pos)>=loopEnd) { + if (s->isLoopable() && ((int)sPreview.pos)>=loopEnd) { switch (s->loopMode) { case DIV_SAMPLE_LOOPMODE_FORWARD: sPreview.dir=false; From 0e1e1f33ec1c7bb7445c7aa9f73fe7874255e579 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Jun 2022 00:36:52 +0900 Subject: [PATCH 21/74] Fix compile --- src/engine/platform/segapcm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index bdb894ff6..911754e46 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -187,7 +187,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if ((s->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (s->loopStart<0 || s->loopStart>=actualLength || s->loopEnd<=s->loopStart || s->loopEnd>=actualLength)) { + if ((s->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (s->loopStart<0 || s->loopStart>=actualLength || s->loopEnd<=(unsigned int)s->loopStart || s->loopEnd>=(unsigned int)actualLength)) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; @@ -220,7 +220,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if ((s->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (s->loopStart<0 || s->loopStart>=actualLength || s->loopEnd<=s->loopStart || s->loopEnd>=actualLength)) { + if ((s->loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (s->loopStart<0 || s->loopStart>=actualLength || s->loopEnd<=(unsigned int)s->loopStart || s->loopEnd>=(unsigned int)actualLength)) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; From a647a2599f93570587830434229501a90d95008e Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 26 Jun 2022 09:06:13 +0900 Subject: [PATCH 22/74] Fix typecasting --- src/engine/platform/es5506.cpp | 12 ++++----- src/engine/platform/vera.cpp | 4 +-- src/engine/platform/ymz280b.cpp | 44 ++++++++++++++++++--------------- src/gui/debugWindow.cpp | 2 +- src/gui/doAction.cpp | 34 ++++++++++++------------- 5 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 7c19dc3e6..577486af0 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -287,7 +287,7 @@ void DivPlatformES5506::e_pin(bool state) DivInstrument* ins=parent->getIns(chan[ch].ins); if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { const int next=chan[ch].pcm.next; - if (next>=0 && nextamiga.transWaveMap.size()) { + if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; int sample=transWaveInd.ind; if (sample>=0 && samplesong.sampleLen) { @@ -578,7 +578,7 @@ void DivPlatformES5506::tick(bool sysTick) { // transwave macros if (chan[i].transWave.enable) { if (chan[i].std.wave.had) { - if (chan[i].std.wave.val>=0 && chan[i].std.wave.valamiga.transWaveMap.size()) { + if (chan[i].std.wave.val>=0 && chan[i].std.wave.val<(int)ins->amiga.transWaveMap.size()) { if (chan[i].pcm.next!=chan[i].std.wave.val) { chan[i].pcm.next=chan[i].std.wave.val; chan[i].pcmChanged.transwaveInd=1; @@ -642,7 +642,7 @@ void DivPlatformES5506::tick(bool sysTick) { if (!chan[i].isTranswave) { if (chan[i].pcmChanged.transwaveInd && (!ins->amiga.useNoteMap && ins->amiga.transWave.enable)) { const int next=chan[i].pcm.next; - if (next>=0 && nextamiga.transWaveMap.size()) { + if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; int sample=transWaveInd.ind; if (sample>=0 && samplesong.sampleLen) { @@ -691,7 +691,7 @@ void DivPlatformES5506::tick(bool sysTick) { const int next=chan[i].pcm.next; bool sampleVaild=false; if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && next<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (next>=0 && nextamiga.transWaveMap.size())) || + ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (next>=0 && next<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && nextsong.sampleLen))) { DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[next]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; @@ -999,7 +999,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); bool sampleVaild=false; if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.indamiga.transWaveMap.size())) || + ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.ind<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (ins->amiga.initSample>=0 && ins->amiga.initSamplesong.sampleLen))) { DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[c.value]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; @@ -1170,7 +1170,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].active) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (c.value>=0 && c.valueamiga.transWaveMap.size())) || + ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (c.value>=0 && c.value<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.valuesong.sampleLen))) { chan[c.chan].pcm.next=c.value; if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 18be8b09f..aa7810256 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -267,12 +267,12 @@ int DivPlatformVERA::dispatch(DivCommand c) { chan[16].pcm.pos=0; DivSample* s=parent->getSample(chan[16].pcm.sample); unsigned char ctrl=0x90|chan[16].vol; // always stereo - if (s->depth==16) { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { chan[16].pcm.depth16=true; ctrl|=0x20; } else { chan[16].pcm.depth16=false; - if (s->depth!=8) chan[16].pcm.sample=-1; + if (s->depth!=DIV_SAMPLE_DEPTH_8BIT) chan[16].pcm.sample=-1; } rWritePCMCtrl(ctrl); } diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 45631a940..287020e82 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -136,9 +136,9 @@ void DivPlatformYMZ280B::tick(bool sysTick) { DivSample* s=parent->getSample(chan[i].sample); unsigned char ctrl; switch (s->depth) { - case 3: ctrl=0x20; break; - case 8: ctrl=0x40; break; - case 16: ctrl=0x60; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: ctrl=0x20; break; + case DIV_SAMPLE_DEPTH_8BIT: ctrl=0x40; break; + case DIV_SAMPLE_DEPTH_16BIT: ctrl=0x60; break; default: ctrl=0; } double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0; @@ -146,40 +146,44 @@ void DivPlatformYMZ280B::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>511) chan[i].freq=511; // ADPCM has half the range - if (s->depth==3 && chan[i].freq>255) chan[i].freq=255; - ctrl|=(chan[i].active?0x80:0)|((s->loopStart>=0)?0x10:0)|(chan[i].freq>>8); + if (s->depth==DIV_SAMPLE_DEPTH_YMZ_ADPCM && chan[i].freq>255) chan[i].freq=255; + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|(chan[i].freq>>8); if (chan[i].keyOn) { unsigned int start=s->offYMZ280B; - unsigned int loop=0; + unsigned int loopStart=0; + unsigned int loopEnd=0; unsigned int end=MIN(start+s->getCurBufLen(),getSampleMemCapacity()-1); if (chan[i].audPos>0) { switch (s->depth) { - case 3: start+=chan[i].audPos/2; break; - case 8: start+=chan[i].audPos; break; - case 16: start+=chan[i].audPos*2; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: start+=chan[i].audPos/2; break; + case DIV_SAMPLE_DEPTH_8BIT: start+=chan[i].audPos; break; + case DIV_SAMPLE_DEPTH_16BIT: start+=chan[i].audPos*2; break; + default: break; } start=MIN(start,end); } - if (s->loopStart>=0) { + if (s->isLoopable()) { switch (s->depth) { - case 3: loop=start+s->loopStart/2; break; - case 8: loop=start+s->loopStart; break; - case 16: loop=start+s->loopStart*2; break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: loopStart=start+s->loopStart/2; loopEnd=start+s->loopEnd/2; break; + case DIV_SAMPLE_DEPTH_8BIT: loopStart=start+s->loopStart; loopEnd=start+s->loopEnd; break; + case DIV_SAMPLE_DEPTH_16BIT: loopStart=start+s->loopStart*2; loopEnd=start+s->loopEnd*2; break; + default: break; } - loop=MIN(loop,end); + loopEnd=MIN(loopEnd,end); + loopStart=MIN(loopStart,loopEnd); } rWrite(0x01+i*4,ctrl&~0x80); // force keyoff first rWrite(0x20+i*4,(start>>16)&0xff); - rWrite(0x21+i*4,(loop>>16)&0xff); - rWrite(0x22+i*4,(end>>16)&0xff); + rWrite(0x21+i*4,(loopStart>>16)&0xff); + rWrite(0x22+i*4,(loopEnd>>16)&0xff); rWrite(0x23+i*4,(end>>16)&0xff); rWrite(0x40+i*4,(start>>8)&0xff); - rWrite(0x41+i*4,(loop>>8)&0xff); - rWrite(0x42+i*4,(end>>8)&0xff); + rWrite(0x41+i*4,(loopStart>>8)&0xff); + rWrite(0x42+i*4,(loopEnd>>8)&0xff); rWrite(0x43+i*4,(end>>8)&0xff); rWrite(0x60+i*4,start&0xff); - rWrite(0x61+i*4,loop&0xff); - rWrite(0x62+i*4,end&0xff); + rWrite(0x61+i*4,loopStart&0xff); + rWrite(0x62+i*4,loopEnd&0xff); rWrite(0x63+i*4,end&0xff); if (!chan[i].std.vol.had) { chan[i].outVol=chan[i].vol; diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 29f75707f..be39ced0e 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -157,7 +157,7 @@ void FurnaceGUI::drawDebug() { ImGui::Text("loopEnd: %d",sample->loopEnd); ImGui::Text("loopMode: %d",(int)(sample->loopMode)); ImGui::Text("loopOffP: %d",sample->loopOffP); - ImGui::Text("depth: %d",sample->depth); + ImGui::Text("depth: %d",(unsigned char)sample->depth); ImGui::Text("length8: %d",sample->length8); ImGui::Text("length16: %d",sample->length16); ImGui::Text("length1: %d",sample->length1); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 6f952a448..701445de1 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -840,7 +840,7 @@ void FurnaceGUI::doAction(int what) { if (!sample->insert(pos,sampleClipboardLen)) { showError("couldn't paste! make sure your sample is 8 or 16-bit."); } else { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; idata8[pos+i]=sampleClipboard[i]>>8; } @@ -866,7 +866,7 @@ void FurnaceGUI::doAction(int what) { if (pos<0) pos=0; e->lockEngine([this,sample,pos]() { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; i=sample->samples) break; sample->data8[pos+i]=sampleClipboard[i]>>8; @@ -896,7 +896,7 @@ void FurnaceGUI::doAction(int what) { if (pos<0) pos=0; e->lockEngine([this,sample,pos]() { - if (sample->depth==8) { + if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (size_t i=0; i=sample->samples) break; int val=sample->data8[pos+i]+(sampleClipboard[i]>>8); @@ -950,7 +950,7 @@ void FurnaceGUI::doAction(int what) { SAMPLE_OP_BEGIN; float maxVal=0.0f; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]/32767.0f); if (val>maxVal) maxVal=val; @@ -965,7 +965,7 @@ void FurnaceGUI::doAction(int what) { sample->data16[i]=val; } } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]/127.0f); if (val>maxVal) maxVal=val; @@ -996,14 +996,14 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*float(i-start)/float(end-start); if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*float(i-start)/float(end-start); if (val<-128) val=-128; @@ -1026,14 +1026,14 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]*float(end-i)/float(end-start); if (val<-32768) val=-32768; if (val>32767) val=32767; sample->data16[i]=val; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]*float(end-i)/float(end-start); if (val<-128) val=-128; @@ -1060,11 +1060,11 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]=0; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]=0; } @@ -1118,7 +1118,7 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[ri]^=sample->data16[i]; sample->data16[i]^=sample->data16[ri]; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; ilockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]=-sample->data16[i]; if (sample->data16[i]==-32768) sample->data16[i]=32767; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]=-sample->data8[i]; if (sample->data16[i]==-128) sample->data16[i]=127; @@ -1176,11 +1176,11 @@ void FurnaceGUI::doAction(int what) { e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; - if (sample->depth==16) { + if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { for (unsigned int i=start; idata16[i]^=0x8000; } - } else if (sample->depth==8) { + } else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { for (unsigned int i=start; idata8[i]^=0x80; } From 04af689ae96fde3bb17ed09db5b1b0e6c048533b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 26 Jun 2022 09:28:18 +0900 Subject: [PATCH 23/74] Fix typecasting(again) --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2b84d98b2..08f9bc276 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3245,7 +3245,7 @@ void FurnaceGUI::drawInsEdit() { transWaveMap.loopEnd=s->loopEnd; } transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - if (ins->amiga.transWave.sliceEnable && i==ins->amiga.transWave.ind) { + if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); } @@ -3262,7 +3262,7 @@ void FurnaceGUI::drawInsEdit() { if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - if (ins->amiga.transWave.sliceEnable && i==ins->amiga.transWave.ind) { + if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); } From 5e72274c5cf40495fb4007e8a24ff40f8e322336 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 26 Jun 2022 09:29:35 +0900 Subject: [PATCH 24/74] I forgot here --- src/engine/vgmOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 2330c5c5d..a88869b5f 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1717,7 +1717,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen); for (int i=0; idepth==16) { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { unsigned int pos=s->offYMZ280B; for (unsigned int j=0; jsamples; j++) { unsigned char lo=sampleMem[pos+j*2]; From 8ae1d36ab6793dcfbc907cbebe6a1a33290fa229 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 26 Jun 2022 09:56:07 +0900 Subject: [PATCH 25/74] Typecasting here --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 08f9bc276..b3d9de5a9 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1192,7 +1192,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (i.macroMode && i.modeName[0]!=NULL) { for (int m=0; i.modeName[m]!=NULL; m++) { String modeName=fmt::sprintf("%s##IMacroMode%d",i.modeName[m],m); - if (ImGui::RadioButton(modeName.c_str(),i.macro->mode==m)) { + if (ImGui::RadioButton(modeName.c_str(),(int)i.macro->mode==m)) { i.macro->mode=m; } } From b449e3812d76d9bb11afe22a05cdfeb5cb600b9b Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 22 Sep 2022 22:49:54 +0900 Subject: [PATCH 26/74] Fix compile --- extern/Nuked-OPL3 | 1 + extern/imgui | 1 + src/engine/platform/sound/es550x/util.hpp | 1 + 3 files changed, 3 insertions(+) create mode 160000 extern/Nuked-OPL3 create mode 160000 extern/imgui diff --git a/extern/Nuked-OPL3 b/extern/Nuked-OPL3 new file mode 160000 index 000000000..bb5c8d08a --- /dev/null +++ b/extern/Nuked-OPL3 @@ -0,0 +1 @@ +Subproject commit bb5c8d08a85779c42b75c79d7b84f365a1b93b66 diff --git a/extern/imgui b/extern/imgui new file mode 160000 index 000000000..1ee252772 --- /dev/null +++ b/extern/imgui @@ -0,0 +1 @@ +Subproject commit 1ee252772ae9c0a971d06257bb5c89f628fa696a diff --git a/src/engine/platform/sound/es550x/util.hpp b/src/engine/platform/sound/es550x/util.hpp index 63d082ac0..ad85fdf99 100644 --- a/src/engine/platform/sound/es550x/util.hpp +++ b/src/engine/platform/sound/es550x/util.hpp @@ -12,6 +12,7 @@ #pragma once +#include #include #include From 8e1ce1abb10884528037172f826d644ab8ab413c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 18:32:34 +0900 Subject: [PATCH 27/74] Sync to master --- src/engine/engine.h | 1 - src/engine/instrument.h | 2 +- src/engine/platform/es5506.cpp | 412 ++++----- src/engine/platform/es5506.h | 19 +- src/engine/platform/sound/es550x/es5504.cpp | 453 ---------- src/engine/platform/sound/es550x/es5504.hpp | 97 --- src/engine/platform/sound/es550x/es5505.cpp | 606 ------------- src/engine/platform/sound/es550x/es5505.hpp | 152 ---- src/engine/platform/sound/es550x/es5506.cpp | 794 ------------------ src/engine/platform/sound/es550x/es5506.hpp | 190 ----- src/engine/platform/sound/es550x/es550x.cpp | 78 -- src/engine/platform/sound/es550x/es550x.hpp | 284 ------- .../platform/sound/es550x/es550x_alu.cpp | 116 --- .../platform/sound/es550x/es550x_filter.cpp | 71 -- src/engine/platform/sound/es550x/util.hpp | 141 ---- src/engine/sample.h | 6 - src/gui/debugWindow.cpp | 1 + src/gui/gui.h | 2 +- src/gui/guiConst.cpp | 5 +- src/gui/insEdit.cpp | 96 +-- src/gui/sampleEdit.cpp | 10 - 21 files changed, 238 insertions(+), 3298 deletions(-) delete mode 100644 src/engine/platform/sound/es550x/es5504.cpp delete mode 100644 src/engine/platform/sound/es550x/es5504.hpp delete mode 100644 src/engine/platform/sound/es550x/es5505.cpp delete mode 100644 src/engine/platform/sound/es550x/es5505.hpp delete mode 100644 src/engine/platform/sound/es550x/es5506.cpp delete mode 100644 src/engine/platform/sound/es550x/es5506.hpp delete mode 100644 src/engine/platform/sound/es550x/es550x.cpp delete mode 100644 src/engine/platform/sound/es550x/es550x.hpp delete mode 100644 src/engine/platform/sound/es550x/es550x_alu.cpp delete mode 100644 src/engine/platform/sound/es550x/es550x_filter.cpp delete mode 100644 src/engine/platform/sound/es550x/util.hpp diff --git a/src/engine/engine.h b/src/engine/engine.h index 596829f05..ff01d2e18 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -384,7 +384,6 @@ class DivEngine { sample(-1), wave(-1), pos(0), - dir(false), pBegin(-1), pEnd(-1), dir(false) {} diff --git a/src/engine/instrument.h b/src/engine/instrument.h index b6d35935b..1336bbd38 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -405,7 +405,7 @@ struct DivInstrumentAmiga { reversed(0), loopStart(-1), loopEnd(-1), - loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} + loopMode(DIV_SAMPLE_LOOP_MAX) {} }; short initSample; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 577486af0..16cec93e3 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -27,7 +27,7 @@ #define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) #define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }} -#define rRead(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} +#define rRead(a,st,...) {hostIntf32.emplace(st,4,(a),__VA_ARGS__);} #define immWrite(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} #define pageWrite(p,a,...) \ if (!skipRegisterWrites) { \ @@ -47,13 +47,13 @@ rWrite((a),__VA_ARGS__); \ } -#define pageReadMask(p,pm,a,...) \ +#define pageReadMask(p,pm,a,st,...) \ if (!skipRegisterWrites) { \ if ((curPage&(pm))!=((p)&(pm))) { \ curPage=(curPage&~(pm))|((p)&(pm)); \ rWrite(0xf,curPage,(pm)); \ } \ - rRead((a),__VA_ARGS__); \ + rRead(st,(a),__VA_ARGS__); \ } @@ -112,90 +112,16 @@ const char** DivPlatformES5506::getRegisterSheet() { return regCheatSheetES5506; } -const char* DivPlatformES5506::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform or sample, transwave index"; - break; - case 0x11: - return "11xx: Set filter mode (00 to 03)"; - break; - case 0x12: - return "120x: Set pause (bit 0)"; - break; - case 0x13: - return "130x: Set transwave slice mode (bit 0)"; - break; - case 0x14: - return "14xx: Set filter coefficient K1 low byte"; - break; - case 0x15: - return "15xx: Set filter coefficient K1 high byte"; - break; - case 0x16: - return "16xx: Set filter coefficient K2 low byte"; - break; - case 0x17: - return "17xx: Set filter coefficient K2 high byte"; - break; - case 0x18: - return "18xx: Set filter coefficient K1 slide up"; - break; - case 0x19: - return "19xx: Set filter coefficient K1 slide down"; - break; - case 0x1a: - return "1axx: Set filter coefficient K2 slide up"; - break; - case 0x1b: - return "1bxx: Set filter coefficient K2 slide down"; - break; - case 0x20: - return "20xx: Set envelope count (000 to 0FF)"; - break; - case 0x21: - return "21xx: Set envelope count (100 to 1FF)"; - break; - case 0x22: - return "22xx: Set envelope left volume ramp (signed)"; - break; - case 0x23: - return "23xx: Set envelope right volume ramp (signed)"; - break; - case 0x24: - return "24xx: Set envelope filter coefficient k1 ramp (signed)"; - break; - case 0x25: - return "25xx: Set envelope filter coefficient k1 ramp (signed, slower)"; - break; - case 0x26: - return "26xx: Set envelope filter coefficient k2 ramp (signed)"; - break; - case 0x27: - return "27xx: Set envelope filter coefficient k2 ramp (signed, slower)"; - break; - default: - if ((effect&0xf0)==0x30) { - return "3xxx: Set filter coefficient K1"; - } else if ((effect&0xf0)==0x40) { - return "4xxx: Set filter coefficient K2"; - } else if ((effect&0xf0)==0x50) { - return "5xxx: Set transwave slice point"; - } - break; - } - return NULL; -} void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h0) { cycle+=w.delay; } + queuedReadState.emplace(w.read,w.state); isReaded=true; } else { isReaded=false; @@ -272,116 +199,127 @@ void DivPlatformES5506::e_pin(bool state) } } } - if (isReaded) { - isReaded=false; - if (irqTrigger) { - irqTrigger=false; - if ((irqv&0x80)==0) { - unsigned char ch=irqv&0x1f; - if (chan[ch].isReverseLoop) { // Reversed loop - pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); - chan[ch].isReverseLoop=false; + if (!queuedReadState.empty()) { + QueuedReadState w=queuedReadState.front(); + const unsigned char state=w.state; + if (state&0x80) { + if (irqTrigger) { + if ((irqv&0x80)==0) { + queuedRead.emplace(irqv&0x1f); } - if (chan[ch].transwaveIRQ) { - if ((chan[ch].cr&0x37)==0x34) { // IRQE = 1, BLE = 1, LPE = 0, LEI = 1 - DivInstrument* ins=parent->getIns(chan[ch].ins); - if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { - const int next=chan[ch].pcm.next; - if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; - int sample=transWaveInd.ind; - if (sample>=0 && samplesong.sampleLen) { - chan[ch].pcm.index=sample; - chan[ch].transWave.ind=next; - DivSample* s=parent->getSample(sample); - // get frequency offset - double off=1.0; - double center=(double)s->centerRate; - if (center<1) { - off=1.0; - } else { - off=(double)center/8363.0; - } - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { - loopMode=transWaveInd.loopMode; - } else if ((chan[ch].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[ch].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[ch].transWave.slicePos(double(chan[ch].transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - // get reversed - bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=2) { - reversed=transWaveInd.reversed; - } - const unsigned int start=s->offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - const double nextFreqOffs=PITCH_OFFSET*off; - chan[ch].pcm.loopMode=loopMode; - chan[ch].pcm.reversed=reversed; - chan[ch].pcm.bank=(s->offES5506>>22)&3; - chan[ch].pcm.start=start; - chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; - chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; - chan[ch].pcm.end=end; - chan[ch].pcm.length=length; - pageWrite(0x20|ch,0x01,chan[ch].pcm.loopStart); - pageWrite(0x20|ch,0x02,chan[ch].pcm.loopEnd); - pageWrite(0x20|ch,0x03,(chan[ch].pcm.reversed)?chan[ch].pcm.loopEnd:chan[ch].pcm.loopStart); - unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); - chan[ch].isReverseLoop=false; - switch (chan[ch].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) - default: - break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop - loopFlag|=0x0008; - break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable - loopFlag|=0x0038; - chan[ch].isReverseLoop=true; - break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support - loopFlag|=0x0018; - break; - } - // Set loop mode & Bank - pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); - if (chan[ch].pcm.nextFreqOffs!=nextFreqOffs) { - chan[ch].pcm.nextFreqOffs=nextFreqOffs; - chan[ch].noteChanged.offs=1; - } + irqTrigger=false; + } + } else { + unsigned char ch=w.state&0x1f; + if (chan[ch].transwaveIRQ) { + if ((chan[ch].cr&0x37)==0x34) { // IRQE = 1, BLE = 1, LPE = 0, LEI = 1 + DivInstrument* ins=parent->getIns(chan[ch].ins); + if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { + const int next=chan[ch].pcm.next; + if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { + DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; + int sample=transWaveInd.ind; + if (sample>=0 && samplesong.sampleLen) { + chan[ch].pcm.index=sample; + chan[ch].transWave.ind=next; + DivSample* s=parent->getSample(sample); + // get frequency offset + double off=1.0; + double center=(double)s->centerRate; + if (center<1) { + off=1.0; + } else { + off=(double)center/8363.0; + } + // get loop mode, transwave loop + double loopStart=(double)s->loopStart; + double loopEnd=(double)s->loopEnd; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { + loopMode=transWaveInd.loopMode; + } else if ((chan[ch].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; + } + // get loop position + loopStart=(double)transWaveInd.loopStart; + loopEnd=(double)transWaveInd.loopEnd; + if (ins->amiga.transWave.sliceEnable) { // sliced loop position? + chan[ch].transWave.updateSize(s->samples,loopStart,loopEnd); + chan[ch].transWave.slicePos(double(chan[ch].transWave.slice)/4095.0); + loopStart=transWaveInd.sliceStart; + loopEnd=transWaveInd.sliceEnd; + } + // get reversed + bool reversed=ins->amiga.reversed; + if (transWaveInd.reversed!=2) { + reversed=transWaveInd.reversed; + } + const unsigned int start=s->offES5506<<10; + const unsigned int length=s->samples-1; + const unsigned int end=start+(length<<11); + const double nextFreqOffs=PITCH_OFFSET*off; + chan[ch].pcm.loopMode=loopMode; + chan[ch].pcm.reversed=reversed; + chan[ch].pcm.bank=(s->offES5506>>22)&3; + chan[ch].pcm.start=start; + chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; + chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; + chan[ch].pcm.end=end; + chan[ch].pcm.length=length; + pageWrite(0x20|ch,0x01,chan[ch].pcm.loopStart); + pageWrite(0x20|ch,0x02,chan[ch].pcm.loopEnd); + pageWrite(0x20|ch,0x03,(chan[ch].pcm.reversed)?chan[ch].pcm.loopEnd:chan[ch].pcm.loopStart); + unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); + chan[ch].isReverseLoop=false; + switch (chan[ch].pcm.loopMode) { + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) + default: + break; + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop + loopFlag|=0x0008; + break; + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable + loopFlag|=0x0038; + chan[ch].isReverseLoop=true; + break; + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support + loopFlag|=0x0018; + break; + } + // Set loop mode & Bank + pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); + if (chan[ch].pcm.nextFreqOffs!=nextFreqOffs) { + chan[ch].pcm.nextFreqOffs=nextFreqOffs; + chan[ch].noteChanged.offs=1; } } - chan[ch].pcmChanged.changed=0; } + chan[ch].pcmChanged.changed=0; } - chan[ch].transwaveIRQ=false; - } - if (chan[ch].isTranswave) { - pageReadMask(0x00|ch,0x5f,0x00,&chan[ch].cr); - chan[ch].transwaveIRQ=true; - chan[ch].isTranswave=false; } + chan[ch].transwaveIRQ=false; } } + queuedReadState.pop(); } + if (!queuedRead.empty()) { + unsigned char ch=queuedRead.front()&0x1f; + if (chan[ch].isReverseLoop) { // Reversed loop + pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); + chan[ch].isReverseLoop=false; + } + if (chan[ch].isTranswave) { + pageReadMask(0x00|ch,0x5f,0x00,ch,&chan[ch].cr); + chan[ch].transwaveIRQ=true; + chan[ch].isTranswave=false; + } + queuedRead.pop(); + } + isReaded=false; } void DivPlatformES5506::irqb(bool state) { - rRead(0x0e,&irqv,0x9f); + rRead(0x0e,0x80,&irqv,0x9f); irqTrigger=true; } @@ -392,7 +330,7 @@ void DivPlatformES5506::tick(bool sysTick) { signed int k1=chan[i].k1Prev,k2=chan[i].k2Prev; // volume/panning macros if (chan[i].std.vol.had) { - const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax))/0xff; + const unsigned int nextVol=VOL_SCALE_LOG((0xffff*chan[i].vol)/0xff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax,0xffff); if (chan[i].outVol!=nextVol) { chan[i].outVol=nextVol; if (!isMuted[i]) { @@ -401,7 +339,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panL.had) { - const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax))/0xffff; + const unsigned int nextLVol=VOL_SCALE_LOG((0xffff*chan[i].lVol)/0xff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax,0xffff); if (chan[i].outLVol!=nextLVol) { chan[i].outLVol=nextLVol; if (!isMuted[i]) { @@ -410,7 +348,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panR.had) { - const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax))/0xffff; + const unsigned int nextRVol=VOL_SCALE_LOG((0xffff*chan[i].rVol)/0xff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax,0xffff); if (chan[i].outRVol!=nextRVol) { chan[i].outRVol=nextRVol; if (!isMuted[i]) { @@ -458,18 +396,19 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].std.ex1.had) { switch (chan[i].std.ex1.mode) { - case 0: // relative - if (chan[i].k1Offs!=chan[i].std.ex1.val) { - chan[i].k1Offs=chan[i].std.ex1.val; - chan[i].filterChanged.k1=1; - } - break; - case 1: // absolute + case 0: // absolute if (chan[i].filter.k1!=(chan[i].std.ex1.val&0xffff)) { chan[i].filter.k1=chan[i].std.ex1.val&0xffff; chan[i].filterChanged.k1=1; } break; + case 1: // relative + if (chan[i].k1Offs!=chan[i].std.ex1.val) { + chan[i].k1Offs=chan[i].std.ex1.val; + chan[i].filterChanged.k1=1; + } + break; + /* case 2: { // delta const signed int next_k1=CLAMP(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); if (chan[i].k1Offs!=next_k1) { @@ -478,24 +417,26 @@ void DivPlatformES5506::tick(bool sysTick) { } break; } + */ default: break; } } if (chan[i].std.ex2.had) { switch (chan[i].std.ex2.mode) { - case 0: // relative - if (chan[i].k2Offs!=chan[i].std.ex1.val) { - chan[i].k2Offs=chan[i].std.ex1.val; - chan[i].filterChanged.k2=1; - } - break; - case 1: // absolute + case 0: // absolute if (chan[i].filter.k2!=(chan[i].std.ex2.val&0xffff)) { chan[i].filter.k2=chan[i].std.ex2.val&0xffff; chan[i].filterChanged.k2=1; } break; + case 1: // relative + if (chan[i].k2Offs!=chan[i].std.ex1.val) { + chan[i].k2Offs=chan[i].std.ex1.val; + chan[i].filterChanged.k2=1; + } + break; + /* case 2: { // delta const signed int next_k2=CLAMP(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); if (chan[i].k2Offs!=next_k2) { @@ -504,6 +445,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; } + */ default: break; } @@ -621,13 +563,13 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].volChanged.changed) { if (!isMuted[i]) { // calculate volume (16 bit) if (chan[i].volChanged.lVol) { - chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; + chan[i].resLVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outLVol,0xffff); if (!chan[i].keyOn) { pageWrite(0x00|i,0x02,chan[i].resLVol); } } if (chan[i].volChanged.rVol) { - chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; + chan[i].resRVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outRVol,0xffff); if (!chan[i].keyOn) { pageWrite(0x00|i,0x04,chan[i].resRVol); } @@ -655,11 +597,11 @@ void DivPlatformES5506::tick(bool sysTick) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -693,13 +635,13 @@ void DivPlatformES5506::tick(bool sysTick) { if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && next<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (next>=0 && next<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && nextsong.sampleLen))) { - DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[next]; + DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; int sample=next; if (ins->amiga.transWave.enable) { sample=transWaveInd.ind; } else if (ins->amiga.useNoteMap) { - sample=noteMapind.ind; + sample=noteMapind.map; } if (sample>=0 && samplesong.sampleLen) { sampleVaild=true; @@ -723,12 +665,12 @@ void DivPlatformES5506::tick(bool sysTick) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -805,8 +747,8 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].pcmChanged.position) { if (!chan[i].keyOn) { - pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart); - pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd); + pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); + pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); } chan[i].pcmChanged.position=0; } @@ -815,17 +757,17 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) default: break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable loopFlag|=0x0038; chan[i].isReverseLoop=true; break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; } @@ -844,14 +786,14 @@ void DivPlatformES5506::tick(bool sysTick) { pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300); } if (chan[i].filterChanged.k2) { - if (chan[i].std.ex2.mode!=1) { // Relative + if (chan[i].std.ex2.mode!=0) { // Relative k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); } else { k2=chan[i].filter.k2; } } if (chan[i].filterChanged.k1) { - if (chan[i].std.ex1.mode!=1) { // Relative + if (chan[i].std.ex1.mode!=0) { // Relative k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); } else { k1=chan[i].filter.k1; @@ -921,8 +863,8 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x00|i,0x07,0xffff); // Set K1 and K2 to 0xffff pageWrite(0x00|i,0x09,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay pageWrite(0x00|i,0x01,chan[i].freq); - pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart); - pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd); + pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); + pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); // initialize envelope pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8); pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8); @@ -930,14 +872,14 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); // initialize filter pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300); - if ((chan[i].std.ex2.mode!=1) && (chan[i].std.ex2.had)) { + if ((chan[i].std.ex2.mode!=0) && (chan[i].std.ex2.had)) { k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); } else { k2=chan[i].filter.k2; } pageWrite(0x00|i,0x07,k2); chan[i].k2Prev=k2; - if ((chan[i].std.ex1.mode!=1) && (chan[i].std.ex1.had)) { + if ((chan[i].std.ex1.mode!=0) && (chan[i].std.ex1.had)) { k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); } else { k1=chan[i].filter.k1; @@ -949,17 +891,17 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) default: break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable loopFlag|=0x0038; chan[i].isReverseLoop=true; break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; } @@ -1001,13 +943,13 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.ind<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (ins->amiga.initSample>=0 && ins->amiga.initSamplesong.sampleLen))) { - DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[c.value]; + DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[c.value]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; int sample=ins->amiga.initSample; if (ins->amiga.transWave.enable) { sample=transWaveInd.ind; } else if (ins->amiga.useNoteMap) { - sample=noteMapind.ind; + sample=noteMapind.map; } if (sample>=0 && samplesong.sampleLen) { sampleVaild=true; @@ -1033,12 +975,12 @@ int DivPlatformES5506::dispatch(DivCommand c) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[c.chan].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[c.chan].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -1093,10 +1035,10 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].outVol=(0xffff*chan[c.chan].vol)/0xff; } if (!chan[c.chan].std.panL.will) { - chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xff; + chan[c.chan].outLVol=(0xffff*chan[c.chan].lVol)/0xff; } if (!chan[c.chan].std.panR.will) { - chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xff; + chan[c.chan].outRVol=(0xffff*chan[c.chan].rVol)/0xff; } chan[c.chan].active=true; chan[c.chan].keyOn=true; @@ -1142,7 +1084,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].lVol!=(unsigned int)(c.value)) { chan[c.chan].lVol=c.value; if (!chan[c.chan].std.panL.has) { - chan[c.chan].outLVol=(ins->es5506.lVol*c.value)/0xff; + chan[c.chan].outLVol=(0xffff*c.value)/0xff; if (!isMuted[c.chan]) { chan[c.chan].volChanged.lVol=1; } @@ -1152,7 +1094,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].rVol!=(unsigned int)(c.value2)) { chan[c.chan].rVol=c.value2; if (!chan[c.chan].std.panR.has) { - chan[c.chan].outRVol=(ins->es5506.rVol*c.value2)/0xff; + chan[c.chan].outRVol=(0xffff*c.value2)/0xff; if (!isMuted[c.chan]) { chan[c.chan].volChanged.rVol=1; } @@ -1336,6 +1278,8 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) { void DivPlatformES5506::reset() { while (!hostIntf32.empty()) hostIntf32.pop(); while (!hostIntf8.empty()) hostIntf8.pop(); + while (!queuedRead.empty()) queuedRead.pop(); + while (!queuedReadState.empty()) queuedReadState.pop(); for (int i=0; i<32; i++) { chan[i]=DivPlatformES5506::Channel(); chan[i].std.setEngine(parent); diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 18b6a4c1a..55f61751c 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -27,7 +27,7 @@ #include #include "../macroInt.h" #include "../sample.h" -#include "sound/es550x/es5506.hpp" +#include "vgsound_emu/src/es550x/es5506.hpp" class DivPlatformES5506: public DivDispatch, public es550x_intf { struct Channel { @@ -60,7 +60,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { length(0), loopStart(0), loopEnd(0), - loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} + loopMode(DIV_SAMPLE_LOOP_MAX) {} } pcm; int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, currNote, ins, wave; unsigned int volMacroMax, panMacroMax; @@ -213,6 +213,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { signed short* sampleMem; // ES5506 uses 16 bit data bus for samples size_t sampleMemLen; struct QueuedHostIntf { + unsigned char state; unsigned char step; unsigned char addr; unsigned int val; @@ -221,6 +222,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned short delay; bool isRead; QueuedHostIntf(unsigned char s, unsigned char a, unsigned int v, unsigned int m=(unsigned int)(~0), unsigned short d=0): + state(0), step(s), addr(a), val(v), @@ -228,7 +230,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { read(NULL), delay(0), isRead(false) {} - QueuedHostIntf(unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0): + QueuedHostIntf(unsigned char st, unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0): + state(st), step(s), addr(a), val(0), @@ -237,8 +240,17 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { delay(d), isRead(true) {} }; + struct QueuedReadState { + unsigned int* read; + unsigned char state; + QueuedReadState(unsigned int* r, unsigned char s): + read(r), + state(s) {} + }; std::queue hostIntf32; std::queue hostIntf8; + std::queue queuedRead; + std::queue queuedReadState; int cycle, curPage; unsigned char maskedVal; unsigned int irqv; @@ -288,7 +300,6 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual size_t getSampleMemUsage(int index = 0) override; virtual void renderSamples() override; virtual const char** getRegisterSheet() override; - virtual const char* getEffectName(unsigned char effect) override; virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override; virtual void quit() override; DivPlatformES5506(): diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp deleted file mode 100644 index c2644fbdb..000000000 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - see es550x.cpp for more info -*/ - -#include "es5504.hpp" - -// Internal functions -void es5504_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // /CAS high, E low: get sample address - if (m_cas.falling_edge()) - { - // /CAS low, E low: fetch sample - if (!m_e.current_edge()) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - // E - if (m_clkin.falling_edge()) // falling edge triggers E clock - { - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) // Host access - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - voice_tick(); - } - if (m_e.falling_edge()) // Voice memory - { - m_host_intf.m_host_access = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5504_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5504_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output (Multiplexed analog output) - m_ch[m_voice[m_voice_cycle].m_cr.ca] = m_voice[m_voice_cycle].m_ch; - - if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices - { - m_voice_end = true; - m_voice_cycle = 0; - } - - m_voice_fetch = 0; - } -} - -void es5504_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.ca, 0, 3), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); -} - -void es5504_core::voice_t::tick(u8 voice) -{ - m_ch = 0; - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - // Send to output - m_ch = ((sign_ext(m_filter.m_o4_1, 16) >> 3) * m_volume) >> 12; // Analog multiplied in real chip, 13/12 bit ladder DAC - - // ALU execute - if (m_alu.tick()) - { - m_alu.loop_exec(); - } - - // ADC check - adc_exec(); - } - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// ADC; Correct? -void es5504_core::voice_t::adc_exec() -{ - if (m_cr.adc) - m_host.m_adc = m_host.m_intf.adc_r() & ~0x7; -} - -void es5504_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_adc = 0; - std::fill(std::begin(m_ch), std::end(m_ch), 0); -} - -void es5504_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_volume = 0; - m_ch = 0; -} - -// Accessors -u16 es5504_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5504_core::host_w(u8 address, u16 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u16 es5504_core::read(u8 address, bool cpu_access) -{ - return regs_r(m_page, address, cpu_access); -} - -void es5504_core::write(u8 address, u16 data, bool cpu_access) -{ - regs_w(m_page, address, data, cpu_access); -} - -u16 es5504_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u16 ret = 0xffff; - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 12: // A/D (A to D Convert/Test) - ret = (ret & ~0xfffb) | (m_adc & 0xfffb); - break; - case 13: // ACT (Number of voices) - ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 14: // IRQV (Interrupting voice vector) - ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(ret, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - ret = (ret & ~0x3f) | bitfield(m_page, 0, 6); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - if (voice < 25) - { - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - ret = v.m_filter.m_o4_1; - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - ret = v.m_filter.m_o3_2; - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - ret = v.m_filter.m_o3_1; - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - ret = v.m_filter.m_o2_2; - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - ret = v.m_filter.m_o2_1; - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - ret = v.m_filter.m_o1_1; - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - ret = (ret & ~0xff) | - (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) - | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) - | (v.m_cr.adc ? 0x04 : 0x00) - | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) - | (v.m_alu.m_cr.ble ? 0x10 : 0x00) - | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) - | (v.m_alu.m_cr.dir ? 0x40 : 0x00) - | (v.m_alu.m_cr.irq ? 0x80 : 0x00); - break; - case 1: // FC (Frequency Control) - ret = (ret & ~0xfffe) | (v.m_alu.m_fc << 1); - break; - case 2: // STRT-H (Loop Start Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); - break; - case 3: // STRT-L (Loop Start Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); - break; - case 5: // END-L (Loop End Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); - break; - case 8: // Volume - ret = (ret & ~0xfff0) | ((v.m_volume << 4) & 0xfff0); - break; - case 9: // CA (Filter Config, Channel Assign) - ret = (ret & ~0x3f) | - bitfield(v.m_cr.ca, 0, 4) - | (bitfield(v.m_filter.m_lp, 0, 2) << 4); - break; - case 10: // ACCH (Accumulator High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); - break; - case 11: // ACCL (Accumulator Low) - ret = bitfield(v.m_alu.m_accum, 0, 16); - break; - } - } - } - } - - return ret; -} - -void es5504_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) -{ - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 12: // A/D (A to D Convert/Test) - if (bitfield(m_adc, 0)) // Writable ADC - { - m_adc = (m_adc & 7) | (data & ~7); - m_intf.adc_w(m_adc & ~7); - } - m_adc = (m_adc & ~3) | (data & 3); - break; - case 13: // ACT (Number of voices) - m_active = std::min(24, bitfield(data, 0, 5)); - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 6); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - if (voice < 25) - { - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(data, 16); - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(data, 16); - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(data, 16); - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(data, 16); - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(data, 16); - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(data, 16); - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_cr.adc = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 1, 15); - break; - case 2: // STRT-H (Loop Start Register High) - v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 3: // STRT-L (Loop Start Register Low) - v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 5: // END-L (Loop End Register Low) - v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = data & 0xfff0; - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = data & 0xfff0; - break; - case 8: // Volume - v.m_volume = bitfield(data, 4, 12); - break; - case 9: // CA (Filter Config, Channel Assign) - v.m_cr.ca = bitfield(data, 0, 4); - v.m_filter.m_lp = bitfield(data, 4, 2); - break; - case 10: // ACCH (Accumulator High) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 11: // ACCL (Accumulator Low) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp deleted file mode 100644 index be6e44d11..000000000 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5504_HPP -#define _VGSOUND_EMU_ES5504_HPP - -#pragma once - -// ES5504 specific -class es5504_core : public es550x_shared_core -{ -public: - // constructor - es5504_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this} - { - } - // host interface - u16 host_r(u8 address); - void host_w(u8 address, u16 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // 16 analog output channels - s32 out(u8 ch) { return m_ch[ch & 0xf]; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u16 read(u8 address, bool cpu_access = false); - void write(u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } - - // per-voice outputs - s32 voice_out(u8 voice) { return (voice < 25) ? m_voice[voice].m_ch : 0; } - -protected: - virtual inline u8 max_voices() override { return 25; } - virtual void voice_tick() override; - -private: - // es5504 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5504_core &host) - : es550x_voice_t(20, 9, false) - , m_host(host) - {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - void adc_exec(); - - // registers - es5504_core &m_host; - u16 m_volume = 0; // 12 bit Volume - s32 m_ch = 0; // channel outputs - }; - - voice_t m_voice[25]; // 25 voices - u16 m_adc = 0; // ADC register - s32 m_ch[16] = {0}; // 16 channel outputs -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp deleted file mode 100644 index fae6b3930..000000000 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ /dev/null @@ -1,606 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5505 emulation core - - see es550x.cpp for more info -*/ - -#include "es5505.hpp" - -// Internal functions -void es5505_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // CLKIN - if (m_clkin.tick()) - { - // SERBCLK - if (m_clkin.m_edge.m_changed) // BCLK is freely running clock - { - if (m_bclk.tick()) - { - m_intf.bclk(m_bclk.current_edge()); - // Serial output - if (m_bclk.falling_edge()) - { - // SERLRCLK - if (m_lrclk.tick()) - m_intf.lrclk(m_lrclk.current_edge()); - } - // SERWCLK - if (m_lrclk.m_edge.m_changed) - m_wclk = 0; - if (m_bclk.falling_edge()) - { - if (m_wclk == ((m_sermode.sony_bb) ? 1 : 0)) - { - if (m_lrclk.current_edge()) - { - for (int i = 0; i < 4; i++) - { - // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); - // clamp to 16 bit (upper 5 bits are overflow guard bits) - m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x8000, 0x7fff); - m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x8000, 0x7fff); - // set signed - if (m_output_latch[i].m_left < 0) - m_output_temp[i].m_left = -1; - if (m_output_latch[i].m_right < 0) - m_output_temp[i].m_right = -1; - } - } - m_wclk_lr = m_lrclk.current_edge(); - m_output_bit = 16; - } - s8 output_bit = --m_output_bit; - if (m_output_bit >= 0) - { - for (int i = 0; i < 4; i++) - { - if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); - else // Left output - m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); - } - } - m_wclk++; - } - } - } - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // /CAS high, E low: get sample address - if (m_cas.falling_edge()) - { - // /CAS low, E low: fetch sample - if (!m_e.current_edge()) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - // E - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) // Host access - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - voice_tick(); - } - else if (m_e.falling_edge()) // Voice memory - { - m_host_intf.m_host_access = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5505_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // output - for (int c = 0; c < 4; c++) - { - m_output[c].m_left = clamp(m_ch[c].m_left, -0x8000, 0x7fff); - m_output[c].m_right = clamp(m_ch[c].m_right, -0x8000, 0x7fff); - } - - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5505_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output - if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices - { - m_voice_end = true; - m_voice_cycle = 0; - for (auto & elem : m_ch) - elem.reset(); - - for (auto & elem : m_voice) - { - m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_left += elem.m_ch.m_left; - m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_right += elem.m_ch.m_right; - elem.m_ch.reset(); - } - } - m_voice_fetch = 0; - } -} - -void es5505_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); -} - -void es5505_core::voice_t::tick(u8 voice) -{ - m_ch.reset(); - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - // Send to output - m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); - m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); - - // ALU execute - if (m_alu.tick()) - m_alu.loop_exec(); - } - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// volume calculation -s32 es5505_core::voice_t::volume_calc(u8 volume, s32 in) -{ - u8 exponent = bitfield(volume, 4, 4); - u8 mantissa = bitfield(volume, 0, 4); - return exponent ? (in * s32(0x10 | mantissa)) >> (20 - exponent) : 0; -} - -void es5505_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_sermode.reset(); - m_bclk.reset(); - m_lrclk.reset(); - m_wclk = 0; - m_wclk_lr = false; - m_output_bit = 0; - for (auto & elem : m_ch) - elem.reset(); - for (auto & elem : m_output) - elem.reset(); - for (auto & elem : m_output_temp) - elem.reset(); - for (auto & elem : m_output_latch) - elem.reset(); -} - -void es5505_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_lvol = 0; - m_rvol = 0; - m_ch.reset(); -} - -// Accessors -u16 es5505_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5505_core::host_w(u8 address, u16 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u16 es5505_core::read(u8 address, bool cpu_access) -{ - return regs_r(m_page, address, cpu_access); -} - -void es5505_core::write(u8 address, u16 data, bool cpu_access) -{ - regs_w(m_page, address, data, cpu_access); -} - -u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u16 ret = 0xffff; - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // ACT (Number of voices) - ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 14: // IRQV (Interrupting voice vector) - ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(ret, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - ret = (ret & ~0x7f) | bitfield(m_page, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - if (!cpu_access) // CPU can't read here - ret = m_ch[bitfield(address, 0, 2)].m_left; - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - if (!cpu_access) // CPU can't read here - ret = m_ch[bitfield(address, 0, 2)].m_right; - break; - case 6: // CH3L (Channel 3 Left) - if ((!cpu_access) || m_sermode.adc) - ret = m_ch[3].m_left; - break; - case 7: // CH3R (Channel 3 Right) - if ((!cpu_access) || m_sermode.adc) - ret = m_ch[3].m_right; - break; - case 8: // SERMODE (Serial Mode) - ret = (ret & ~0xf807) | - (m_sermode.adc ? 0x01 : 0x00) - | (m_sermode.test ? 0x02 : 0x00) - | (m_sermode.sony_bb ? 0x04 : 0x00) - | (bitfield(m_sermode.msb, 0, 5) << 11); - break; - case 9: // PAR (Port A/D Register) - ret = (ret & ~0x3f) | (m_intf.adc_r() & ~0x3f); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - ret = v.m_filter.m_o4_1; - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - ret = v.m_filter.m_o3_2; - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - ret = v.m_filter.m_o3_1; - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - ret = v.m_filter.m_o2_2; - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - ret = v.m_filter.m_o2_1; - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - ret = v.m_filter.m_o1_1; - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - ret = (ret & ~0xfff) | - (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) - | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) - | (bitfield(v.m_cr.bs, 0) ? 0x04 : 0x00) - | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) - | (v.m_alu.m_cr.ble ? 0x10 : 0x00) - | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) - | (v.m_alu.m_cr.dir ? 0x40 : 0x00) - | (v.m_alu.m_cr.irq ? 0x80 : 0x00) - | (bitfield(v.m_cr.ca, 0, 2) << 8) - | (bitfield(v.m_filter.m_lp, 0, 2) << 10); - break; - case 1: // FC (Frequency Control) - ret = (ret & ~0xfffe) | (bitfield(v.m_alu.m_fc, 0, 15) << 1); - break; - case 2: // STRT-H (Loop Start Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); - break; - case 3: // STRT-L (Loop Start Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); - break; - case 5: // END-L (Loop End Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); - break; - case 8: // LVOL (Left Volume) - ret = (ret & ~0xff00) | ((v.m_lvol << 8) & 0xff00); - break; - case 9: // RVOL (Right Volume) - ret = (ret & ~0xff00) | ((v.m_rvol << 8) & 0xff00); - break; - case 10: // ACCH (Accumulator High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); - break; - case 11: // ACCL (Accumulator Low) - ret = bitfield(v.m_alu.m_accum, 0, 16); - break; - } - } - } - } - - return ret; -} - -void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) -{ - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 13: // ACT (Number of voices) - m_active = std::max(7, bitfield(data, 0, 5)); - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 7); - break; - } - } - else // Voice specific registers - { - if (bitfield(page, 6)) // Channel registers - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - if (m_sermode.test) - m_ch[0].m_left = data; - break; - case 1: // CH0R (Channel 0 Right) - if (m_sermode.test) - m_ch[0].m_right = data; - break; - case 2: // CH1L (Channel 1 Left) - if (m_sermode.test) - m_ch[1].m_left = data; - break; - case 3: // CH1R (Channel 1 Right) - if (m_sermode.test) - m_ch[1].m_right = data; - break; - case 4: // CH2L (Channel 2 Left) - if (m_sermode.test) - m_ch[2].m_left = data; - break; - case 5: // CH2R (Channel 2 Right) - if (m_sermode.test) - m_ch[2].m_right = data; - break; - case 6: // CH3L (Channel 3 Left) - if (m_sermode.test) - m_ch[3].m_left = data; - break; - case 7: // CH3R (Channel 3 Right) - if (m_sermode.test) - m_ch[3].m_right = data; - break; - case 8: // SERMODE (Serial Mode) - m_sermode.adc = bitfield(data, 0); - m_sermode.test = bitfield(data, 1); - m_sermode.sony_bb = bitfield(data, 2); - m_sermode.msb = bitfield(data, 11, 5); - break; - case 9: // PAR (Port A/D Register) - // Read only - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(data, 16); - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(data, 16); - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(data, 16); - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(data, 16); - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(data, 16); - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(data, 16); - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_cr.bs = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_cr.ca = bitfield(data, 8, 2); - v.m_filter.m_lp = bitfield(data, 10, 2); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 1, 15); - break; - case 2: // STRT-H (Loop Start Register High) - v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 3: // STRT-L (Loop Start Register Low) - v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 5: // END-L (Loop End Register Low) - v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = data & 0xfff0; - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = data & 0xfff0; - break; - case 8: // LVOL (Left Volume) - v.m_lvol = bitfield(data, 8, 8); - break; - case 9: // RVOL (Right Volume) - v.m_rvol = bitfield(data, 8, 8); - break; - case 10: // ACCH (Accumulator High) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 11: // ACCL (Accumulator Low) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp deleted file mode 100644 index 6498ddff0..000000000 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5505_HPP -#define _VGSOUND_EMU_ES5505_HPP - -#pragma once - -// ES5505 specific -class es5505_core : public es550x_shared_core -{ -public: - // constructor - es5505_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this} - { - } - // host interface - u16 host_r(u8 address); - void host_w(u8 address, u16 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // clock outputs - bool bclk() { return m_bclk.current_edge(); } - bool bclk_rising_edge() { return m_bclk.rising_edge(); } - bool bclk_falling_edge() { return m_bclk.falling_edge(); } - - // Input mode for Channel 3 - void lin(s32 in) { if (m_sermode.adc) { m_ch[3].m_left = in; } } - void rin(s32 in) { if (m_sermode.adc) { m_ch[3].m_right = in; } } - - // 4 stereo output channels - s32 lout(u8 ch) { return m_ch[ch & 0x3].m_left; } - s32 rout(u8 ch) { return m_ch[ch & 0x3].m_right; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u16 read(u8 address, bool cpu_access = false); - void write(u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } - - // per-voice outputs - s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } - s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } - -protected: - virtual inline u8 max_voices() override { return 32; } - virtual void voice_tick() override; - -private: - struct output_t - { - void reset() - { - m_left = 0; - m_right = 0; - }; - - s32 m_left = 0; - s32 m_right = 0; - }; - - // es5505 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5505_core &host) - : es550x_voice_t(20, 9, false) - , m_host(host) - {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - s32 volume_calc(u8 volume, s32 in); - - // registers - es5505_core &m_host; - u8 m_lvol = 0; // Left volume - u8 m_rvol = 0; // Right volume - output_t m_ch; // channel output - }; - - struct sermode_t - { - sermode_t() - : adc(0) - , test(0) - , sony_bb(0) - , msb(0) - {}; - - void reset() - { - adc = 0; - test = 0; - sony_bb = 0; - msb = 0; - } - - u8 adc : 1; // A/D - u8 test : 1; // Test - u8 sony_bb : 1; // Sony/BB format serial output - u8 msb : 5; // Serial output MSB - }; - - voice_t m_voice[32]; // 32 voices - // Serial related stuffs - sermode_t m_sermode; // Serial mode register - clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock - clock_pulse_t m_lrclk; // LRCLK - s16 m_wclk = 0; // WCLK - bool m_wclk_lr = false; // WCLK, L/R output select - s8 m_output_bit = 0; // Bit position in output - output_t m_ch[4]; // 4 stereo output channels - output_t m_output[4]; // Serial outputs - output_t m_output_temp[4]; // temporary signal for serial output - output_t m_output_latch[4]; // output latch -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp deleted file mode 100644 index c401a4b63..000000000 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ /dev/null @@ -1,794 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5506 emulation core - - see es550x.cpp for more info -*/ - -#include "es5506.hpp" - -// Internal functions -void es5506_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // CLKIN - if (m_clkin.tick()) - { - // BCLK - if (m_clkin.m_edge.m_changed && (!m_mode.bclk_en)) // BCLK is freely running clock - { - if (m_bclk.tick()) - { - m_intf.bclk(m_bclk.current_edge()); - // Serial output - if (!m_mode.lrclk_en) - { - if (m_bclk.falling_edge()) - { - // LRCLK - if (m_lrclk.tick()) - { - m_intf.lrclk(m_lrclk.current_edge()); - if (m_lrclk.rising_edge()) - { - m_w_st_curr = m_w_st; - m_w_end_curr = m_w_end; - } - if (m_lrclk.falling_edge()) // update width - m_lrclk.set_width_latch(m_lr_end); - } - } - } - // WCLK - if (!m_mode.wclk_en) - { - if (!m_mode.lrclk_en) - { - if (m_lrclk.m_edge.m_changed) - m_wclk = 0; - } - if (m_bclk.falling_edge()) - { - if (m_wclk == m_w_st_curr) - { - m_intf.wclk(true); - if (m_lrclk.current_edge()) - { - for (int i = 0; i < 6; i++) - { - // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); - // clamp to 20 bit (upper 3 bits are overflow guard bits) - m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x80000, 0x7ffff); - m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x80000, 0x7ffff); - // set signed - if (m_output_latch[i].m_left < 0) - m_output_temp[i].m_left = -1; - if (m_output_latch[i].m_right < 0) - m_output_temp[i].m_right = -1; - } - } - m_wclk_lr = m_lrclk.current_edge(); - m_output_bit = 20; - } - if (m_wclk < m_w_end_curr) - { - s8 output_bit = --m_output_bit; - if (m_output_bit >= 0) - { - for (int i = 0; i < 6; i++) - { - if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); - else // Left output - m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); - } - } - } - if (m_wclk == m_w_end_curr) - m_intf.wclk(false); - - m_wclk++; - } - } - } - } - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // single OTTO master mode, /CAS high, E low: get sample address - // single OTTO early mode, /CAS falling, E high: get sample address - if (m_cas.falling_edge()) - { - if (!m_e.current_edge()) - { - // single OTTO master mode, /CAS low, E low: fetch sample - if (m_mode.master) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - else if (m_e.current_edge()) - { - // dual OTTO slave mode, /CAS low, E high: fetch sample - if (m_mode.dual && (!m_mode.master)) // Dual OTTO, slave mode - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - } - // E - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - } - else if (m_e.falling_edge()) - { - m_host_intf.m_host_access = false; - voice_tick(); - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 0)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5506_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // output - if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.wclk_en)) && (m_w_st < m_w_end)) - { - const int output_bits = 20 - (m_w_end - m_w_st); - if (output_bits < 20) - { - for (int c = 0; c < 6; c++) - { - m_output[c].m_left = clamp(m_ch[c].m_left, -0x80000, 0x7ffff) >> output_bits; - m_output[c].m_right = clamp(m_ch[c].m_right, -0x80000, 0x7ffff) >> output_bits; - } - } - } - else - { - for (int c = 0; c < 6; c++) - { - m_output[c].m_left = 0; - m_output[c].m_right = 0; - } - } - - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5506_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output - if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices - { - m_voice_end = true; - m_voice_cycle = 0; - for (auto & elem : m_ch) - elem.reset(); - - for (auto & elem : m_voice) - { - const u8 ca = bitfield(elem.m_cr.ca, 0, 3); - if (ca < 6) - { - m_ch[ca].m_left += elem.m_ch.m_left; - m_ch[ca].m_right += elem.m_ch.m_right; - } - elem.m_ch.reset(); - } - } - m_voice_fetch = 0; - } -} - -void es5506_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0, 1), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); - if (m_cr.cmpd) // Decompress (Upper 8 bit is used for compressed format) - m_alu.m_sample[cycle] = decompress(bitfield(m_alu.m_sample[cycle], 8, 8)); -} - -void es5506_core::voice_t::tick(u8 voice) -{ - m_ch.reset(); - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - if (!m_mute) - { - // Send to output - m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); - m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); - } - - // ALU execute - if (m_alu.tick()) - m_alu.loop_exec(); - } - // Envelope - if (m_ecount != 0) - { - // Left and Right volume - if (bitfield(m_lvramp, 0, 8) != 0) - m_lvol = clamp(m_lvol + sign_ext(bitfield(m_lvramp, 0, 8), 8), 0, 0xffff); - if (bitfield(m_rvramp, 0, 8) != 0) - m_rvol = clamp(m_rvol + sign_ext(bitfield(m_rvramp, 0, 8), 8), 0, 0xffff); - - // Filter coeffcient - if ((m_k1ramp.ramp != 0) && ((m_k1ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) - m_filter.m_k1 = clamp(m_filter.m_k1 + sign_ext(m_k1ramp.ramp, 8), 0, 0xffff); - if ((m_k2ramp.ramp != 0) && ((m_k2ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) - m_filter.m_k2 = clamp(m_filter.m_k2 + sign_ext(m_k2ramp.ramp, 8), 0, 0xffff); - - m_ecount--; - } - m_filtcount = bitfield(m_filtcount + 1, 0, 3); - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// Compressed format -s16 es5506_core::voice_t::decompress(u8 sample) -{ - u8 exponent = bitfield(sample, 5, 3); - u8 mantissa = bitfield(sample, 0, 5); - return (exponent > 0) ? - s16(((bitfield(mantissa, 4) ? 0x10 : ~0x1f) | bitfield(mantissa, 0, 4)) << (4 + (exponent - 1))) : - s16(((bitfield(mantissa, 4) ? ~0xf : 0) | bitfield(mantissa, 0, 4)) << 4); -} - -// volume calculation -s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in) -{ - u8 exponent = bitfield(volume, 12, 4); - u8 mantissa = bitfield(volume, 4, 8); - return (in * s32(0x100 | mantissa)) >> (20 - exponent); -} - -void es5506_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_read_latch = 0xffffffff; - m_write_latch = 0xffffffff; - m_w_st = 0; - m_w_end = 0; - m_lr_end = 0; - m_w_st_curr = 0; - m_w_end_curr = 0; - m_mode.reset(); - m_bclk.reset(); - m_lrclk.reset(32); - m_wclk = 0; - m_wclk_lr = false; - m_output_bit = 0; - for (auto & elem : m_ch) - elem.reset(); - for (auto & elem : m_output) - elem.reset(); - for (auto & elem : m_output_temp) - elem.reset(); - for (auto & elem : m_output_latch) - elem.reset(); -} - -void es5506_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_lvol = 0; - m_lvramp = 0; - m_rvol = 0; - m_rvramp = 0; - m_ecount = 0; - m_k2ramp.reset(); - m_k1ramp.reset(); - m_filtcount = 0; - m_ch.reset(); - m_mute = false; -} - -// Accessors -u8 es5506_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5506_core::host_w(u8 address, u8 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u8 es5506_core::read(u8 address, bool cpu_access) -{ - const u8 byte = bitfield(address, 0, 2); // byte select - const u8 shift = 24 - (byte << 3); - if (byte != 0) // Return already latched register if not highest byte is accessing - return bitfield(m_read_latch, shift, 8); - - address = bitfield(address, 2, 4); // 4 bit address for CPU access - - // get read register - m_read_latch = regs_r(m_page, address, cpu_access); - - return bitfield(m_read_latch, 24, 8); -} - -void es5506_core::write(u8 address, u8 data, bool cpu_access) -{ - const u8 byte = bitfield(address, 0, 2); // byte select - const u8 shift = 24 - (byte << 3); - address = bitfield(address, 2, 4); // 4 bit address for CPU access - - // Update register latch - m_write_latch = (m_write_latch & ~(0xff << shift)) | (u32(data) << shift); - - if (byte != 3) // Wait until lowest byte is writed - return; - - regs_w(m_page, address, m_write_latch, cpu_access); - - // Reset latch - m_write_latch = 0; -} - -u32 es5506_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u32 read_latch = 0xffffffff; - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // POT (Pot A/D Register) - read_latch = (read_latch & ~0x3ff) | bitfield(m_intf.adc_r(), 0, 10); - break; - case 14: // IRQV (Interrupting voice vector) - read_latch = (read_latch & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(read_latch, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - read_latch = (read_latch & ~0x7f) | bitfield(m_page, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers are Write only - { - if (!cpu_access) // CPU can't read here - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - case 6: // CH3L (Channel 3 Left) - case 8: // CH4L (Channel 4 Left) - case 10: // CH5L (Channel 5 Left) - read_latch = m_ch[bitfield(address, 1, 3)].m_left; - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - case 7: // CH3R (Channel 3 Right) - case 9: // CH4R (Channel 4 Right) - case 11: // CH5R (Channel 5 Right) - read_latch = m_ch[bitfield(address, 1, 3)].m_right; - break; - } - } - } - else - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 0: // CR (Control Register) - read_latch = (read_latch & ~0xffff) | - (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) - | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) - | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) - | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) - | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) - | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) - | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) - | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) - | (bitfield(v.m_filter.m_lp, 0, 2) << 8) - | (bitfield(v.m_cr.ca, 0, 3) << 10) - | (v.m_cr.cmpd ? 0x2000 : 0x0000) - | (bitfield(v.m_cr.bs, 0, 2) << 14); - break; - case 1: // START (Loop Start Register) - read_latch = (read_latch & ~0xfffff800) | (v.m_alu.m_start & 0xfffff800); - break; - case 2: // END (Loop End Register) - read_latch = (read_latch & ~0xffffff80) | (v.m_alu.m_end & 0xffffff80); - break; - case 3: // ACCUM (Accumulator Register) - read_latch = v.m_alu.m_accum; - break; - case 4: // O4(n-1) (Filter 4 Temp Register) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o4_1, 0, 18); - else - read_latch = v.m_filter.m_o4_1; - break; - case 5: // O3(n-2) (Filter 3 Temp Register #2) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_2, 0, 18); - else - read_latch = v.m_filter.m_o3_2; - break; - case 6: // O3(n-1) (Filter 3 Temp Register #1) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_1, 0, 18); - else - read_latch = v.m_filter.m_o3_1; - break; - case 7: // O2(n-2) (Filter 2 Temp Register #2) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_2, 0, 18); - else - read_latch = v.m_filter.m_o2_2; - break; - case 8: // O2(n-1) (Filter 2 Temp Register #1) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_1, 0, 18); - else - read_latch = v.m_filter.m_o2_1; - break; - case 9: // O1(n-1) (Filter 1 Temp Register) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o1_1, 0, 18); - else - read_latch = v.m_filter.m_o1_1; - break; - case 10: // W_ST (Word Clock Start Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_w_st, 0, 7); - break; - case 11: // W_END (Word Clock End Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_w_end, 0, 7); - break; - case 12: // LR_END (Left/Right Clock End Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_lr_end, 0, 7); - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - read_latch = (read_latch & ~0xffff) | - (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) - | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) - | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) - | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) - | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) - | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) - | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) - | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) - | (bitfield(v.m_filter.m_lp, 0, 2) << 8) - | (bitfield(v.m_cr.ca, 0, 3) << 10) - | (v.m_cr.cmpd ? 0x2000 : 0x0000) - | (bitfield(v.m_cr.bs, 0, 2) << 14); - break; - case 1: // FC (Frequency Control) - read_latch = (read_latch & ~0x1ffff) | bitfield(v.m_alu.m_fc, 0, 17); - break; - case 2: // LVOL (Left Volume) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_lvol, 0, 16); - break; - case 3: // LVRAMP (Left Volume Ramp) - read_latch = (read_latch & ~0xff00) | (bitfield(v.m_lvramp, 0, 8) << 8); - break; - case 4: // RVOL (Right Volume) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_rvol, 0, 16); - break; - case 5: // RVRAMP (Right Volume Ramp) - read_latch = (read_latch & ~0xff00) | (bitfield(v.m_rvramp, 0, 8) << 8); - break; - case 6: // ECOUNT (Envelope Counter) - read_latch = (read_latch & ~0x01ff) | bitfield(v.m_ecount, 0, 9); - break; - case 7: // K2 (Filter Cutoff Coefficient #2) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k2, 0, 16); - break; - case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) - read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k2ramp.ramp, 0, 8) << 8) | (v.m_k2ramp.slow ? 0x0001 : 0x0000); - break; - case 9: // K1 (Filter Cutoff Coefficient #1) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k1, 0, 16); - break; - case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) - read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k1ramp.ramp, 0, 8) << 8) | (v.m_k1ramp.slow ? 0x0001 : 0x0000); - break; - case 11: // ACT (Number of voices) - read_latch = (read_latch & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 12: // MODE (Global Mode) - read_latch = (read_latch & ~0x1f) | - (m_mode.lrclk_en ? 0x01 : 0x00) - | (m_mode.wclk_en ? 0x02 : 0x00) - | (m_mode.bclk_en ? 0x04 : 0x00) - | (m_mode.master ? 0x08 : 0x00) - | (m_mode.dual ? 0x10 : 0x00); - break; - } - } - } - } - - return read_latch; -} - -void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) -{ - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // POT (Pot A/D Register) - // Read only - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers are Write only, and for test purposes - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - case 6: // CH3L (Channel 3 Left) - case 8: // CH4L (Channel 4 Left) - case 10: // CH5L (Channel 5 Left) - m_ch[bitfield(address, 1, 3)].m_left = sign_ext(bitfield(data, 0, 23), 23); - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - case 7: // CH3R (Channel 3 Right) - case 9: // CH4R (Channel 4 Right) - case 11: // CH5R (Channel 5 Right) - m_ch[bitfield(address, 1, 3)].m_right = sign_ext(bitfield(data, 0, 23), 23); - break; - } - } - else - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_alu.m_cr.lei = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_filter.m_lp = bitfield(data, 8, 2); - v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); - v.m_cr.cmpd = bitfield(data, 13); - v.m_cr.bs = bitfield(data, 14, 2); - break; - case 1: // START (Loop Start Register) - v.m_alu.m_start = data & 0xfffff800; - break; - case 2: // END (Loop End Register) - v.m_alu.m_end = data & 0xffffff80; - break; - case 3: // ACCUM (Accumulator Register) - v.m_alu.m_accum = data; - break; - case 4: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 5: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 6: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 7: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 8: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 9: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 10: // W_ST (Word Clock Start Register) - m_w_st = bitfield(data, 0, 7); - break; - case 11: // W_END (Word Clock End Register) - m_w_end = bitfield(data, 0, 7); - break; - case 12: // LR_END (Left/Right Clock End Register) - m_lr_end = bitfield(data, 0, 7); - m_lrclk.set_width(m_lr_end); - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_alu.m_cr.lei = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_filter.m_lp = bitfield(data, 8, 2); - v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); - v.m_cr.cmpd = bitfield(data, 13); - v.m_cr.bs = bitfield(data, 14, 2); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 0, 17); - break; - case 2: // LVOL (Left Volume) - v.m_lvol = bitfield(data, 0, 16); - break; - case 3: // LVRAMP (Left Volume Ramp) - v.m_lvramp = bitfield(data, 8, 8); - break; - case 4: // RVOL (Right Volume) - v.m_rvol = bitfield(data, 0, 16); - break; - case 5: // RVRAMP (Right Volume Ramp) - v.m_rvramp = bitfield(data, 8, 8); - break; - case 6: // ECOUNT (Envelope Counter) - v.m_ecount = bitfield(data, 0, 9); - break; - case 7: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = bitfield(data, 0, 16); - break; - case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) - v.m_k2ramp.slow = bitfield(data, 0); - v.m_k2ramp.ramp = bitfield(data, 8, 8); - break; - case 9: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = bitfield(data, 0, 16); - break; - case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) - v.m_k1ramp.slow = bitfield(data, 0); - v.m_k1ramp.ramp = bitfield(data, 8, 8); - break; - case 11: // ACT (Number of voices) - m_active = std::max(4, bitfield(data, 0, 5)); - break; - case 12: // MODE (Global Mode) - m_mode.lrclk_en = bitfield(data, 0); - m_mode.wclk_en = bitfield(data, 1); - m_mode.bclk_en = bitfield(data, 2); - m_mode.master = bitfield(data, 3); - m_mode.dual = bitfield(data, 4); - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp deleted file mode 100644 index b16be3672..000000000 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5506_HPP -#define _VGSOUND_EMU_ES5506_HPP - -#pragma once - -// ES5506 specific -class es5506_core : public es550x_shared_core -{ -public: - // constructor - es5506_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this} - { - } - // host interface - u8 host_r(u8 address); - void host_w(u8 address, u8 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // clock outputs - bool bclk() { return m_bclk.current_edge(); } - bool bclk_rising_edge() { return m_bclk.rising_edge(); } - bool bclk_falling_edge() { return m_bclk.falling_edge(); } - - // 6 stereo output channels - s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_left; } - s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_right; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u8 read(u8 address, bool cpu_access = false); - void write(u8 address, u8 data, bool cpu_access = false); - - u32 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u32 data, bool cpu_access = false); - - u8 regs8_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u8 ret = read(address, false); m_page = prev; return ret; } - void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].m_mute = mute; } - - // per-voice outputs - s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } - s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } - -protected: - virtual inline u8 max_voices() override { return 32; } - virtual void voice_tick() override; - -private: - struct output_t - { - void reset() - { - m_left = 0; - m_right = 0; - }; - - s32 m_left = 0; - s32 m_right = 0; - }; - - // es5506 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5506_core &host) - : es550x_voice_t(21, 11, true) - , m_host(host) {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - // accessors, getters, setters - s16 decompress(u8 sample); - s32 volume_calc(u16 volume, s32 in); - - struct filter_ramp_t - { - filter_ramp_t() - : slow(0) - , ramp(0) - { }; - - void reset() - { - slow = 0; - ramp = 0; - }; - - u16 slow : 1; // Slow mode flag - u16 ramp = 8; // Ramp value - }; - - // registers - es5506_core &m_host; - s32 m_lvol = 0; // Left volume - 4 bit exponent, 8 bit mantissa, 4 LSBs are used for fine control of ramp increment for hardware envelope - s32 m_lvramp = 0; // Left volume ramp - s32 m_rvol = 0; // Right volume - s32 m_rvramp = 0; // Righr volume ramp - s16 m_ecount = 0; // Envelope counter - filter_ramp_t m_k2ramp; // Filter coefficient 2 Ramp - filter_ramp_t m_k1ramp; // Filter coefficient 1 Ramp - u8 m_filtcount = 0; // Internal counter for slow mode - output_t m_ch; // channel output - bool m_mute = false; // mute flag (for debug purpose) - }; - - // 5 bit mode - struct mode_t - { - mode_t() - : bclk_en(0) - , wclk_en(0) - , lrclk_en(0) - , master(0) - , dual(0) - { }; - - void reset() - { - bclk_en = 1; - wclk_en = 1; - lrclk_en = 1; - master = 0; - dual = 0; - } - - u8 bclk_en : 1; // Set BCLK to output - u8 wclk_en : 1; // Set WCLK to output - u8 lrclk_en : 1; // Set LRCLK to output - u8 master : 1; // Set memory mode to master - u8 dual : 1; // Set dual chip config - }; - - voice_t m_voice[32]; // 32 voices - - // Host interfaces - u32 m_read_latch = 0; // 32 bit register latch for host read - u32 m_write_latch = 0; // 32 bit register latch for host write - - // Serial register - u8 m_w_st = 0; // Word clock start register - u8 m_w_end = 0; // Word clock end register - u8 m_lr_end = 0; // Left/Right clock end register - mode_t m_mode; // Global mode - - // Serial related stuffs - u8 m_w_st_curr = 0; // Word clock start, current status - u8 m_w_end_curr = 0; // Word clock end register - clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock - clock_pulse_t m_lrclk; // LRCLK - s16 m_wclk = 0; // WCLK - bool m_wclk_lr = false; // WCLK, L/R output select - s8 m_output_bit = 0; // Bit position in output - output_t m_ch[6]; // 6 stereo output channels - output_t m_output[6]; // Serial outputs - output_t m_output_temp[6]; // temporary signal for serial output - output_t m_output_latch[6]; // output latch -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp deleted file mode 100644 index 10d1d9a90..000000000 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 emulation core - - After ES5503 DOC's appeared, Ensoniq announces ES5504 DOC II, ES5505 OTIS, ES5506 OTTO. - - These are not just PCM chip; but with built-in 4 pole filters and variable voice limits. - - It can be trades higher sample rate and finer frequency and Tons of voices, or vice-versa. - - These are mainly used with their synthesizers, musical stuffs. It's also mainly paired with ES5510 ESP/ES5511 ESP2 for post processing. - ES5506 can be paired with itself, It's called Dual chip configuration and Both chips are can be shares same memory spaces. - - ES5505 was also mainly used on Taito's early- to late-90s arcade hardware for their PCM sample based sound system, - paired with ES5510 ESP for post processing. It's configuration is borrowed from Ensoniq's 32 Voice synths powered by these chips. - It's difference is external logic to adds per-voice bankswitching looks like what Konami doing on K007232. - - Atari Panther was will be use ES5505, but finally canceled. - - Ensoniq's ISA Sound Card for PC, Soundscape used ES5506, "Elite" model has optional daughterboard with ES5510 for digital effects. - - Related chips: - ES5530 "OPUS" variant is 2-in-one chip with built-in ES5506 and Sequoia. - ES5540 "OTTOFX" variant is ES5506 and ES5510 merged in single package. - ES5548 "OTTO48" variant is used at late-90s ensoniq synths and musical instruments, 2 ES5506s are merged in single package, or with 48 voices in chip? - - Chip difference: - ES5504 to ES5505: - Total voice amount is expanded to 32, rather than 25. - ADC and DAC is completely redesigned. it's has now voice-independent 10 bit and Sony/Burr-Brown format DAC. - Output channel and Volume is changed to 16 mono to 4 stereo, 12 bit Analog to 8 bit Stereo digital, also Floating point-ish format and independent per left and right output. - Channel 3 is can be Input/Output. - Channel output is can be accessible at host for test purpose. - Max sample memory is expanded to 2MWords (1MWords * 2 Banks) - - ES5505 to ES5506: - Frequency is more finer now: 11 bit fraction rather than 9 bit. - Output channel and Volume is changed to 4 stereo to 6 stereo, 8 bit to 16 bit, but only 12 bit is used for calculation; 4 LSB is used for envelope ramping. - Transwave flag is added - its helpful for transwave process, with interrupt per voices. - Hardware envelope is added - K1, K2, Volume value is can be modified in run-time. also K1, K2 is expanded to 16 bit for finer envelope ramping. - Filter calculation resolution is expanded to 18 bit. - All channels are output, Serial output is now partially programmable. - Max sample memory is expanded to 8MWords (2MWords * 4 Banks) - - Register format between these chips are incompatible. - -*/ - -#include "es550x.hpp" - -// Shared functions -void es550x_shared_core::reset() -{ - m_host_intf.reset(); - m_ha = 0; - m_hd = 0; - m_page = 0; - m_irqv.reset(); - m_active = max_voices() - 1; - m_voice_cycle = 0; - m_voice_fetch = 0; - m_voice_update = false; - m_voice_end = false; - m_clkin.reset(); - m_cas.reset(); - m_e.reset(); -} - -void es550x_shared_core::es550x_voice_t::reset() -{ - m_cr.reset(); - m_alu.reset(); - m_filter.reset(); -} diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp deleted file mode 100644 index e5106b78a..000000000 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 emulation core - - See es550x.cpp for more info -*/ - -#ifndef _VGSOUND_EMU_ES550X_HPP -#define _VGSOUND_EMU_ES550X_HPP - -#pragma once - -#include -#include -#include "util.hpp" - -// ES5504/ES5505/ES5506 interface -class es550x_intf -{ -public: - virtual void e_pin(bool state) {} // E output - virtual void bclk(bool state) {} // BCLK output (serial specific) - virtual void lrclk(bool state) {} // LRCLK output (serial specific) - virtual void wclk(bool state) {} // WCLK output (serial specific) - - virtual void irqb(bool state) {} // IRQB output - virtual u16 adc_r() { return 0; } // ADC input - virtual void adc_w(u16 data) {} // ADC output - virtual s16 read_sample(u8 voice, u8 bank, u32 address) { return 0; } -}; - -// Shared functions for ES5504/ES5505/ES5506 -class es550x_shared_core -{ - friend class es550x_intf; // es550x specific memory interface -public: - // constructor - es550x_shared_core(es550x_intf &intf) - : m_intf(intf) - { }; - - // internal state - virtual void reset(); - virtual void tick() {} - - // clock outputs - bool _cas() { return m_cas.current_edge(); } - bool _cas_rising_edge() { return m_cas.rising_edge(); } - bool _cas_falling_edge() { return m_cas.falling_edge(); } - - bool e() { return m_e.current_edge(); } - bool e_rising_edge() { return m_e.rising_edge(); } - bool e_falling_edge() { return m_e.falling_edge(); } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // voice cycle - u8 voice_cycle() { return m_voice_cycle; } - - // voice update flag - bool voice_update() { return m_voice_update; } - bool voice_end() { return m_voice_end; } - -protected: - // Constants - virtual inline u8 max_voices() { return 32; } - - // Shared registers, functions - virtual void voice_tick() {} // voice tick - - // Interrupt bits - struct es550x_irq_t - { - es550x_irq_t() - : voice(0) - , irqb(1) - { }; - - void reset() - { - voice = 0; - irqb = 1; - } - - void set(u8 index) - { - irqb = 0; - voice = index; - } - - void clear() - { - irqb = 1; - voice = 0; - } - - u8 voice : 5; - u8 irqb : 1; - }; - - // Common control bits - struct es550x_control_t - { - es550x_control_t() - : ca(0) - , adc(0) - , bs(0) - , cmpd(0) - { }; - - void reset() - { - ca = 0; - adc = 0; - bs = 0; - cmpd = 0; - } - - u8 ca : 4; // Channel assign (4 bit (16 channel or Bank) for ES5504, 2 bit (4 stereo channels) for ES5505, 3 bit (6 stereo channels) for ES5506) - // ES5504 Specific - u8 adc : 1; // Start ADC - // ES5505/ES5506 Specific - u8 bs : 2; // Bank bit (1 bit for ES5505, 2 bit for ES5506) - u8 cmpd : 1; // Use compressed sample format - }; - - // Accumulator - struct es550x_alu_t - { - es550x_alu_t(u8 integer, u8 fraction, bool transwave) - : m_integer(integer) - , m_fraction(fraction) - , m_total_bits(integer + fraction) - , m_accum_mask(u32(std::min(~0, u64(u64(1) << u64(integer + fraction)) - 1))) - , m_transwave(transwave) - {} - - const u8 m_integer; - const u8 m_fraction; - const u8 m_total_bits; - const u32 m_accum_mask; - const bool m_transwave; - - void reset(); - bool busy(); - bool tick(); - void loop_exec(); - s32 interpolation(); - u32 get_accum_integer(); - void irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index); - void irq_update(es550x_intf &intf, es550x_irq_t &irqv) { intf.irqb(irqv.irqb ? false : true); } - - struct es550x_alu_cr_t - { - es550x_alu_cr_t() - : stop0(0) - , stop1(0) - , lpe(0) - , ble(0) - , irqe(0) - , dir(0) - , irq(0) - , lei(0) - { }; - - void reset() - { - stop0 = 0; - stop1 = 0; - lpe = 0; - ble = 0; - irqe = 0; - dir = 0; - irq = 0; - lei = 0; - } - - u8 stop0 : 1; // Stop with ALU - u8 stop1 : 1; // Stop with processor - u8 lpe : 1; // Loop enable - u8 ble : 1; // Bidirectional loop enable - u8 irqe : 1; // IRQ enable - u8 dir : 1; // Playback direction - u8 irq : 1; // IRQ bit - u8 lei : 1; // Loop end ignore (ES5506 specific) - }; - - es550x_alu_cr_t m_cr; - u32 m_fc = 0; // Frequency - 6 integer, 9 fraction for ES5506/ES5505, 6 integer, 11 fraction for ES5506 - u32 m_start = 0; // Start register - u32 m_end = 0; // End register - u32 m_accum = 0; // Accumulator - 20 integer, 9 fraction for ES5506/ES5505, 21 integer, 11 fraction for ES5506 - s32 m_sample[2] = {0}; // Samples - }; - - // Filter - struct es550x_filter_t - { - void reset(); - void tick(s32 in); - s32 lp_exec(s32 coeff, s32 in, s32 prev_out); - s32 hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in); - - // Registers - u8 m_lp = 0; // Filter mode - // Filter coefficient registers - s32 m_k2 = 0; // Filter coefficient 2 - 12 bit for filter calculation, 4 LSBs are used for fine control of ramp increment for hardware envelope (ES5506) - s32 m_k1 = 0; // Filter coefficient 1 - // Filter storage registers - s32 m_o1_1 = 0; // First stage - s32 m_o2_1 = 0; // Second stage - s32 m_o2_2 = 0; // Second stage HP - s32 m_o3_1 = 0; // Third stage - s32 m_o3_2 = 0; // Third stage HP - s32 m_o4_1 = 0; // Final stage - }; - - // Common voice struct - struct es550x_voice_t - { - es550x_voice_t(u8 integer, u8 fraction, bool transwave) - : m_alu(integer, fraction, transwave) - {} - - // internal state - virtual void reset(); - virtual void fetch(u8 voice, u8 cycle) = 0; - virtual void tick(u8 voice) = 0; - - es550x_control_t m_cr; - es550x_alu_t m_alu; - es550x_filter_t m_filter; - }; - - - // Host interfaces - struct host_interface_flag_t - { - host_interface_flag_t() - : m_host_access(0) - , m_host_access_strobe(0) - , m_rw(0) - , m_rw_strobe(0) - {} - - void reset() - { - m_host_access = 0; - m_host_access_strobe = 0; - m_rw = 0; - m_rw_strobe = 0; - } - - u8 m_host_access : 1; // Host access trigger - u8 m_host_access_strobe : 1; // Host access strobe - u8 m_rw : 1; // R/W state - u8 m_rw_strobe : 1; // R/W strobe - }; - host_interface_flag_t m_host_intf; // Host interface flag - u8 m_ha = 0; // Host address (4 bit) - u16 m_hd = 0; // Host data (16 bit for ES5504/ES5505, 8 bit for ES5506) - u8 m_page = 0; // Page - es550x_irq_t m_irqv; // Voice interrupt vector registers - // Internal states - u8 m_active = max_voices() - 1; // Activated voices (-1, ~25 for ES5504, ~32 for ES5505/ES5506) - u8 m_voice_cycle = 0; // Voice cycle - u8 m_voice_fetch = 0; // Voice fetch cycle - bool m_voice_update = false; // Voice update flag - bool m_voice_end = false; // End of one voice cycle flag - es550x_intf &m_intf; // es550x specific memory interface - clock_pulse_t m_clkin; // CLKIN clock - clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock - clock_pulse_t m_e; // E clock (CLKIN / 8), falling edge of CLKIN trigger this clock -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp deleted file mode 100644 index 6b11d9ec9..000000000 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core - - see es550x.cpp for more info -*/ - -#include "es550x.hpp" - -// Accumulator functions -void es550x_shared_core::es550x_alu_t::reset() -{ - m_cr.reset(); - m_fc = 0; - m_start = 0; - m_end = 0; - m_accum = 0; - m_sample[0] = m_sample[1] = 0; -} - -bool es550x_shared_core::es550x_alu_t::busy() -{ - return ((!m_cr.stop0) && (!m_cr.stop1)); -} - -bool es550x_shared_core::es550x_alu_t::tick() -{ - if (m_cr.dir) - m_accum -= m_fc; - else - m_accum += m_fc; - - m_accum &= m_accum_mask; - return ((!m_cr.lei) - && ((( m_cr.dir) && (m_accum < m_start)) - || ((!m_cr.dir) && (m_accum > m_end)))) ? true : false; -} - -void es550x_shared_core::es550x_alu_t::loop_exec() -{ - if (m_cr.irqe) // Set IRQ - m_cr.irq = 1; - - if (m_cr.dir) // Reverse playback - { - if (m_cr.lpe) // Loop enable - { - if (m_cr.ble) // Bidirectional - { - m_cr.dir = 0; - m_accum = m_start + (m_start - m_accum); - } - else// Normal - m_accum = m_end - (m_start - m_accum); - } - else if (m_cr.ble && m_transwave) // m_transwave - { - m_cr.lpe = m_cr.ble = 0; - m_cr.lei = 1; // Loop end ignore - m_accum = m_end - (m_start - m_accum); - } - else // Stop - m_cr.stop0 = 1; - } - else - { - if (m_cr.lpe) // Loop enable - { - if (m_cr.ble) // Bidirectional - { - m_cr.dir = 1; - m_accum = m_end - (m_end - m_accum); - } - else // Normal - m_accum = (m_accum - m_end) + m_start; - } - else if (m_cr.ble && m_transwave) // m_transwave - { - m_cr.lpe = m_cr.ble = 0; - m_cr.lei = 1; // Loop end ignore - m_accum = (m_accum - m_end) + m_start; - } - else // Stop - m_cr.stop0 = 1; - } -} - -s32 es550x_shared_core::es550x_alu_t::interpolation() -{ - // SF = S1 + ACCfr * (S2 - S1) - return m_sample[0] + ((bitfield(m_accum, std::max(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); -} - -u32 es550x_shared_core::es550x_alu_t::get_accum_integer() -{ - return bitfield(m_accum, m_fraction, m_integer); -} - -void es550x_shared_core::es550x_alu_t::irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index) -{ - const u8 prev = irqv.irqb; - if (m_cr.irq) - { - if (irqv.irqb) - { - irqv.set(index); - m_cr.irq = 0; - } - } - if (prev != irqv.irqb) - irq_update(intf, irqv); -} diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp deleted file mode 100644 index bf0b260c1..000000000 --- a/src/engine/platform/sound/es550x/es550x_filter.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core - - see es550x.cpp for more info -*/ - -#include "es550x.hpp" - -// Filter functions -void es550x_shared_core::es550x_filter_t::reset() -{ - m_lp = 0; - m_k2 = 0; - m_k1 = 0; - m_o1_1 = 0; - m_o2_1 = 0; - m_o2_2 = 0; - m_o3_1 = 0; - m_o3_2 = 0; - m_o4_1 = 0; -} - -void es550x_shared_core::es550x_filter_t::tick(s32 in) -{ - s32 coeff_k1 = s32(bitfield(m_k1, 4, 12)); // 12 MSB used - s32 coeff_k2 = s32(bitfield(m_k2, 4, 12)); // 12 MSB used - // Store previous filter data - m_o2_2 = m_o2_1; - m_o3_2 = m_o3_1; - - // First and second stage: LP/K1, LP/K1 Fixed - m_o1_1 = lp_exec(coeff_k1, in, m_o1_1); - m_o2_1 = lp_exec(coeff_k1, m_o1_1, m_o2_1); - switch (m_lp) - { - case 0: // LP3 = 0, LP4 = 0: HP/K2, HP/K2 - default: - m_o3_1 = hp_exec(coeff_k2, m_o2_1, m_o3_1, m_o2_2); - m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); - break; - case 1: // LP3 = 0, LP4 = 1: HP/K2, LP/K1 - m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); - break; - case 2: // LP3 = 1, LP4 = 0: LP/K2, LP/K2 - m_o3_1 = lp_exec(coeff_k2, m_o2_1, m_o3_1); - m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); - break; - case 3: // LP3 = 1, LP4 = 1: LP/K2, LP/K1 - m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); - break; - } -} - -s32 es550x_shared_core::es550x_filter_t::lp_exec(s32 coeff, s32 in, s32 prev_out) -{ - // Yn = K*(Xn - Yn-1) + Yn-1 - return ((coeff * (in - prev_out)) / 4096) + prev_out; -} - -s32 es550x_shared_core::es550x_filter_t::hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in) -{ - // Yn = Xn - Xn-1 + K*Yn-1 - return in - prev_in + ((coeff * prev_out) / 8192) + (prev_out / 2); -} diff --git a/src/engine/platform/sound/es550x/util.hpp b/src/engine/platform/sound/es550x/util.hpp deleted file mode 100644 index ad85fdf99..000000000 --- a/src/engine/platform/sound/es550x/util.hpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Various core utilities for vgsound_emu -*/ - -#ifndef _VGSOUND_EMU_CORE_UTIL_HPP -#define _VGSOUND_EMU_CORE_UTIL_HPP - -#pragma once - -#include -#include -#include - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; - -// get bitfield, bitfield(input, position, len) -template T bitfield(T in, u8 pos, u8 len = 1) -{ - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); -} - -// get sign extended value, sign_ext(input, len) -template T sign_ext(T in, u8 len) -{ - len = std::max(0, (8 * sizeof(T)) - len); - return T(T(in) << len) >> len; -} - -// std::clamp is only for C++17 or later; I use my own code -template T clamp(T in, T min, T max) -{ - return std::min(std::max(in, min), max); -} - -template -struct clock_pulse_t -{ - void reset(T init = InitWidth) - { - m_edge.reset(); - m_width = m_width_latch = m_counter = init; - m_cycle = 0; - } - - bool tick(T width = 0) - { - bool carry = ((--m_counter) <= 0); - if (carry) - { - if (!width) - m_width = m_width_latch; - else - m_width = width; // reset width - m_counter = m_width; - m_cycle = 0; - } - else - m_cycle++; - - m_edge.tick(carry); - return carry; - } - - void set_width(T width) { m_width = width; } - void set_width_latch(T width) { m_width_latch = width; } - - // Accessors - bool current_edge() { return m_edge.m_current; } - bool rising_edge() { return m_edge.m_rising; } - bool falling_edge() { return m_edge.m_rising; } - T cycle() { return m_cycle; } - - struct edge_t - { - edge_t() - : m_current(InitEdge ^ 1) - , m_previous(InitEdge) - , m_rising(0) - , m_falling(0) - , m_changed(0) - { - set(InitEdge); - } - - void tick(bool toggle) - { - u8 current = m_current; - if (toggle) - current ^= 1; - set(current); - } - - void set(u8 edge) - { - edge &= 1; - m_rising = m_falling = m_changed = 0; - if (m_current != edge) - { - m_changed = 1; - if (m_current && (!edge)) - m_falling = 1; - else if ((!m_current) && edge) - m_rising = 1; - m_current = edge; - } - m_previous = m_current; - } - - void reset() - { - m_previous = InitEdge; - m_current = InitEdge ^ 1; - set(InitEdge); - } - - u8 m_current : 1; // current edge - u8 m_previous : 1; // previous edge - u8 m_rising : 1; // rising edge - u8 m_falling : 1; // falling edge - u8 m_changed : 1; // changed flag - }; - - edge_t m_edge; - T m_width = InitWidth; // clock pulse width - T m_width_latch = InitWidth; // clock pulse width latch - T m_counter = InitWidth; // clock counter - T m_cycle = 0; // clock cycle -}; - -#endif diff --git a/src/engine/sample.h b/src/engine/sample.h index e3b7743d8..3a054304c 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -178,12 +178,6 @@ struct DivSample { bool resampleBlep(double rate); bool resampleSinc(double rate); - /** - * check if sample is loopable. - * @return whether it was loopable. - */ - bool isLoopable(); - /** * save this sample to a file. * @param path a path. diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 61dacf893..99b09be68 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -180,6 +180,7 @@ void FurnaceGUI::drawDebug() { ImGui::Text("loopMode: %d ()",(unsigned char)sample->loopMode); } + ImGui::Text("depth: %d",(unsigned char)sample->depth); ImGui::Text("length8: %d",sample->length8); ImGui::Text("length16: %d",sample->length16); ImGui::Text("length1: %d",sample->length1); diff --git a/src/gui/gui.h b/src/gui/gui.h index 2c2418b65..a873f8431 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -907,7 +907,7 @@ struct FurnaceGUIMacroDesc { float height; const char* displayName; const char** bitfieldBits; - const char** modeName; + const char* modeName; ImVec4 color; unsigned int bitOffset; bool isBitfield, blockMode, bit30; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index eb309a509..7ffd1ba3d 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -161,9 +161,8 @@ const char* resampleStrats[DIV_RESAMPLE_MAX]={ "best possible" }; -const char* loopMode[DIV_SAMPLE_LOOPMODE_MAX]={ - "Disable", - "Foward", +const char* loopMode[DIV_SAMPLE_LOOP_MAX]={ + "Forward", "Backward", "Pingpong" }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ce9d111ae..7a1ea9220 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -247,10 +247,6 @@ const char* n163UpdateBits[8]={ "now", "every waveform changed", NULL }; -const char* es5506FilterModes[4]={ - "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", -}; - const char* suControlBits[5]={ "ring mod", "low pass", "high pass", "band pass", NULL }; @@ -263,18 +259,6 @@ const char* panBits[3]={ "right", "left", NULL }; -const char* es5506EnvelopeModes[3]={ - "k1 slowdown", "k2 slowdown", NULL -}; - -const char* es5506ControlModes[2]={ - "pause", NULL -}; - -const char* transwaveControlModes[2]={ - "slice", NULL -}; - const char* oneBit[2]={ "on", NULL }; @@ -287,6 +271,10 @@ const char* es5506ControlModes[2]={ "pause", NULL }; +const char* transwaveControlModes[2]={ + "slice", NULL +}; + const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -388,21 +376,17 @@ String macroHoverES5506FilterMode(int id, float val, void* u) { String macroLFOWaves(int id, float val, void* u) { switch (((int)val)&3) { case 0: - mode="Saw"; - break; + return "Saw"; case 1: - mode="Square"; - break; + return "Square"; case 2: - mode="Sine"; - break; + return "Sine"; case 3: - mode="Random"; - break; + return "Random"; default: - break; + return "???"; } - return fmt::sprintf("%d: %s",id,mode); + return "???"; } void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) { @@ -3242,10 +3226,10 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTabItem("FM Macros")) { if (ins->type==DIV_INS_OPLL) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3311,10 +3295,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else if (ins->type==DIV_INS_OPLL) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3324,10 +3308,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3344,7 +3328,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); if (ins->type==DIV_INS_FM) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,ssgEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } drawMacros(macroList); @@ -3826,22 +3810,22 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i].ind<0 || ins->amiga.noteMap[i].ind>=e->song.sampleLen) { + if (ins->amiga.noteMap[i].map<0 || ins->amiga.noteMap[i].map>=e->song.sampleLen) { sName="-- empty --"; - ins->amiga.noteMap[i].ind=-1; + ins->amiga.noteMap[i].map=-1; } else { - sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; + sName=e->song.sample[ins->amiga.noteMap[i].map]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER - ins->amiga.noteMap[i].ind=-1; + if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].map==-1)) { PARAMETER + ins->amiga.noteMap[i].map=-1; } for (int j=0; jsong.sampleLen; j++) { id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].ind==j)) { PARAMETER - ins->amiga.noteMap[i].ind=j; + if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].map==j)) { PARAMETER + ins->amiga.noteMap[i].map=j; if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); } } @@ -4045,7 +4029,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->amiga.transWave.enable) { if (ImGui::BeginTabItem("Transwave Macros")) { - macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,transwaveControlModes)); + macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,transwaveControlModes)); macroList.push_back(FurnaceGUIMacroDesc("Transwave slice",&ins->std.fmsMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); drawMacros(macroList); ImGui::EndTabItem(); @@ -4833,14 +4817,14 @@ void FurnaceGUI::drawInsEdit() { } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { - macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } } - macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM || ins->type==DIV_INS_STD || @@ -4873,7 +4857,7 @@ void FurnaceGUI::drawInsEdit() { } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,filtModeBits)); + macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits)); } else if (ins->type==DIV_INS_SAA1099) { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits)); } else if (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) { @@ -4900,7 +4884,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_N163) { - macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } else if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { @@ -4912,12 +4896,12 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SNES) { macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } else { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,ex2Bit,ayEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } } if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,c64SpecialBits)); - macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits)); + macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample)) { macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -4925,14 +4909,14 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Wave",&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Pos",&ins->std.algMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Len",&ins->std.fbMacro,0,252,160,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Position",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 843e356fd..a3e65e7c2 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -116,16 +116,11 @@ void FurnaceGUI::drawSampleEdit() { sample->loopStart=-1; sample->loopEnd=sample->samples; } - if (sample->loopEnd>sample->samples) { - sample->loopEnd=sample->samples; - } - sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Length: %d",sample->samples); - bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -678,16 +673,11 @@ void FurnaceGUI::drawSampleEdit() { sample->loopStart=-1; sample->loopEnd=sample->samples; } - if (sample->loopEnd>sample->samples) { - sample->loopEnd=sample->samples; - } - sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Length: %d",sample->samples); - bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn(); From 23e29fe57e461850cad71fb05268ac5dcdc08063 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 18:44:38 +0900 Subject: [PATCH 28/74] Sync with master --- extern/Nuked-OPL3 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 extern/Nuked-OPL3 diff --git a/extern/Nuked-OPL3 b/extern/Nuked-OPL3 deleted file mode 160000 index bb5c8d08a..000000000 --- a/extern/Nuked-OPL3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bb5c8d08a85779c42b75c79d7b84f365a1b93b66 From b474b065bd3b8ef0c6b441b841f2a16e249937ff Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 18:57:42 +0900 Subject: [PATCH 29/74] Fix SDL --- extern/SDL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/SDL b/extern/SDL index 8ce003a42..031c9b03f 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 8ce003a42c2ef82b713a21ccf65750d955ff63ef +Subproject commit 031c9b03f1e5054e8d78e1974b92a6ef77b71774 From bd08fc0193a3ef28f77b542e39f0987a7df7591e Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 19:00:01 +0900 Subject: [PATCH 30/74] Removed from master --- extern/imgui | 1 - 1 file changed, 1 deletion(-) delete mode 160000 extern/imgui diff --git a/extern/imgui b/extern/imgui deleted file mode 160000 index 1ee252772..000000000 --- a/extern/imgui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1ee252772ae9c0a971d06257bb5c89f628fa696a From 81bebc5112ff01b79d0f20d8bc86c9bad33abfa6 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 19:21:49 +0900 Subject: [PATCH 31/74] Reduce unnecessary changes, Volume macro fixes, calcArp --- src/engine/platform/es5506.cpp | 39 ++++++++++++---------------------- src/engine/playback.cpp | 4 ---- src/engine/sample.cpp | 12 +++++------ src/gui/insEdit.cpp | 39 +++++++++++++++++----------------- 4 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 16cec93e3..071537ec9 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -272,7 +272,7 @@ void DivPlatformES5506::e_pin(bool state) unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); chan[ch].isReverseLoop=false; switch (chan[ch].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // no loop default: break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop @@ -326,11 +326,11 @@ void DivPlatformES5506::irqb(bool state) { void DivPlatformES5506::tick(bool sysTick) { for (int i=0; i<=chanMax; i++) { chan[i].std.next(); - DivInstrument* ins=parent->getIns(chan[i].ins); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_ES5506); signed int k1=chan[i].k1Prev,k2=chan[i].k2Prev; // volume/panning macros if (chan[i].std.vol.had) { - const unsigned int nextVol=VOL_SCALE_LOG((0xffff*chan[i].vol)/0xff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax,0xffff); + const unsigned int nextVol=VOL_SCALE_LOG((0xffff*chan[i].vol)/0xff,(0xffff*(unsigned int)chan[i].std.vol.val)/chan[i].volMacroMax,0xffff); if (chan[i].outVol!=nextVol) { chan[i].outVol=nextVol; if (!isMuted[i]) { @@ -339,7 +339,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panL.had) { - const unsigned int nextLVol=VOL_SCALE_LOG((0xffff*chan[i].lVol)/0xff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax,0xffff); + const unsigned int nextLVol=VOL_SCALE_LOG((0xffff*chan[i].lVol)/0xff,(0xffff*(unsigned int)chan[i].std.panL.val)/chan[i].panMacroMax,0xffff); if (chan[i].outLVol!=nextLVol) { chan[i].outLVol=nextLVol; if (!isMuted[i]) { @@ -348,7 +348,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panR.had) { - const unsigned int nextRVol=VOL_SCALE_LOG((0xffff*chan[i].rVol)/0xff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax,0xffff); + const unsigned int nextRVol=VOL_SCALE_LOG((0xffff*chan[i].rVol)/0xff,(0xffff*(unsigned int)chan[i].std.panR.val)/chan[i].panMacroMax,0xffff); if (chan[i].outRVol!=nextRVol) { chan[i].outRVol=nextRVol; if (!isMuted[i]) { @@ -359,18 +359,9 @@ void DivPlatformES5506::tick(bool sysTick) { // arpeggio/pitch macros, frequency related if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].nextNote=chan[i].std.arp.val; - } else { - chan[i].nextNote=chan[i].note+chan[i].std.arp.val; - } + chan[i].nextNote=parent->calcArp(chan[i].note,chan[i].std.arp.val); } chan[i].noteChanged.note=1; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].nextNote=chan[i].note; - chan[i].noteChanged.note=1; - } } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { @@ -408,8 +399,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].filterChanged.k1=1; } break; - /* - case 2: { // delta + /*case 2: { // delta const signed int next_k1=CLAMP(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); if (chan[i].k1Offs!=next_k1) { chan[i].k1Offs=next_k1; @@ -436,8 +426,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].filterChanged.k2=1; } break; - /* - case 2: { // delta + /*case 2: { // delta const signed int next_k2=CLAMP(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); if (chan[i].k2Offs!=next_k2) { chan[i].k2Offs=next_k2; @@ -757,7 +746,7 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // no loop default: break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop @@ -891,7 +880,7 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // no loop default: break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop @@ -938,7 +927,7 @@ void DivPlatformES5506::tick(bool sysTick) { int DivPlatformES5506::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); bool sampleVaild=false; if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.ind<(int)ins->amiga.transWaveMap.size())) || @@ -1079,7 +1068,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { return chan[c.chan].outVol; break; case DIV_CMD_PANNING: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); // Left volume if (chan[c.chan].lVol!=(unsigned int)(c.value)) { chan[c.chan].lVol=c.value; @@ -1110,7 +1099,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_WAVE: if (!chan[c.chan].useWave) { if (chan[c.chan].active) { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (c.value>=0 && c.value<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.valuesong.sampleLen))) { @@ -1221,7 +1210,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { } 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)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_ES5506)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index e11d07c01..8c03dd749 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1372,10 +1372,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) { DivSample* s=song.sample[sPreview.sample]; - const bool pBeginVaild=sPreview.pBegin>=0 && sPreview.pBegin<(int)s->samples; - const bool pEndVaild=sPreview.pEnd>=0 && sPreview.pEnd<(int)s->samples; - const int loopStart=pBeginVaild?sPreview.pBegin:s->loopStart; - const int loopEnd=pEndVaild?sPreview.pEnd:(int)s->loopEnd; for (size_t i=0; i=(int)s->samples || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { samp_temp=0; diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 72075df94..6839a370c 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -546,7 +546,7 @@ bool DivSample::resampleLinear(double r) { if (depth==DIV_SAMPLE_DEPTH_16BIT) { for (int i=0; i=samples)?0:oldData16[posInt]; - short s2=(posInt+1>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+1]; + short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; data16[i]=s1+(float)(s2-s1)*posFrac; @@ -559,7 +559,7 @@ bool DivSample::resampleLinear(double r) { } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { for (int i=0; i=samples)?0:oldData8[posInt]; - short s2=(posInt+1>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+1]; + short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; data8[i]=s1+(float)(s2-s1)*posFrac; @@ -589,8 +589,8 @@ bool DivSample::resampleCubic(double r) { float* t=&cubicTable[n<<2]; float s0=(posInt<1)?0:oldData16[posInt-1]; float s1=(posInt>=samples)?0:oldData16[posInt]; - float s2=(posInt+1>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+1]; - float s3=(posInt+2>=samples)?(isLoopable()?oldData16[loopStart]:0):oldData16[posInt+2]; + float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1]; + float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+2]; float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3]; if (result<-32768) result=-32768; @@ -609,8 +609,8 @@ bool DivSample::resampleCubic(double r) { float* t=&cubicTable[n<<2]; float s0=(posInt<1)?0:oldData8[posInt-1]; float s1=(posInt>=samples)?0:oldData8[posInt]; - float s2=(posInt+1>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+1]; - float s3=(posInt+2>=samples)?(isLoopable()?oldData8[loopStart]:0):oldData8[posInt+2]; + float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1]; + float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+2]; float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3]; if (result<-128) result=-128; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 383ec9740..6229c9555 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3792,6 +3792,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::BeginDisabled(ins->amiga.useWave||ins->amiga.transWave.enable); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { + // TODO: frequency map? if (ImGui::BeginTable("NoteMap",3/*4*/,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); @@ -3809,49 +3810,49 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::Text("Reversed"); for (int i=0; i<120; i++) { + DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); ImGui::TableNextColumn(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i].map<0 || ins->amiga.noteMap[i].map>=e->song.sampleLen) { + if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { sName="-- empty --"; - ins->amiga.noteMap[i].map=-1; + sampleMap.map=-1; } else { - sName=e->song.sample[ins->amiga.noteMap[i].map]->name; + sName=e->song.sample[sampleMap.map]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].map==-1)) { PARAMETER - ins->amiga.noteMap[i].map=-1; + if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER + sampleMap.map=-1; } for (int j=0; jsong.sampleLen; j++) { id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].map==j)) { PARAMETER - ins->amiga.noteMap[i].map=j; - if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER + sampleMap.map=j; + if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); } } ImGui::EndCombo(); } - /* - ImGui::TableNextColumn(); + /*ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&ins->amiga.noteMap[i].freq,50,500)) { PARAMETER - if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; - if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; + if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&sampleMap.freq,50,500)) { PARAMETER + if (sampleMap.freq<0) sampleMap.freq=0; + if (sampleMap.freq>262144) sampleMap.freq=262144; } */ ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==0)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=0; + if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),sampleMap.reversed==0)) { MARK_MODIFIED + sampleMap.reversed=0; } - if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),ins->amiga.noteMap[i].reversed==1)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=1; + if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),sampleMap.reversed==1)) { MARK_MODIFIED + sampleMap.reversed=1; } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),ins->amiga.noteMap[i].reversed==2)) { MARK_MODIFIED - ins->amiga.noteMap[i].reversed=2; + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),sampleMap.reversed==2)) { MARK_MODIFIED + sampleMap.reversed=2; } ImGui::PopID(); } From b0b729201a83975894c4bd881620a810c9db8ed5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 19:23:23 +0900 Subject: [PATCH 32/74] Remove duplicate --- src/gui/guiConst.cpp | 6 ------ src/gui/guiConst.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 7ea82d422..f761a2afa 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -161,12 +161,6 @@ const char* resampleStrats[DIV_RESAMPLE_MAX]={ "best possible" }; -const char* loopMode[DIV_SAMPLE_LOOP_MAX]={ - "Forward", - "Backward", - "Pingpong" -}; - const FurnaceGUIColors fxColors[256]={ GUI_COLOR_PATTERN_EFFECT_MISC, // 00 GUI_COLOR_PATTERN_EFFECT_PITCH, // 01 diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index a7ff2bf79..cb5eb5408 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -44,7 +44,6 @@ extern const char* sampleLoopModes[]; extern const char* sampleDepths[]; extern const char* resampleStrats[]; extern const char* chipCategoryNames[]; -extern const char* loopMode[]; extern const int availableSystems[]; extern const int chipsFM[]; extern const int chipsSquare[]; From a11440ac0fc23e1cea4f776ff6f05d4225984d8b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 20:22:22 +0900 Subject: [PATCH 33/74] Fix cmdName --- src/engine/playback.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8c03dd749..604617852 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -204,6 +204,7 @@ const char* cmdName[]={ "SU_SWEEP_BOUND", "SU_SWEEP_ENABLE", "SU_SYNC_PERIOD_LOW", + "SU_SYNC_PERIOD_HIGH", "ADPCMA_GLOBAL_VOLUME", From a0745e80b5b2be256b934c4c1026dbc5069fa218 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 20:25:05 +0900 Subject: [PATCH 34/74] Accidentally removed this --- src/engine/playback.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 604617852..d1b89b978 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -210,6 +210,7 @@ const char* cmdName[]={ "SNES_ECHO", "SNES_PITCH_MOD", + "SNES_INVERT", "SNES_GAIN_MODE", "SNES_GAIN", "SNES_ECHO_ENABLE", From 682aa0ad235b1aa8d77d4561f62365dd0813155e Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 22:23:56 +0900 Subject: [PATCH 35/74] Unused variable --- src/engine/platform/es5506.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 071537ec9..397255efc 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1068,7 +1068,6 @@ int DivPlatformES5506::dispatch(DivCommand c) { return chan[c.chan].outVol; break; case DIV_CMD_PANNING: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); // Left volume if (chan[c.chan].lVol!=(unsigned int)(c.value)) { chan[c.chan].lVol=c.value; From d87aebf47aa8a8c1d3b3b37d92a35514d1931f3c Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 26 Sep 2022 07:49:22 +0900 Subject: [PATCH 36/74] Revert "Fix SDL" This reverts commit b474b065bd3b8ef0c6b441b841f2a16e249937ff. --- extern/SDL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/SDL b/extern/SDL index 031c9b03f..8ce003a42 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 031c9b03f1e5054e8d78e1974b92a6ef77b71774 +Subproject commit 8ce003a42c2ef82b713a21ccf65750d955ff63ef From 45462be5dd4d05bb22ef0983ceadfe19be57819d Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 26 Sep 2022 07:54:52 +0900 Subject: [PATCH 37/74] Don't mess around with SDL --- extern/SDL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/SDL b/extern/SDL index 8ce003a42..f8e14ad25 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 8ce003a42c2ef82b713a21ccf65750d955ff63ef +Subproject commit f8e14ad25aa6f0b4bbed411583a9863c855ad9e6 From 4f71214887bdeeb93d40d71d53af8ddd25173a46 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 27 Sep 2022 04:54:04 +0900 Subject: [PATCH 38/74] code style --- src/engine/platform/es5506.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index fb85668ff..dab6f7c5d 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -140,11 +140,9 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l } } -void DivPlatformES5506::e_pin(bool state) -{ - // get channel outputs +void DivPlatformES5506::e_pin(bool state) { if (es5506.e_falling_edge()) { - if (es5506.voice_update()) { + if (es5506.voice_update()) { // get channel outputs chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); chan[prevChanCycle].oscOut=CLAMP((chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5,-32768,32767); From 5248f30fb41a29ee3d14ccc482065a7b50ae5a78 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 29 Sep 2022 22:40:28 +0900 Subject: [PATCH 39/74] Add ES5506 configs at format.md Fix code format --- papers/format.md | 4 ++++ src/engine/platform/es5506.cpp | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/papers/format.md b/papers/format.md index a58193be0..2123d5dde 100644 --- a/papers/format.md +++ b/papers/format.md @@ -1520,6 +1520,10 @@ chips which aren't on this list don't have any flags. - 1: 16.67MHz - bit 4: stereo (bool) +## 0xb1: Ensoniq ES5506 + +- bit 0-4: channels (int) + ## 0xb5: tildearrow Sound Unit - bit 0: clockSel (int) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index dab6f7c5d..adaebca9a 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -141,8 +141,8 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l } void DivPlatformES5506::e_pin(bool state) { - if (es5506.e_falling_edge()) { - if (es5506.voice_update()) { // get channel outputs + if (es5506.e_falling_edge()) { // get channel outputs + if (es5506.voice_update()) { chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); chan[prevChanCycle].oscOut=CLAMP((chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5,-32768,32767); @@ -155,8 +155,7 @@ void DivPlatformES5506::e_pin(bool state) { } } } - // host interface - if (es5506.e_rising_edge()) { + if (es5506.e_rising_edge()) { // host interface if (cycle) { // wait until delay cycle--; } else if (!hostIntf8.empty()) { From 8b934aa4a145e94afd94c2dde14017663fbfe670 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 29 Sep 2022 23:05:03 +0900 Subject: [PATCH 40/74] Fix ES5506 sysDef --- src/engine/sysDef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index e8f4c333c..385e20650 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1448,15 +1448,15 @@ void DivEngine::registerSystems() { {0x23, {DIV_CMD_ES5506_ENVELOPE_RVRAMP, "23xx: Set envelope right volume ramp (signed) (00 to FF)",effectVal}}, {0x24, {DIV_CMD_ES5506_ENVELOPE_K1RAMP, "24xx: Set envelope filter coefficient k1 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, {0x25, {DIV_CMD_ES5506_ENVELOPE_K1RAMP, "25xx: Set envelope filter coefficient k1 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}}, - {0x26, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "24xx: Set envelope filter coefficient k2 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, - {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "25xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}} + {0x26, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "26xx: Set envelope filter coefficient k2 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, + {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "27xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}} }; EffectHandlerMap es5506PostEffectHandlerMap={ {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}}, {0x18, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "18xx: Set filter coefficient K1 slide up (00 to FF)",effectVal,constVal<0>}}, {0x19, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "19xx: Set filter coefficient K1 slide down (00 to FF)",effectVal,constVal<1>}}, - {0x1a, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1axx: Set filter coefficient K2 slide up (00 to FF)",effectVal,constVal<0>}}, - {0x1b, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1bxx: Set filter coefficient K2 slide down (00 to FF)",effectVal,constVal<1>}}, + {0x1a, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Axx: Set filter coefficient K2 slide up (00 to FF)",effectVal,constVal<0>}}, + {0x1b, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Bxx: Set filter coefficient K2 slide down (00 to FF)",effectVal,constVal<1>}}, }; const EffectHandler es5506ECountHandler(DIV_CMD_ES5506_ENVELOPE_COUNT, "2xxx: Set envelope count (000 to 1FF)", effectValLong<9>); const EffectHandler es5506K1Handler(DIV_CMD_ES5506_FILTER_K1, "3xxx: Set filter coefficient K1 (000 to FFF)", effectValLongShift<12,4>); From fdd53c1587e3e9b8336891e02db2ac9483199e75 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 30 Sep 2022 19:54:13 +0900 Subject: [PATCH 41/74] Fix crash, enum-ise reverse mode --- src/engine/instrument.h | 20 ++++++++++++------- src/engine/platform/es5506.cpp | 12 ++++++------ src/gui/insEdit.cpp | 35 +++++++++++++++++----------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index bc0898399..0355a8155 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -339,11 +339,17 @@ struct DivInstrumentC64 { }; struct DivInstrumentAmiga { + enum DivReverseMode: unsigned char { + DIV_REVERSE_DISABLE=0, + DIV_REVERSE_ENABLE, + DIV_REVERSE_DEFAULT + }; + struct SampleMap { int freq; short map; - unsigned char reversed; - SampleMap(int f=0, short m=-1, unsigned char r=0): + DivInstrumentAmiga::DivReverseMode reversed; + SampleMap(int f=0, short m=-1, DivInstrumentAmiga::DivReverseMode r=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT): freq(f), map(m), reversed(r) {} @@ -395,21 +401,21 @@ struct DivInstrumentAmiga { struct TransWaveMap: TransWaveSlice { short ind; - unsigned char reversed; + DivReverseMode reversed; int loopStart, loopEnd; DivSampleLoopMode loopMode; TransWaveMap(): TransWaveSlice(), ind(-1), - reversed(0), + reversed(DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT), loopStart(-1), loopEnd(-1), loopMode(DIV_SAMPLE_LOOP_MAX) {} }; short initSample; - bool reversed; + DivInstrumentAmiga::DivReverseMode reversed; bool useNoteMap; bool useSample; bool useWave; @@ -448,7 +454,7 @@ struct DivInstrumentAmiga { * get the sample reversed flag at specified note. * @return the reversed flag. */ - inline bool getReversed(int note) { + inline DivInstrumentAmiga::DivReverseMode getReversed(int note) { if (useNoteMap) { if (note<0) note=0; if (note>119) note=119; @@ -459,7 +465,7 @@ struct DivInstrumentAmiga { DivInstrumentAmiga(): initSample(0), - reversed(false), + reversed(DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE), useNoteMap(false), useSample(false), useWave(false), diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index adaebca9a..f1b2e486a 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -249,7 +249,7 @@ void DivPlatformES5506::e_pin(bool state) { } // get reversed bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=2) { + if (transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=transWaveInd.reversed; } const unsigned int start=offES5506<<10; @@ -601,7 +601,7 @@ void DivPlatformES5506::tick(bool sysTick) { } // get reversed bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=2) { + if (transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=transWaveInd.reversed; } chan[i].pcmChanged.slice=1; @@ -672,9 +672,9 @@ void DivPlatformES5506::tick(bool sysTick) { } // get reversed bool reversed=ins->amiga.reversed; - if (ins->amiga.transWave.enable&&transWaveInd.reversed!=2) { + if (ins->amiga.transWave.enable&&transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=transWaveInd.reversed; - } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=2) { + } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=noteMapind.reversed; } const unsigned int start=offES5506<<10; @@ -984,9 +984,9 @@ int DivPlatformES5506::dispatch(DivCommand c) { } // get reversed bool reversed=ins->amiga.reversed; - if (ins->amiga.transWave.enable&&transWaveInd.reversed!=2) { + if (ins->amiga.transWave.enable&&transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=transWaveInd.reversed; - } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=2) { + } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { reversed=noteMapind.reversed; } const unsigned int start=offES5506<<10; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index f6b8b9a84..d5cd0385e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3765,7 +3765,10 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndCombo(); } ImGui::BeginDisabled(ins->amiga.useWave); - P(ImGui::Checkbox("Reversed playback",&ins->amiga.reversed)); + bool reversed=ins->amiga.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE; + if (ImGui::Checkbox("Reversed playback",&reversed)) { PARAMETER + ins->amiga.reversed=reversed?DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE:DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE; + } ImGui::EndDisabled(); // Wavetable if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SNES) { @@ -3850,14 +3853,14 @@ void FurnaceGUI::drawInsEdit() { } */ ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),sampleMap.reversed==0)) { MARK_MODIFIED - sampleMap.reversed=0; + if (ImGui::RadioButton(fmt::sprintf("Disable##SampleMap_Reversed_Disable_%d",i).c_str(),sampleMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE)) { MARK_MODIFIED + sampleMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE; } - if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),sampleMap.reversed==1)) { MARK_MODIFIED - sampleMap.reversed=1; + if (ImGui::RadioButton(fmt::sprintf("Enable##SampleMap_Reversed_Enable_%d",i).c_str(),sampleMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE)) { MARK_MODIFIED + sampleMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE; } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),sampleMap.reversed==2)) { MARK_MODIFIED - sampleMap.reversed=2; + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##SampleMap_Reversed_Default_%d",i).c_str(),sampleMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT)) { MARK_MODIFIED + sampleMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT; } ImGui::PopID(); } @@ -3962,10 +3965,10 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER transWaveMap.ind=j; if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { - transWaveMap.loopStart=s->loopStart; + transWaveMap.loopStart=CLAMP(s->loopStart,0,s->samples); } if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { - transWaveMap.loopEnd=s->loopEnd; + transWaveMap.loopEnd=CLAMP(s->loopEnd,0,s->samples); } transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { @@ -4019,14 +4022,14 @@ void FurnaceGUI::drawInsEdit() { transWaveMap.loopMode=DIV_SAMPLE_LOOP_MAX; } ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==0)) { MARK_MODIFIED - transWaveMap.reversed=0; + if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE)) { MARK_MODIFIED + transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE; } - if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==1)) { MARK_MODIFIED - transWaveMap.reversed=1; + if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE)) { MARK_MODIFIED + transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE; } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==2)) { MARK_MODIFIED - transWaveMap.reversed=2; + if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT)) { MARK_MODIFIED + transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT; } ImGui::EndDisabled(); ImGui::PopID(); @@ -4044,8 +4047,6 @@ void FurnaceGUI::drawInsEdit() { drawMacros(macroList); ImGui::EndTabItem(); } - ImGui::EndDisabled(); - ImGui::EndTabItem(); } } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) { From c83d919fbcb6adffb0ab517067d03a7ffa6de058 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 30 Sep 2022 20:01:31 +0900 Subject: [PATCH 42/74] Sync to master --- src/engine/platform/es5506.cpp | 24 ++++++++++++------------ src/engine/platform/es5506.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index f1b2e486a..f0dad9dde 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -270,9 +270,6 @@ void DivPlatformES5506::e_pin(bool state) { unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); chan[ch].isReverseLoop=false; switch (chan[ch].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // no loop - default: - break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; @@ -283,6 +280,9 @@ void DivPlatformES5506::e_pin(bool state) { case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; + case DIV_SAMPLE_LOOP_MAX: // no loop + default: + break; } // Set loop mode & Bank pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); @@ -745,9 +745,6 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // no loop - default: - break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; @@ -758,6 +755,9 @@ void DivPlatformES5506::tick(bool sysTick) { case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; + case DIV_SAMPLE_LOOP_MAX: // no loop + default: + break; } // Set loop mode & Bank pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0xfcfd); @@ -879,9 +879,6 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_MAX: // no loop - default: - break; case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; @@ -892,6 +889,9 @@ void DivPlatformES5506::tick(bool sysTick) { case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; + case DIV_SAMPLE_LOOP_MAX: // no loop + default: + break; } if (chan[i].pcm.pause) { loopFlag|=0x0002; @@ -1324,8 +1324,8 @@ void DivPlatformES5506::notifyInsDeletion(void* ins) { } } -void DivPlatformES5506::setFlags(unsigned int flags) { - initChanMax=MAX(4,flags&0x1f); +void DivPlatformES5506::setFlags(const DivConfig& flags) { + initChanMax=MAX(4,flags.getInt("channels",0)&0x1f); chanMax=initChanMax; pageWriteMask(0x00,0x60,0x0b,chanMax); } @@ -1401,7 +1401,7 @@ void DivPlatformES5506::renderSamples() { sampleMemLen=memPos+256; } -int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { +int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { sampleMem=new signed short[getSampleMemCapacity()/sizeof(short)]; sampleMemLen=0; parent=p; diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index f60bbf42d..58f694050 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -290,7 +290,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual void muteChannel(int ch, bool mute) override; virtual bool isStereo() override; virtual bool keyOffAffectsArp(int ch) override; - virtual void setFlags(unsigned int flags) override; + virtual void setFlags(const DivConfig& flags) override; virtual void notifyInsChange(int ins) override; virtual void notifyWaveChange(int wave) override; virtual void notifyInsDeletion(void* ins) override; @@ -301,7 +301,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual size_t getSampleMemUsage(int index = 0) override; virtual void renderSamples() override; virtual const char** getRegisterSheet() override; - virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override; + virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override; virtual void quit() override; DivPlatformES5506(): DivDispatch(), From 930369b7971d0c81149d81dc12dcc5e1f33d83ad Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 1 Oct 2022 17:22:18 +0900 Subject: [PATCH 43/74] Make macOS happy --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 12b48277e..15421be16 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3965,10 +3965,10 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER transWaveMap.ind=j; if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { - transWaveMap.loopStart=CLAMP(s->loopStart,0,s->samples); + transWaveMap.loopStart=CLAMP(s->loopStart,0,(int)s->samples); } if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { - transWaveMap.loopEnd=CLAMP(s->loopEnd,0,s->samples); + transWaveMap.loopEnd=CLAMP(s->loopEnd,0,(int)s->samples); } transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { From 87cb3c49a43d1b25a5a31d8b8a48adef3886101b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 22 Oct 2022 17:19:39 +0900 Subject: [PATCH 44/74] Update ES5506: Remove transwave for now - It consumes high CPU usage, so possibly little headroom for anything else. Fix per-voice OSC via git master Fix default channel for ES5506 Fix macro order - Filter macro must be executed after key on Add SSV preset --- src/engine/dispatch.h | 2 - src/engine/instrument.h | 65 +--- src/engine/platform/es5506.cpp | 549 +++++++++------------------------ src/engine/platform/es5506.h | 11 +- src/engine/playback.cpp | 2 - src/engine/sysDef.cpp | 25 +- src/gui/debug.cpp | 4 +- src/gui/insEdit.cpp | 191 +----------- src/gui/presets.cpp | 6 + src/gui/sysConf.cpp | 2 +- 10 files changed, 168 insertions(+), 689 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 39f3ff656..926f8fc7a 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -73,8 +73,6 @@ enum DivDispatchCmds { DIV_CMD_SAMPLE_BANK, // (bank) DIV_CMD_SAMPLE_POS, // (pos) DIV_CMD_SAMPLE_DIR, // (direction) - DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, // (enabled) - DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, // (slice) DIV_CMD_FM_HARD_RESET, // (enabled) DIV_CMD_FM_LFO, // (speed) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 818717cc7..1a2e53e7d 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -361,65 +361,6 @@ struct DivInstrumentAmiga { reversed(r) {} }; - struct TransWaveSlice { - // states - double sliceSize; - double sliceBound; - double sliceStart; - double sliceEnd; - - // inlines - inline void updateSize(double length, double loopStart, double loopEnd) { - sliceSize=loopEnd-loopStart; - sliceBound=(length-sliceSize); - } - inline double slicePos(double slice) { - double pos=sliceBound*slice; - if (sliceStart!=pos) { - sliceStart=pos; - } - if (sliceEnd!=(sliceSize+pos)) { - sliceEnd=(sliceSize+pos); - } - return pos; - } - - TransWaveSlice(): - sliceSize(0), - sliceBound(0), - sliceStart(0), - sliceEnd(0) {} - }; - - struct TransWave: TransWaveSlice { - bool enable; - bool sliceEnable; - int ind; - unsigned short slice; - - TransWave(): - TransWaveSlice(), - enable(false), - sliceEnable(false), - ind(0), - slice(0) {} - }; - - struct TransWaveMap: TransWaveSlice { - short ind; - DivReverseMode reversed; - int loopStart, loopEnd; - DivSampleLoopMode loopMode; - - TransWaveMap(): - TransWaveSlice(), - ind(-1), - reversed(DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT), - loopStart(-1), - loopEnd(-1), - loopMode(DIV_SAMPLE_LOOP_MAX) {} - }; - short initSample; DivInstrumentAmiga::DivReverseMode reversed; bool useNoteMap; @@ -427,8 +368,6 @@ struct DivInstrumentAmiga { bool useWave; unsigned char waveLen; SampleMap noteMap[120]; - TransWave transWave; - std::vector transWaveMap; /** * get the sample at specified note. @@ -475,9 +414,7 @@ struct DivInstrumentAmiga { useNoteMap(false), useSample(false), useWave(false), - waveLen(31), - transWave(TransWave()), - transWaveMap(1) { + waveLen(31) { for (SampleMap& elem: noteMap) { elem=SampleMap(); } diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index f0dad9dde..cf3670b35 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -206,97 +206,6 @@ void DivPlatformES5506::e_pin(bool state) { } irqTrigger=false; } - } else { - unsigned char ch=w.state&0x1f; - if (chan[ch].transwaveIRQ) { - if ((chan[ch].cr&0x37)==0x34) { // IRQE = 1, BLE = 1, LPE = 0, LEI = 1 - DivInstrument* ins=parent->getIns(chan[ch].ins); - if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { - const int next=chan[ch].pcm.next; - if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; - int sample=transWaveInd.ind; - if (sample>=0 && samplesong.sampleLen) { - const unsigned int offES5506=sampleOffES5506[sample]; - chan[ch].pcm.index=sample; - chan[ch].transWave.ind=next; - DivSample* s=parent->getSample(sample); - // get frequency offset - double off=1.0; - double center=(double)s->centerRate; - if (center<1) { - off=1.0; - } else { - off=(double)center/8363.0; - } - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { - loopMode=transWaveInd.loopMode; - } else if ((chan[ch].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOP_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[ch].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[ch].transWave.slicePos(double(chan[ch].transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - // get reversed - bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=transWaveInd.reversed; - } - const unsigned int start=offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - const double nextFreqOffs=PITCH_OFFSET*off; - chan[ch].pcm.loopMode=loopMode; - chan[ch].pcm.reversed=reversed; - chan[ch].pcm.bank=(offES5506>>22)&3; - chan[ch].pcm.start=start; - chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; - chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; - chan[ch].pcm.end=end; - chan[ch].pcm.length=length; - pageWrite(0x20|ch,0x01,chan[ch].pcm.loopStart); - pageWrite(0x20|ch,0x02,chan[ch].pcm.loopEnd); - pageWrite(0x20|ch,0x03,(chan[ch].pcm.reversed)?chan[ch].pcm.loopEnd:chan[ch].pcm.loopStart); - unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); - chan[ch].isReverseLoop=false; - switch (chan[ch].pcm.loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: // Foward loop - loopFlag|=0x0008; - break; - case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable - loopFlag|=0x0038; - chan[ch].isReverseLoop=true; - break; - case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support - loopFlag|=0x0018; - break; - case DIV_SAMPLE_LOOP_MAX: // no loop - default: - break; - } - // Set loop mode & Bank - pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); - if (chan[ch].pcm.nextFreqOffs!=nextFreqOffs) { - chan[ch].pcm.nextFreqOffs=nextFreqOffs; - chan[ch].noteChanged.offs=1; - } - } - } - chan[ch].pcmChanged.changed=0; - } - } - chan[ch].transwaveIRQ=false; - } } queuedReadState.pop(); } @@ -306,11 +215,6 @@ void DivPlatformES5506::e_pin(bool state) { pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); chan[ch].isReverseLoop=false; } - if (chan[ch].isTranswave) { - pageReadMask(0x00|ch,0x5f,0x00,ch,&chan[ch].cr); - chan[ch].transwaveIRQ=true; - chan[ch].isTranswave=false; - } queuedRead.pop(); } isReaded=false; @@ -504,29 +408,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } } - // transwave macros - if (chan[i].transWave.enable) { - if (chan[i].std.wave.had) { - if (chan[i].std.wave.val>=0 && chan[i].std.wave.val<(int)ins->amiga.transWaveMap.size()) { - if (chan[i].pcm.next!=chan[i].std.wave.val) { - chan[i].pcm.next=chan[i].std.wave.val; - chan[i].pcmChanged.transwaveInd=1; - } - } - } - if (chan[i].std.fb.had) { - if (chan[i].transWave.sliceEnable!=(bool)(chan[i].std.fb.val&1)) { - chan[i].transWave.sliceEnable=chan[i].std.fb.val&1; - chan[i].pcmChanged.slice=1; - } - } - if (chan[i].std.fms.had) { - if (chan[i].transWave.slice!=(unsigned short)(chan[i].std.fms.val&0xfff)) { - chan[i].transWave.slice=chan[i].std.fms.val&0xfff; - chan[i].pcmChanged.slice=1; - } - } - } else if (chan[i].pcm.isNoteMap) { + if (chan[i].pcm.isNoteMap) { // note map macros if (chan[i].std.wave.had) { if (chan[i].std.wave.val>=0 && chan[i].std.wave.val<120) { @@ -536,7 +418,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } } - } else if (!chan[i].transWave.enable && !chan[i].pcm.isNoteMap) { + } else if (!chan[i].pcm.isNoteMap) { if (chan[i].std.wave.had) { if (chan[i].std.wave.val>=0 && chan[i].std.wave.valsong.sampleLen) { if (chan[i].pcm.next!=chan[i].std.wave.val) { @@ -551,13 +433,13 @@ void DivPlatformES5506::tick(bool sysTick) { if (!isMuted[i]) { // calculate volume (16 bit) if (chan[i].volChanged.lVol) { chan[i].resLVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outLVol,0xffff); - if (!chan[i].keyOn) { + if (!chan[i].keyOn && chan[i].active) { pageWrite(0x00|i,0x02,chan[i].resLVol); } } if (chan[i].volChanged.rVol) { chan[i].resRVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outRVol,0xffff); - if (!chan[i].keyOn) { + if (!chan[i].keyOn && chan[i].active) { pageWrite(0x00|i,0x04,chan[i].resRVol); } } @@ -568,205 +450,125 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].volChanged.changed=0; } if (chan[i].pcmChanged.changed) { - if (!chan[i].isTranswave) { - if (chan[i].pcmChanged.transwaveInd && (!ins->amiga.useNoteMap && ins->amiga.transWave.enable)) { - const int next=chan[i].pcm.next; - if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; - int sample=transWaveInd.ind; - if (sample>=0 && samplesong.sampleLen) { - if (chan[i].pcm.index!=sample) { - pageWriteMask(0x00|i,0x5f,0x00,0x0034,0x00ff); // Set IRQ - chan[i].isTranswave=true; - } else { - chan[i].transWave.ind=next; - DivSample* s=parent->getSample(sample); - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { - loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOP_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[i].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[i].transWave.slicePos(double(chan[i].transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - // get reversed - bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=transWaveInd.reversed; - } - chan[i].pcmChanged.slice=1; - if ((chan[i].pcm.loopMode!=loopMode) || (chan[i].pcm.reversed!=reversed)) { - chan[i].pcm.loopMode=loopMode; - chan[i].pcm.reversed=reversed; - chan[i].pcmChanged.loopBank=1; - } - } + if (chan[i].pcmChanged.index) { + const int next=chan[i].pcm.next; + bool sampleVaild=false; + if (((ins->amiga.useNoteMap) && (next>=0 && next<120)) || + ((!ins->amiga.useNoteMap) && (next>=0 && nextsong.sampleLen))) { + DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next]; + int sample=next; + if (ins->amiga.useNoteMap) { + sample=noteMapind.map; + } + if (sample>=0 && samplesong.sampleLen) { + const unsigned int offES5506=sampleOffES5506[sample]; + sampleVaild=true; + chan[i].pcm.index=sample; + chan[i].pcm.isNoteMap=ins->amiga.useNoteMap; + DivSample* s=parent->getSample(sample); + // get frequency offset + double off=1.0; + double center=(double)s->centerRate; + if (center<1) { + off=1.0; + } else { + off=(double)center/8363.0; + } + if (ins->amiga.useNoteMap) { + off*=(double)noteMapind.freq/((double)MAX(1,center)*pow(2.0,((double)next-48.0)/12.0)); + chan[i].pcm.note=next; + } + // get loop mode + double loopStart=(double)s->loopStart; + double loopEnd=(double)s->loopEnd; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; + // get reversed + bool reversed=ins->amiga.reversed; + if (ins->amiga.useNoteMap&¬eMapind.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { + reversed=noteMapind.reversed; + } + const unsigned int start=offES5506<<10; + const unsigned int length=s->samples-1; + const unsigned int end=start+(length<<11); + const unsigned int nextBank=(offES5506>>22)&3; + const double nextFreqOffs=PITCH_OFFSET*off; + chan[i].pcm.loopMode=loopMode; + chan[i].pcm.reversed=reversed; + chan[i].pcm.bank=nextBank; + chan[i].pcm.start=start; + chan[i].pcm.end=end; + chan[i].pcm.length=length; + if ((chan[i].pcm.loopMode!=loopMode) || (chan[i].pcm.reversed!=reversed) || (chan[i].pcm.bank!=nextBank)) { + chan[i].pcm.loopMode=loopMode; + chan[i].pcm.reversed=reversed; + chan[i].pcm.bank=nextBank; + chan[i].pcmChanged.loopBank=1; + } + if (chan[i].pcm.nextFreqOffs!=nextFreqOffs) { + chan[i].pcm.nextFreqOffs=nextFreqOffs; + chan[i].noteChanged.offs=1; } } - chan[i].pcmChanged.transwaveInd=0; } - if ((!chan[i].pcmChanged.transwaveInd) && (!chan[i].isTranswave)) { - if (chan[i].pcmChanged.index) { - const int next=chan[i].pcm.next; - bool sampleVaild=false; - if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && next<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (next>=0 && next<(int)ins->amiga.transWaveMap.size())) || - ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && nextsong.sampleLen))) { - DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next]; - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; - int sample=next; - if (ins->amiga.transWave.enable) { - sample=transWaveInd.ind; - } else if (ins->amiga.useNoteMap) { - sample=noteMapind.map; - } - if (sample>=0 && samplesong.sampleLen) { - const unsigned int offES5506=sampleOffES5506[sample]; - sampleVaild=true; - chan[i].pcm.index=sample; - chan[i].pcm.isNoteMap=ins->amiga.useNoteMap && !ins->amiga.transWave.enable; - chan[i].transWave.enable=!ins->amiga.useNoteMap && ins->amiga.transWave.enable; - chan[i].transWave.ind=next; - DivSample* s=parent->getSample(sample); - // get frequency offset - double off=1.0; - double center=(double)s->centerRate; - if (center<1) { - off=1.0; - } else { - off=(double)center/8363.0; - } - if (ins->amiga.useNoteMap) { - off*=(double)noteMapind.freq/((double)MAX(1,center)*pow(2.0,((double)next-48.0)/12.0)); - chan[i].pcm.note=next; - } - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; - if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { - loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOP_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[i].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[i].transWave.slicePos(double(chan[i].transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - } - // get reversed - bool reversed=ins->amiga.reversed; - if (ins->amiga.transWave.enable&&transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=transWaveInd.reversed; - } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=noteMapind.reversed; - } - const unsigned int start=offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - const unsigned int nextBank=(offES5506>>22)&3; - const double nextFreqOffs=PITCH_OFFSET*off; - chan[i].pcm.loopMode=loopMode; - chan[i].pcm.reversed=reversed; - chan[i].pcm.bank=nextBank; - chan[i].pcm.start=start; - chan[i].pcm.end=end; - chan[i].pcm.length=length; - if ((chan[i].pcm.loopMode!=loopMode) || (chan[i].pcm.reversed!=reversed) || (chan[i].pcm.bank!=nextBank)) { - chan[i].pcm.loopMode=loopMode; - chan[i].pcm.reversed=reversed; - chan[i].pcm.bank=nextBank; - chan[i].pcmChanged.loopBank=1; - } - if (chan[i].pcm.nextFreqOffs!=nextFreqOffs) { - chan[i].pcm.nextFreqOffs=nextFreqOffs; - chan[i].noteChanged.offs=1; - } - } - } - if (sampleVaild) { - if (!chan[i].keyOn) { - pageWrite(0x20|i,0x03,(chan[i].pcm.reversed)?chan[i].pcm.end:chan[i].pcm.start); - } - chan[i].pcmChanged.slice=1; - } - chan[i].pcmChanged.index=0; + if (sampleVaild) { + if (!chan[i].keyOn) { + pageWrite(0x20|i,0x03,(chan[i].pcm.reversed)?chan[i].pcm.end:chan[i].pcm.start); } - if (chan[i].pcmChanged.slice) { - if (!chan[i].keyOn) { - if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { - // get loop mode, transwave loop - DivSample* s=parent->getSample(chan[i].pcm.index); - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[i].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[i].transWave.slicePos(double(chan[i].transWave.slice)/4095.0); - loopStart=chan[i].transWave.sliceStart; - loopEnd=chan[i].transWave.sliceEnd; - } - const unsigned int start=sampleOffES5506[chan[i].pcm.index]<<10; - const unsigned int nextLoopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; - const unsigned int nextLoopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; - if ((chan[i].pcm.loopStart!=nextLoopStart) || (chan[i].pcm.loopEnd!=nextLoopEnd)) { - chan[i].pcm.loopStart=nextLoopStart; - chan[i].pcm.loopEnd=nextLoopEnd; - chan[i].pcmChanged.position=1; - } - } - } - chan[i].pcmChanged.slice=0; - } - if (chan[i].pcmChanged.position) { - if (!chan[i].keyOn) { - pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); - pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); - } - chan[i].pcmChanged.position=0; - } - if (chan[i].pcmChanged.loopBank) { - if (!chan[i].keyOn) { - unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); - chan[i].isReverseLoop=false; - switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: // Foward loop - loopFlag|=0x0008; - break; - case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable - loopFlag|=0x0038; - chan[i].isReverseLoop=true; - break; - case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support - loopFlag|=0x0018; - break; - case DIV_SAMPLE_LOOP_MAX: // no loop - default: - break; - } - // Set loop mode & Bank - pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0xfcfd); - } - chan[i].pcmChanged.loopBank=0; - } - chan[i].pcmChanged.dummy=0; + chan[i].pcmChanged.slice=1; } + chan[i].pcmChanged.index=0; } + if (chan[i].pcmChanged.slice) { + if (!chan[i].keyOn) { + if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { + // get loop mode + DivSample* s=parent->getSample(chan[i].pcm.index); + double loopStart=(double)s->loopStart; + double loopEnd=(double)s->loopEnd; + const unsigned int start=sampleOffES5506[chan[i].pcm.index]<<10; + const unsigned int nextLoopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; + const unsigned int nextLoopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; + if ((chan[i].pcm.loopStart!=nextLoopStart) || (chan[i].pcm.loopEnd!=nextLoopEnd)) { + chan[i].pcm.loopStart=nextLoopStart; + chan[i].pcm.loopEnd=nextLoopEnd; + chan[i].pcmChanged.position=1; + } + } + } + chan[i].pcmChanged.slice=0; + } + if (chan[i].pcmChanged.position) { + if (!chan[i].keyOn) { + pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); + pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); + } + chan[i].pcmChanged.position=0; + } + if (chan[i].pcmChanged.loopBank) { + if (!chan[i].keyOn) { + unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); + chan[i].isReverseLoop=false; + switch (chan[i].pcm.loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop + loopFlag|=0x0008; + break; + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable + loopFlag|=0x0038; + chan[i].isReverseLoop=true; + break; + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support + loopFlag|=0x0018; + break; + case DIV_SAMPLE_LOOP_MAX: // no loop + default: + break; + } + // Set loop mode & Bank + pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0xfcfd); + } + chan[i].pcmChanged.loopBank=0; + } + chan[i].pcmChanged.dummy=0; } if (chan[i].filterChanged.changed) { if (!chan[i].keyOn) { @@ -843,11 +645,18 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].freq=CLAMP(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,chan[i].pcm.freqOffs),0,0x1ffff); if (chan[i].keyOn) { if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { + unsigned int startPos=chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start; + if (chan[i].pcm.nextPos) { + const unsigned int start=chan[i].pcm.start; + const unsigned int end=chan[i].pcm.length; + startPos+=(chan[i].pcm.reversed?(end-chan[i].pcm.nextPos):chan[i].pcm.nextPos)<<11; + chan[i].pcm.nextPos=0; + } chan[i].k1Prev=0xffff; chan[i].k2Prev=0xffff; pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR pageWrite(0x00|i,0x06,0); // Clear ECOUNT - pageWrite(0x20|i,0x03,chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start); // Set ACCUM to start address + pageWrite(0x20|i,0x03,startPos); // Set ACCUM to start address pageWrite(0x00|i,0x07,0xffff); // Set K1 and K2 to 0xffff pageWrite(0x00|i,0x09,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay pageWrite(0x00|i,0x01,chan[i].freq); @@ -910,7 +719,7 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; } - if (!chan[i].keyOn) { + if (!chan[i].keyOn && chan[i].active) { if (chan[i].k2Prev!=k2) { pageWrite(0x00|i,0x07,k2); chan[i].k2Prev=k2; @@ -928,81 +737,18 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); bool sampleVaild=false; - if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.ind<(int)ins->amiga.transWaveMap.size())) || - ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (ins->amiga.initSample>=0 && ins->amiga.initSamplesong.sampleLen))) { + if (((ins->amiga.useNoteMap) && (c.value>=0 && c.value<120)) || + ((!ins->amiga.useNoteMap) && (ins->amiga.initSample>=0 && ins->amiga.initSamplesong.sampleLen))) { DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[c.value]; - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; int sample=ins->amiga.initSample; - if (ins->amiga.transWave.enable) { - sample=transWaveInd.ind; - } else if (ins->amiga.useNoteMap) { + if (ins->amiga.useNoteMap) { sample=noteMapind.map; } if (sample>=0 && samplesong.sampleLen) { - const unsigned int offES5506=sampleOffES5506[sample]; sampleVaild=true; - chan[c.chan].pcm.index=chan[c.chan].pcm.next=sample; - chan[c.chan].pcm.pause=(chan[c.chan].std.alg.will)?(chan[c.chan].std.alg.val&1):false; - chan[c.chan].pcm.isNoteMap=ins->amiga.useNoteMap && !ins->amiga.transWave.enable; - chan[c.chan].transWave.enable=!ins->amiga.useNoteMap && ins->amiga.transWave.enable; - chan[c.chan].transWave.sliceEnable=ins->amiga.transWave.sliceEnable; - chan[c.chan].transWave.ind=ins->amiga.transWave.ind; - DivSample* s=parent->getSample(sample); - // get frequency offset - double off=1.0; - double center=(double)s->centerRate; - if (center<1) { - off=1.0; - } else { - off=(double)center/8363.0; - } - if (ins->amiga.useNoteMap) { - off*=(double)noteMapind.freq/((double)MAX(1,center)*pow(2.0,((double)c.value-48.0)/12.0)); - chan[c.chan].pcm.note=c.value; - } - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; - if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { - loopMode=transWaveInd.loopMode; - } else if ((chan[c.chan].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOP_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[c.chan].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[c.chan].transWave.slice=ins->amiga.transWave.slice; - chan[c.chan].transWave.slicePos(double(ins->amiga.transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - } - // get reversed - bool reversed=ins->amiga.reversed; - if (ins->amiga.transWave.enable&&transWaveInd.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=transWaveInd.reversed; - } else if (ins->amiga.useNoteMap&¬eMapind.reversed!=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT) { - reversed=noteMapind.reversed; - } - const unsigned int start=offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - chan[c.chan].pcm.loopMode=loopMode; - chan[c.chan].pcm.freqOffs=PITCH_OFFSET*off; - chan[c.chan].pcm.reversed=reversed; - chan[c.chan].pcm.bank=(offES5506>>22)&3; - chan[c.chan].pcm.start=start; - chan[c.chan].pcm.end=end; - chan[c.chan].pcm.length=length; - chan[c.chan].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; - chan[c.chan].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; chan[c.chan].volMacroMax=ins->type==DIV_INS_AMIGA?64:0xffff; chan[c.chan].panMacroMax=ins->type==DIV_INS_AMIGA?127:0xffff; + chan[c.chan].pcm.next=sample; chan[c.chan].filter=ins->es5506.filter; chan[c.chan].envelope=ins->es5506.envelope; } @@ -1017,6 +763,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].nextNote=chan[c.chan].note; chan[c.chan].pcm.nextFreqOffs=chan[c.chan].pcm.freqOffs; chan[c.chan].freqChanged=true; + chan[c.chan].pcmChanged.changed=0xff; chan[c.chan].noteChanged.changed=0xff; chan[c.chan].volChanged.changed=0xff; } @@ -1099,32 +846,15 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (!chan[c.chan].useWave) { if (chan[c.chan].active) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506); - if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || - ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (c.value>=0 && c.value<(int)ins->amiga.transWaveMap.size())) || - ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.valuesong.sampleLen))) { + if (((ins->amiga.useNoteMap) && (c.value>=0 && c.value<120)) || + ((!ins->amiga.useNoteMap) && (c.value>=0 && c.valuesong.sampleLen))) { chan[c.chan].pcm.next=c.value; - if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { - chan[c.chan].pcmChanged.transwaveInd=1; - } else { - chan[c.chan].pcmChanged.index=1; - } + chan[c.chan].pcmChanged.index=1; } } } // reserved for useWave break; - case DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE: - if (chan[c.chan].transWave.sliceEnable!=(bool)(c.value&1)) { - chan[c.chan].transWave.sliceEnable=c.value&1; - chan[c.chan].pcmChanged.slice=1; - } - break; - case DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS: - if (chan[c.chan].transWave.sliceEnable && (chan[c.chan].transWave.slice!=(unsigned short)(c.value&0xfff))) { - chan[c.chan].transWave.slice=c.value&0xfff; - chan[c.chan].pcmChanged.slice=1; - } - break; // Filter commands case DIV_CMD_ES5506_FILTER_MODE: chan[c.chan].filter.mode=DivInstrumentES5506::Filter::FilterMode(c.value&3); @@ -1216,13 +946,17 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_POS: { if (chan[c.chan].useWave) break; if (chan[c.chan].active) { - const unsigned int start=chan[c.chan].transWave.enable?chan[c.chan].pcm.loopStart:chan[c.chan].pcm.start; - const unsigned int end=chan[c.chan].transWave.enable?chan[c.chan].pcm.loopEnd:chan[c.chan].pcm.length; + const unsigned int start=chan[c.chan].pcm.start; + const unsigned int end=chan[c.chan].pcm.length; const unsigned int pos=chan[c.chan].pcm.reversed?(end-c.value):c.value; if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && pos}}, - {0x13, {DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, "130x: Set transwave slice mode (bit 0)",effectValAnd<1>}}, + {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}}, {0x14, {DIV_CMD_ES5506_FILTER_K1, "14xx: Set filter coefficient K1 low byte (00 to FF)",effectValShift<0>,constVal<0x00ff>}}, {0x15, {DIV_CMD_ES5506_FILTER_K1, "15xx: Set filter coefficient K1 high byte (00 to FF)",effectValShift<8>,constVal<0xff00>}}, {0x16, {DIV_CMD_ES5506_FILTER_K2, "16xx: Set filter coefficient K2 low byte (00 to FF)",effectValShift<0>,constVal<0x00ff>}}, {0x17, {DIV_CMD_ES5506_FILTER_K2, "17xx: Set filter coefficient K2 high byte (00 to FF)",effectValShift<8>,constVal<0xff00>}}, + {0x18, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "18xx: Set filter coefficient K1 slide up (00 to FF)",effectVal,constVal<0>}}, + {0x19, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "19xx: Set filter coefficient K1 slide down (00 to FF)",effectVal,constVal<1>}}, + {0x1a, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Axx: Set filter coefficient K2 slide up (00 to FF)",effectVal,constVal<0>}}, + {0x1b, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Bxx: Set filter coefficient K2 slide down (00 to FF)",effectVal,constVal<1>}}, {0x22, {DIV_CMD_ES5506_ENVELOPE_LVRAMP, "22xx: Set envelope left volume ramp (signed) (00 to FF)",effectVal}}, {0x23, {DIV_CMD_ES5506_ENVELOPE_RVRAMP, "23xx: Set envelope right volume ramp (signed) (00 to FF)",effectVal}}, {0x24, {DIV_CMD_ES5506_ENVELOPE_K1RAMP, "24xx: Set envelope filter coefficient k1 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, @@ -1480,21 +1486,12 @@ void DivEngine::registerSystems() { {0x26, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "26xx: Set envelope filter coefficient k2 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "27xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}} }; - EffectHandlerMap es5506PostEffectHandlerMap={ - {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}}, - {0x18, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "18xx: Set filter coefficient K1 slide up (00 to FF)",effectVal,constVal<0>}}, - {0x19, {DIV_CMD_ES5506_FILTER_K1_SLIDE, "19xx: Set filter coefficient K1 slide down (00 to FF)",effectVal,constVal<1>}}, - {0x1a, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Axx: Set filter coefficient K2 slide up (00 to FF)",effectVal,constVal<0>}}, - {0x1b, {DIV_CMD_ES5506_FILTER_K2_SLIDE, "1Bxx: Set filter coefficient K2 slide down (00 to FF)",effectVal,constVal<1>}}, - }; const EffectHandler es5506ECountHandler(DIV_CMD_ES5506_ENVELOPE_COUNT, "2xxx: Set envelope count (000 to 1FF)", effectValLong<9>); const EffectHandler es5506K1Handler(DIV_CMD_ES5506_FILTER_K1, "3xxx: Set filter coefficient K1 (000 to FFF)", effectValLongShift<12,4>); const EffectHandler es5506K2Handler(DIV_CMD_ES5506_FILTER_K2, "4xxx: Set filter coefficient K2 (000 to FFF)", effectValLongShift<12,4>); - const EffectHandler transWaveSlicePositionHandler(DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, "5xxx: Set transwave slice point (000 to FFF)", effectValLong<12>); - for (int i=0; i<2; i++) es5506PreEffectHandlerMap.emplace(0x20+i,es5506ECountHandler); - for (int i=0; i<16; i++) es5506PreEffectHandlerMap.emplace(0x30+i, es5506K1Handler); - for (int i=0; i<16; i++) es5506PreEffectHandlerMap.emplace(0x40+i, es5506K2Handler); - for (int i=0; i<16; i++) es5506PreEffectHandlerMap.emplace(0x50+i, transWaveSlicePositionHandler); + for (int i=0; i<2; i++) es5506PostEffectHandlerMap.emplace(0x20+i,es5506ECountHandler); + for (int i=0; i<16; i++) es5506PostEffectHandlerMap.emplace(0x30+i, es5506K1Handler); + for (int i=0; i<16; i++) es5506PostEffectHandlerMap.emplace(0x40+i, es5506K2Handler); // TODO: custom sample format sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 2ebfc8f77..51b8fbea8 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -1078,6 +1078,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - loopStart: %.8x",ch->pcm.loopStart); ImGui::Text(" - loopEnd: %.8x",ch->pcm.loopEnd); ImGui::Text(" - loopMode: %d",ch->pcm.loopMode); + ImGui::Text(" - nextPos: %d",ch->pcm.nextPos); ImGui::Text("* Filter:"); ImGui::Text(" - Mode: %d",ch->filter.mode); ImGui::Text(" - K1: %.4x",ch->filter.k1); @@ -1122,10 +1123,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->pcmChanged.slice?colorOn:colorOff,">> PCMSliceChanged"); ImGui::TextColored(ch->pcmChanged.position?colorOn:colorOff,">> PCMPositionChanged"); ImGui::TextColored(ch->pcmChanged.loopBank?colorOn:colorOff,">> PCMLoopBankChanged"); - ImGui::TextColored(ch->pcmChanged.transwaveInd?colorOn:colorOff,">> PCMTranswaveIndexChanged"); ImGui::TextColored(ch->isReverseLoop?colorOn:colorOff,">> IsReverseLoop"); - ImGui::TextColored(ch->isTranswave?colorOn:colorOff,">> IsTranswave"); - ImGui::TextColored(ch->transwaveIRQ?colorOn:colorOff,">> TranswaveIRQ"); ImGui::TextColored(ch->pcm.reversed?colorOn:colorOff,">> PCMReversed"); ImGui::TextColored(ch->envelope.k1Slow?colorOn:colorOff,">> EnvK1Slow"); ImGui::TextColored(ch->envelope.k2Slow?colorOn:colorOff,">> EnvK2Slow"); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2bac01436..6a8faf78d 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -290,10 +290,6 @@ const char* es5506ControlModes[2]={ "pause", NULL }; -const char* transwaveControlModes[2]={ - "slice", NULL -}; - const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -4055,7 +4051,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); // Wavetable if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SNES) { - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.transWave.enable); + ImGui::BeginDisabled(ins->amiga.useNoteMap); P(ImGui::Checkbox("Use wavetable (Amiga/SNES/Generic DAC only)",&ins->amiga.useWave)); if (ins->amiga.useWave) { int len=ins->amiga.waveLen+1; @@ -4080,7 +4076,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); } // Note map - ImGui::BeginDisabled(ins->amiga.useWave||ins->amiga.transWave.enable); + ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { // TODO: frequency map? @@ -4151,186 +4147,8 @@ void FurnaceGUI::drawInsEdit() { } } ImGui::EndDisabled(); - // Transwave - ImGui::BeginDisabled(ins->amiga.useNoteMap||ins->amiga.useWave||ins->amiga.useNoteMap); - P(ImGui::Checkbox("Use Transwave##UseTransWave",&ins->amiga.transWave.enable)); - if (ins->amiga.transWave.enable) { - int size=ins->amiga.transWaveMap.size(); - if (ImGui::InputInt("Transwave Map Size##TransWaveSize",&size,1,16)) { PARAMETER - if (size<=ins->amiga.transWave.ind) size=ins->amiga.transWave.ind+1; - if (size<1) size=1; - if (size>256) size=256; - if (ins->amiga.transWaveMap.size()!=(size_t)(size)) { - ins->amiga.transWaveMap.resize(size,DivInstrumentAmiga::TransWaveMap()); - if (ins->amiga.transWaveMap.capacity()>(size_t)(size)) { - ins->amiga.transWaveMap.shrink_to_fit(); - } - } - } - if (ImGui::InputInt("Initial Transwave Index##TransWaveInit",&ins->amiga.transWave.ind,1,16)) { PARAMETER - if (ins->amiga.transWave.ind<1) ins->amiga.transWave.ind=0; - if (ins->amiga.transWave.ind>=(int)(ins->amiga.transWaveMap.size())) ins->amiga.transWave.ind=ins->amiga.transWaveMap.size()-1; - if (ins->amiga.transWave.sliceEnable) { - DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; - if (ind.ind>=0 && ind.ind<(short)(e->song.sampleLen)) { - DivSample* s=e->song.sample[ind.ind]; - ins->amiga.transWave.updateSize(s->samples,ind.loopStart,ind.loopEnd); - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } - } - } - if (ImGui::Checkbox("Use Transwave Slice##UseTransWaveSlice",&ins->amiga.transWave.sliceEnable)) { PARAMETER - if (ins->amiga.transWave.sliceEnable) { - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - if (ins->amiga.transWave.sliceEnable) { - DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; - if (ind.ind>=0 && ind.ind<(short)(e->song.sampleLen)) { - DivSample* s=e->song.sample[ind.ind]; - ins->amiga.transWave.updateSize(s->samples,ind.loopStart,ind.loopEnd); - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } - } - } - } - DivInstrumentAmiga::TransWaveMap ind=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; - if (ins->amiga.transWave.sliceEnable && (ind.ind>=0 && ind.indsong.sampleLen)) { - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - double sliceStart=ins->amiga.transWave.sliceStart; - double sliceEnd=ins->amiga.transWave.sliceEnd; - if (CWSliderScalar("Initial Transwave Slice##TransWaveSliceInit",ImGuiDataType_U16,&ins->amiga.transWave.slice,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE,fmt::sprintf("%d: %.6f - %.6f",ins->amiga.transWave.slice,sliceStart,sliceEnd).c_str())) { PARAMETER - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } rightClickable - } - if (ImGui::BeginTable("TransWaveMap",6,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); // Number - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); // Sample index - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); // Loop start - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); // Loop end - ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); // Loop mode - ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch); // Reversed - - ImGui::TableSetupScrollFreeze(0,1); - - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::Text("Sample"); - ImGui::TableNextColumn(); - ImGui::Text("Loop Start"); - ImGui::TableNextColumn(); - ImGui::Text("Loop End"); - ImGui::TableNextColumn(); - ImGui::Text("Loop Mode"); - ImGui::TableNextColumn(); - ImGui::Text("Reversed"); - for (size_t i=0; iamiga.transWaveMap.size(); i++) { - DivInstrumentAmiga::TransWaveMap& transWaveMap=ins->amiga.transWaveMap[i]; - ImGui::TableNextRow(); - ImGui::PushID(fmt::sprintf("TransWaveMap_%d",i).c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%d",(int)(i)); - ImGui::TableNextColumn(); - if (transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen) { - sName="-- empty --"; - transWaveMap.ind=-1; - } else { - sName=e->song.sample[transWaveMap.ind]->name; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo(fmt::sprintf("##TransWaveMap_Index_%d",i).c_str(),sName.c_str())) { - String id; - if (ImGui::Selectable("-- empty --",transWaveMap.ind==-1)) { PARAMETER - transWaveMap.ind=-1; - } - for (int j=0; jsong.sampleLen; j++) { - DivSample* s=e->song.sample[j]; - id=fmt::sprintf("%d: %s",j,s->name); - if (ImGui::Selectable(id.c_str(),transWaveMap.ind==j)) { PARAMETER - transWaveMap.ind=j; - if (transWaveMap.loopStart<0 || transWaveMap.loopStart>(int)(s->samples)) { - transWaveMap.loopStart=CLAMP(s->loopStart,0,(int)s->samples); - } - if (transWaveMap.loopEnd<0 || transWaveMap.loopEnd>(int)(s->samples)) { - transWaveMap.loopEnd=CLAMP(s->loopEnd,0,(int)s->samples); - } - transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { - ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } - } - } - ImGui::EndCombo(); - } - ImGui::BeginDisabled(transWaveMap.ind<0 || transWaveMap.ind>=e->song.sampleLen); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopStart_%d",i).c_str(),&transWaveMap.loopStart,256,4096)) { PARAMETER - if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { - DivSample* s=e->song.sample[transWaveMap.ind]; - if (transWaveMap.loopStart<0) transWaveMap.loopStart=0; - if (transWaveMap.loopStart>transWaveMap.loopEnd) transWaveMap.loopStart=transWaveMap.loopEnd; - transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - if (ins->amiga.transWave.sliceEnable && (int)i==ins->amiga.transWave.ind) { - ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } - } - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##TransWaveMap_LoopEnd_%d",i).c_str(),&transWaveMap.loopEnd,256,4096)) { PARAMETER - if (transWaveMap.ind>=0 && transWaveMap.indsong.sampleLen) { - DivSample* s=e->song.sample[transWaveMap.ind]; - if (transWaveMap.loopEnd(int)(s->samples)) transWaveMap.loopEnd=s->samples; - transWaveMap.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - if (ins->amiga.transWave.sliceEnable) { - ins->amiga.transWave.updateSize(s->samples,transWaveMap.loopStart,transWaveMap.loopEnd); - ins->amiga.transWave.slicePos((double)(ins->amiga.transWave.slice)/4095.0); - } - } - } - ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Forward##TransWaveMap_LoopMode_Forward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOP_FORWARD)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOP_FORWARD; - } - if (ImGui::RadioButton(fmt::sprintf("Backward##TransWaveMap_LoopMode_Backward_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOP_BACKWARD)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOP_BACKWARD; - } - if (ImGui::RadioButton(fmt::sprintf("Pingpong##TransWaveMap_LoopMode_Pingpong_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOP_PINGPONG)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOP_PINGPONG; - } - if (ImGui::RadioButton(fmt::sprintf("Use sample setting##TransWaveMap_LoopMode_Default_%d",i).c_str(),transWaveMap.loopMode==DIV_SAMPLE_LOOP_MAX)) { MARK_MODIFIED - transWaveMap.loopMode=DIV_SAMPLE_LOOP_MAX; - } - ImGui::TableNextColumn(); - if (ImGui::RadioButton(fmt::sprintf("Disable##TransWaveMap_Reversed_Disable_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE)) { MARK_MODIFIED - transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DISABLE; - } - if (ImGui::RadioButton(fmt::sprintf("Enable##TransWaveMap_Reversed_Enable_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE)) { MARK_MODIFIED - transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_ENABLE; - } - if (ImGui::RadioButton(fmt::sprintf("Use instrument setting##TransWaveMap_Reversed_Default_%d",i).c_str(),transWaveMap.reversed==DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT)) { MARK_MODIFIED - transWaveMap.reversed=DivInstrumentAmiga::DivReverseMode::DIV_REVERSE_DEFAULT; - } - ImGui::EndDisabled(); - ImGui::PopID(); - } - ImGui::EndTable(); - } - } - ImGui::EndDisabled(); ImGui::EndTabItem(); } - if (ins->amiga.transWave.enable) { - if (ImGui::BeginTabItem("Transwave Macros")) { - macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,transwaveControlModes)); - macroList.push_back(FurnaceGUIMacroDesc("Transwave slice",&ins->std.fmsMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); - drawMacros(macroList); - ImGui::EndTabItem(); - } - } } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) { if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER @@ -4987,10 +4805,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; if ((ins->type==DIV_INS_AMIGA && !ins->amiga.useWave) || ins->type==DIV_INS_ES5506) { - if (ins->amiga.transWave.enable) { - waveLabel="Transwave index"; - waveMax=MAX(0,(int)(ins->amiga.transWaveMap.size())-1); - } else if (!ins->amiga.useWave) { + if (!ins->amiga.useWave) { waveLabel="Sample index"; waveMax=ins->amiga.useNoteMap?120:MAX(0,(int)(e->song.sampleLen)-1); } else { diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 30b49174a..2e50af963 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -2168,6 +2168,12 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Sammy/Seta/Visco SSV", { + DIV_SYSTEM_ES5506, 64, 0, 31, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Cave 68000", { DIV_SYSTEM_YMZ280B, 64, 0, 0, diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b40e433ac..0e75db30d 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -785,7 +785,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo break; } case DIV_SYSTEM_ES5506: { - int channels=flags.getInt("channels",0)+1; + int channels=flags.getInt("channels",0x1f)+1; ImGui::Text("Initial channel limit:"); if (CWSliderInt("##OTTO_InitialChannelLimit",&channels,5,32)) { if (channels<5) channels=5; From b6cdaa81e3d4f8c0b2b9c9f599854cc873e9124e Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 22 Oct 2022 17:36:33 +0900 Subject: [PATCH 45/74] Fix compile --- src/engine/platform/es5506.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index cf3670b35..54af2ef81 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -479,8 +479,6 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].pcm.note=next; } // get loop mode - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; // get reversed bool reversed=ins->amiga.reversed; From 9a41cff290781b8cf9b3d932ee1da241ce63ee90 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 22 Oct 2022 17:57:44 +0900 Subject: [PATCH 46/74] Remove unused variable --- src/engine/platform/es5506.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 54af2ef81..82c118898 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -645,7 +645,6 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { unsigned int startPos=chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start; if (chan[i].pcm.nextPos) { - const unsigned int start=chan[i].pcm.start; const unsigned int end=chan[i].pcm.length; startPos+=(chan[i].pcm.reversed?(end-chan[i].pcm.nextPos):chan[i].pcm.nextPos)<<11; chan[i].pcm.nextPos=0; From 2e3aee08d63404c466b766e80e0856ec7007d876 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 26 Oct 2022 12:27:25 +0900 Subject: [PATCH 47/74] Spelling fix --- src/engine/platform/es5506.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 82c118898..92aa2e20d 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -547,7 +547,7 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Forward loop loopFlag|=0x0008; break; case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable @@ -685,7 +685,7 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Forward loop loopFlag|=0x0008; break; case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable From 72594d978b8ee54936a98b304e3b2a7c516f0442 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 29 Oct 2022 21:49:31 +0900 Subject: [PATCH 48/74] Fix ES5506 command before keyon, Fix freqOffs change behavior, Fix initializing behavior, Reduce unnecessary variable --- src/engine/platform/es5506.cpp | 113 +++++++++++++++++++++++++++------ src/engine/platform/es5506.h | 47 ++++++++++++-- src/engine/sysDef.cpp | 18 +++--- src/gui/debug.cpp | 41 +++++++++++- 4 files changed, 184 insertions(+), 35 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 92aa2e20d..42ce685a3 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -143,13 +143,13 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformES5506::e_pin(bool state) { if (es5506.e_falling_edge()) { // get channel outputs if (es5506.voice_update()) { - chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); - chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); - chan[prevChanCycle].oscOut=CLAMP((chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5,-32768,32767); + const signed int lOut=es5506.voice_lout(prevChanCycle); + const signed int rOut=es5506.voice_rout(prevChanCycle); + chan[prevChanCycle].oscOut=CLAMP((lOut+rOut)>>5,-32768,32767); if (es5506.voice_end()) { if (prevChanCycle<31) { for (int c=31; c>prevChanCycle; c--) { - chan[c].lOut=chan[c].rOut=chan[c].oscOut=0; + chan[c].oscOut=0; } } } @@ -614,11 +614,9 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].noteChanged.offs) { if (chan[i].pcm.freqOffs!=chan[i].pcm.nextFreqOffs) { chan[i].pcm.freqOffs=chan[i].pcm.nextFreqOffs; - const int nextFreq=NOTE_ES5506(i,chan[i].currNote); - if (chan[i].nextFreq!=nextFreq) { - chan[i].nextFreq=nextFreq; - chan[i].noteChanged.freq=1; - } + chan[i].nextFreq=NOTE_ES5506(i,chan[i].currNote); + chan[i].noteChanged.freq=1; + chan[i].freqChanged=true; } } if (chan[i].noteChanged.note) { @@ -659,24 +657,36 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x00|i,0x01,chan[i].freq); pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); + // initialize overwrite + const DivInstrumentES5506::Filter::FilterMode filterModeInit=chan[i].overwrite.state.mode?chan[i].overwrite.filter.mode:chan[i].filter.mode; + const signed int k1Init=chan[i].overwrite.state.k1?chan[i].overwrite.filter.k1:chan[i].filter.k1; + const signed int k2Init=chan[i].overwrite.state.k2?chan[i].overwrite.filter.k2:chan[i].filter.k2; + + const unsigned short ecountInit=chan[i].overwrite.state.ecount?chan[i].overwrite.envelope.ecount:chan[i].envelope.ecount; + const unsigned char lVRampInit=(unsigned char)(chan[i].overwrite.state.lVRamp?chan[i].overwrite.envelope.lVRamp:chan[i].envelope.lVRamp); + const unsigned char rVRampInit=(unsigned char)(chan[i].overwrite.state.rVRamp?chan[i].overwrite.envelope.rVRamp:chan[i].envelope.rVRamp); + const unsigned char k1RampInit=(unsigned char)(chan[i].overwrite.state.k1Ramp?chan[i].overwrite.envelope.k1Ramp:chan[i].envelope.k1Ramp); + const unsigned char k2RampInit=(unsigned char)(chan[i].overwrite.state.k2Ramp?chan[i].overwrite.envelope.k2Ramp:chan[i].envelope.k2Ramp); + const bool k1SlowInit=chan[i].overwrite.state.k1Ramp?chan[i].overwrite.envelope.k1Slow:chan[i].envelope.k1Slow; + const bool k2SlowInit=chan[i].overwrite.state.k2Ramp?chan[i].overwrite.envelope.k2Slow:chan[i].envelope.k2Slow; // initialize envelope - pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8); - pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8); - pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0)); - pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); + pageWrite(0x00|i,0x03,lVRampInit<<8); + pageWrite(0x00|i,0x05,rVRampInit<<8); + pageWrite(0x00|i,0x0a,(k1RampInit<<8)|(k1SlowInit?1:0)); + pageWrite(0x00|i,0x08,(k2RampInit<<8)|(k2SlowInit?1:0)); // initialize filter - pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300); + pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(filterModeInit<<8),0xc300); if ((chan[i].std.ex2.mode!=0) && (chan[i].std.ex2.had)) { - k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); + k2=CLAMP(k2Init+chan[i].k2Offs,0,65535); } else { - k2=chan[i].filter.k2; + k2=k2Init; } pageWrite(0x00|i,0x07,k2); chan[i].k2Prev=k2; if ((chan[i].std.ex1.mode!=0) && (chan[i].std.ex1.had)) { - k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); + k1=CLAMP(k1Init+chan[i].k1Offs,0,65535); } else { - k1=chan[i].filter.k1; + k1=k1Init; } pageWrite(0x00|i,0x09,k1); chan[i].k1Prev=k1; @@ -703,17 +713,20 @@ void DivPlatformES5506::tick(bool sysTick) { loopFlag|=0x0002; } // Run sample - pageWrite(0x00|i,0x06,chan[i].envelope.ecount); // Clear ECOUNT + pageWrite(0x00|i,0x06,ecountInit); // Clear ECOUNT pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0x3cff); } } if (chan[i].keyOff) { pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR - } else if (chan[i].active) { + } else if (!chan[i].keyOn && chan[i].active) { pageWrite(0x00|i,0x01,chan[i].freq); } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; + if (chan[i].overwrite.state.overwrited!=0) { + chan[i].overwrite.state.overwrited=0; + } chan[i].freqChanged=false; } if (!chan[i].keyOn && chan[i].active) { @@ -854,14 +867,35 @@ int DivPlatformES5506::dispatch(DivCommand c) { break; // Filter commands case DIV_CMD_ES5506_FILTER_MODE: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.mode) { + chan[c.chan].overwrite.filter.mode=chan[c.chan].filter.mode; + chan[c.chan].overwrite.state.mode=1; + } + chan[c.chan].overwrite.filter.mode=DivInstrumentES5506::Filter::FilterMode(c.value&3); + } chan[c.chan].filter.mode=DivInstrumentES5506::Filter::FilterMode(c.value&3); chan[c.chan].filterChanged.mode=1; break; case DIV_CMD_ES5506_FILTER_K1: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.k1) { + chan[c.chan].overwrite.filter.k1=chan[c.chan].filter.k1; + chan[c.chan].overwrite.state.k1=1; + } + chan[c.chan].overwrite.filter.k1=(chan[c.chan].overwrite.filter.k1&~c.value2)|(c.value&c.value2); + } chan[c.chan].filter.k1=(chan[c.chan].filter.k1&~c.value2)|(c.value&c.value2); chan[c.chan].filterChanged.k1=1; break; case DIV_CMD_ES5506_FILTER_K2: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.k2) { + chan[c.chan].overwrite.filter.k2=chan[c.chan].filter.k2; + chan[c.chan].overwrite.state.k2=1; + } + chan[c.chan].overwrite.filter.k2=(chan[c.chan].overwrite.filter.k2&~c.value2)|(c.value&c.value2); + } chan[c.chan].filter.k2=(chan[c.chan].filter.k2&~c.value2)|(c.value&c.value2); chan[c.chan].filterChanged.k2=1; break; @@ -873,23 +907,62 @@ int DivPlatformES5506::dispatch(DivCommand c) { break; // Envelope commands case DIV_CMD_ES5506_ENVELOPE_COUNT: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.ecount) { + chan[c.chan].overwrite.envelope.ecount=chan[c.chan].envelope.ecount; + chan[c.chan].overwrite.state.ecount=1; + } + chan[c.chan].overwrite.envelope.ecount=c.value&0x1ff; + } chan[c.chan].envelope.ecount=c.value&0x1ff; chan[c.chan].envChanged.ecount=1; break; case DIV_CMD_ES5506_ENVELOPE_LVRAMP: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.lVRamp) { + chan[c.chan].overwrite.envelope.lVRamp=chan[c.chan].envelope.lVRamp; + chan[c.chan].overwrite.state.lVRamp=1; + } + chan[c.chan].overwrite.envelope.lVRamp=(signed char)(c.value&0xff); + } chan[c.chan].envelope.lVRamp=(signed char)(c.value&0xff); chan[c.chan].envChanged.lVRamp=1; break; case DIV_CMD_ES5506_ENVELOPE_RVRAMP: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.rVRamp) { + chan[c.chan].overwrite.envelope.rVRamp=chan[c.chan].envelope.rVRamp; + chan[c.chan].overwrite.state.rVRamp=1; + } + chan[c.chan].overwrite.envelope.rVRamp=(signed char)(c.value&0xff); + } chan[c.chan].envelope.rVRamp=(signed char)(c.value&0xff); chan[c.chan].envChanged.rVRamp=1; break; case DIV_CMD_ES5506_ENVELOPE_K1RAMP: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.k1Ramp) { + chan[c.chan].overwrite.envelope.k1Ramp=chan[c.chan].envelope.k1Ramp; + chan[c.chan].overwrite.envelope.k1Slow=chan[c.chan].envelope.k1Slow; + chan[c.chan].overwrite.state.k1Ramp=1; + } + chan[c.chan].overwrite.envelope.k1Ramp=(signed char)(c.value&0xff); + chan[c.chan].overwrite.envelope.k1Slow=c.value2&1; + } chan[c.chan].envelope.k1Ramp=(signed char)(c.value&0xff); chan[c.chan].envelope.k1Slow=c.value2&1; chan[c.chan].envChanged.k1Ramp=1; break; case DIV_CMD_ES5506_ENVELOPE_K2RAMP: + if (!chan[c.chan].keyOn) { + if (!chan[c.chan].overwrite.state.k2Ramp) { + chan[c.chan].overwrite.envelope.k2Ramp=chan[c.chan].envelope.k2Ramp; + chan[c.chan].overwrite.envelope.k2Slow=chan[c.chan].envelope.k2Slow; + chan[c.chan].overwrite.state.k2Ramp=1; + } + chan[c.chan].overwrite.envelope.k2Ramp=(signed char)(c.value&0xff); + chan[c.chan].overwrite.envelope.k2Slow=c.value2&1; + } chan[c.chan].envelope.k2Ramp=(signed char)(c.value&0xff); chan[c.chan].envelope.k2Slow=c.value2&1; chan[c.chan].envChanged.k2Ramp=1; diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 6bfcfc85c..d7b88c8b1 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -141,15 +141,46 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { }; unsigned char changed; }; + PCMChanged(): + changed(0) {} } pcmChanged; + struct Overwrite { + DivInstrumentES5506::Filter filter; + DivInstrumentES5506::Envelope envelope; + + struct State { + // overwrited flag + union { + struct { + unsigned char mode: 1; // filter mode + unsigned char k1: 1; // k1 + unsigned char k2: 1; // k2 + unsigned char ecount: 1; // envelope count + unsigned char lVRamp: 1; // left volume ramp + unsigned char rVRamp: 1; // right volume ramp + unsigned char k1Ramp: 1; // k1 ramp + unsigned char k2Ramp: 1; // k2 ramp + }; + unsigned char overwrited; + }; + State(): + overwrited(0) {} + } state; + + Overwrite(): + filter(DivInstrumentES5506::Filter()), + envelope(DivInstrumentES5506::Envelope()), + state(State()) {} + } overwrite; + signed int k1Offs, k2Offs; signed int k1Slide, k2Slide; signed int k1Prev, k2Prev; unsigned int vol, lVol, rVol; unsigned int outVol, outLVol, outRVol; unsigned int resLVol, resRVol; - signed int lOut, rOut, oscOut; + signed int oscOut; DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; DivMacroInt std; @@ -166,6 +197,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { k2Prev=0xffff; } Channel(): + pcm(PCM()), freq(0), baseFreq(0), nextFreq(0), @@ -187,6 +219,12 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { useWave(false), isReverseLoop(false), cr(0), + noteChanged(NoteChanged()), + volChanged(VolChanged()), + filterChanged(FilterChanged()), + envChanged(EnvChanged()), + pcmChanged(PCMChanged()), + overwrite(Overwrite()), k1Offs(0), k2Offs(0), k1Slide(0), @@ -201,9 +239,9 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { outRVol(0xffff), resLVol(0xffff), resRVol(0xffff), - lOut(0), - rOut(0), - oscOut(0) {} + oscOut(0), + filter(DivInstrumentES5506::Filter()), + envelope(DivInstrumentES5506::Envelope()) {} }; Channel chan[32]; DivDispatchOscBuffer* oscBuf[32]; @@ -263,6 +301,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { es5506_core es5506; unsigned char regPool[4*16*128]; // 7 bit page x 16 registers per page x 32 bit per registers + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index b1bcc3aac..de57b848d 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1478,11 +1478,8 @@ void DivEngine::registerSystems() { ); EffectHandlerMap es5506PreEffectHandlerMap={ - {0x10, {DIV_CMD_WAVE, "10xx: Change waveform or sample (00 to FF)",effectVal}} - }; - EffectHandlerMap es5506PostEffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Change waveform or sample (00 to FF)",effectVal}}, {0x11, {DIV_CMD_ES5506_FILTER_MODE, "11xx: Set filter mode (00 to 03)",effectValAnd<3>}}, - {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}}, {0x14, {DIV_CMD_ES5506_FILTER_K1, "14xx: Set filter coefficient K1 low byte (00 to FF)",effectValShift<0>,constVal<0x00ff>}}, {0x15, {DIV_CMD_ES5506_FILTER_K1, "15xx: Set filter coefficient K1 high byte (00 to FF)",effectValShift<8>,constVal<0xff00>}}, {0x16, {DIV_CMD_ES5506_FILTER_K2, "16xx: Set filter coefficient K2 low byte (00 to FF)",effectValShift<0>,constVal<0x00ff>}}, @@ -1498,12 +1495,15 @@ void DivEngine::registerSystems() { {0x26, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "26xx: Set envelope filter coefficient k2 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "27xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}} }; + EffectHandlerMap es5506PostEffectHandlerMap={ + {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}} + }; const EffectHandler es5506ECountHandler(DIV_CMD_ES5506_ENVELOPE_COUNT, "2xxx: Set envelope count (000 to 1FF)", effectValLong<9>); - const EffectHandler es5506K1Handler(DIV_CMD_ES5506_FILTER_K1, "3xxx: Set filter coefficient K1 (000 to FFF)", effectValLongShift<12,4>); - const EffectHandler es5506K2Handler(DIV_CMD_ES5506_FILTER_K2, "4xxx: Set filter coefficient K2 (000 to FFF)", effectValLongShift<12,4>); - for (int i=0; i<2; i++) es5506PostEffectHandlerMap.emplace(0x20+i,es5506ECountHandler); - for (int i=0; i<16; i++) es5506PostEffectHandlerMap.emplace(0x30+i, es5506K1Handler); - for (int i=0; i<16; i++) es5506PostEffectHandlerMap.emplace(0x40+i, es5506K2Handler); + const EffectHandler es5506K1Handler(DIV_CMD_ES5506_FILTER_K1, "3xxx: Set filter coefficient K1 (000 to FFF)", effectValLongShift<12,4>,constVal<0xfff0>); + const EffectHandler es5506K2Handler(DIV_CMD_ES5506_FILTER_K2, "4xxx: Set filter coefficient K2 (000 to FFF)", effectValLongShift<12,4>,constVal<0xfff0>); + for (int i=0; i<2; i++) es5506PreEffectHandlerMap.emplace(0x20+i,es5506ECountHandler); + for (int i=0; i<16; i++) es5506PreEffectHandlerMap.emplace(0x30+i, es5506K1Handler); + for (int i=0; i<16; i++) es5506PreEffectHandlerMap.emplace(0x40+i, es5506K2Handler); // TODO: custom sample format sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 51b8fbea8..1956b2fcd 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -554,6 +554,24 @@ void putDispatchChip(void* data, int type) { ImGui::TextColored(ch->outStereo?colorOn:colorOff,">> OutStereo"); break; } + case DIV_SYSTEM_ES5506: { + DivPlatformES5506* ch=(DivPlatformES5506*)data; + ImGui::Text("> ES5506"); + COMMON_CHIP_DEBUG; + ImGui::Text("- cycle: %d",ch->cycle); + ImGui::Text("- curPage: %d",ch->curPage); + ImGui::Text("- maskedVal: %.2x",ch->maskedVal); + ImGui::Text("- irqv: %.2x",ch->irqv); + ImGui::Text("- curCR: %.8x",ch->curCR); + ImGui::Text("- prevChanCycle: %d",ch->prevChanCycle); + ImGui::Text("- initChanMax: %d",ch->initChanMax); + ImGui::Text("- chanMax: %d",ch->chanMax); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->isMasked?colorOn:colorOff,">> IsMasked"); + ImGui::TextColored(ch->isReaded?colorOn:colorOff,">> isReaded"); + ImGui::TextColored(ch->irqTrigger?colorOn:colorOff,">> IrqTrigger"); + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; @@ -1095,6 +1113,17 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - K2Slide: %d",ch->k2Slide); ImGui::Text(" - K1Prev: %.4x",ch->k1Prev); ImGui::Text(" - K2Prev: %.4x",ch->k2Prev); + ImGui::Text("* Overwrite:"); + ImGui::Text(" * Filter:"); + ImGui::Text(" - Mode: %d",ch->overwrite.filter.mode); + ImGui::Text(" - K1: %.4x",ch->overwrite.filter.k1); + ImGui::Text(" - K2: %.4x",ch->overwrite.filter.k2); + ImGui::Text(" * Envelope:"); + ImGui::Text(" - EnvCount: %.3x",ch->overwrite.envelope.ecount); + ImGui::Text(" - LVRamp: %d",ch->overwrite.envelope.lVRamp); + ImGui::Text(" - RVRamp: %d",ch->overwrite.envelope.rVRamp); + ImGui::Text(" - K1Ramp: %d",ch->overwrite.envelope.k1Ramp); + ImGui::Text(" - K2Ramp: %d",ch->overwrite.envelope.k2Ramp); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- LVol: %.2x",ch->lVol); ImGui::Text("- RVol: %.2x",ch->rVol); @@ -1103,8 +1132,6 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- outRVol: %.2x",ch->outRVol); ImGui::Text("- ResLVol: %.2x",ch->resLVol); ImGui::Text("- ResRVol: %.2x",ch->resRVol); - ImGui::Text("- LOut: %d",ch->lOut); - ImGui::Text("- ROut: %d",ch->rOut); ImGui::Text("- oscOut: %d",ch->oscOut); ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); @@ -1127,6 +1154,16 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->pcm.reversed?colorOn:colorOff,">> PCMReversed"); ImGui::TextColored(ch->envelope.k1Slow?colorOn:colorOff,">> EnvK1Slow"); ImGui::TextColored(ch->envelope.k2Slow?colorOn:colorOff,">> EnvK2Slow"); + ImGui::TextColored(ch->overwrite.envelope.k1Slow?colorOn:colorOff,">> EnvK1SlowOverwrite"); + ImGui::TextColored(ch->overwrite.envelope.k2Slow?colorOn:colorOff,">> EnvK2SlowOverwrite"); + ImGui::TextColored(ch->overwrite.state.mode?colorOn:colorOff,">> FilterModeOverwrited"); + ImGui::TextColored(ch->overwrite.state.k1?colorOn:colorOff,">> FilterK1Overwrited"); + ImGui::TextColored(ch->overwrite.state.k2?colorOn:colorOff,">> FilterK2Overwrited"); + ImGui::TextColored(ch->overwrite.state.ecount?colorOn:colorOff,">> EnvECountOverwrited"); + ImGui::TextColored(ch->overwrite.state.lVRamp?colorOn:colorOff,">> EnvLVRampOverwrited"); + ImGui::TextColored(ch->overwrite.state.rVRamp?colorOn:colorOff,">> EnvRVRampOverwrited"); + ImGui::TextColored(ch->overwrite.state.k1Ramp?colorOn:colorOff,">> EnvK1RampOverwrited"); + ImGui::TextColored(ch->overwrite.state.k2Ramp?colorOn:colorOff,">> EnvK2RampOverwrited"); break; } case DIV_SYSTEM_LYNX: { From 1dd217de2196b2c0fbd0f93c0f38a3af78367116 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 29 Oct 2022 22:07:48 +0900 Subject: [PATCH 49/74] Fix sample position command --- src/engine/platform/es5506.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 42ce685a3..c781aa3e8 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -643,8 +643,9 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { unsigned int startPos=chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start; if (chan[i].pcm.nextPos) { + const unsigned int start=chan[i].pcm.start; const unsigned int end=chan[i].pcm.length; - startPos+=(chan[i].pcm.reversed?(end-chan[i].pcm.nextPos):chan[i].pcm.nextPos)<<11; + startPos=start+((chan[i].pcm.reversed?(end-chan[i].pcm.nextPos):(chan[i].pcm.nextPos))<<11); chan[i].pcm.nextPos=0; } chan[i].k1Prev=0xffff; From ae3d0bf019858db07ad92caf6c96dcde7aa7930f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 29 Oct 2022 22:29:14 +0900 Subject: [PATCH 50/74] Add some comments --- src/engine/platform/es5506.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index c781aa3e8..f20c56085 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -659,10 +659,11 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); // initialize overwrite + // Filter const DivInstrumentES5506::Filter::FilterMode filterModeInit=chan[i].overwrite.state.mode?chan[i].overwrite.filter.mode:chan[i].filter.mode; const signed int k1Init=chan[i].overwrite.state.k1?chan[i].overwrite.filter.k1:chan[i].filter.k1; const signed int k2Init=chan[i].overwrite.state.k2?chan[i].overwrite.filter.k2:chan[i].filter.k2; - + // Envelope const unsigned short ecountInit=chan[i].overwrite.state.ecount?chan[i].overwrite.envelope.ecount:chan[i].envelope.ecount; const unsigned char lVRampInit=(unsigned char)(chan[i].overwrite.state.lVRamp?chan[i].overwrite.envelope.lVRamp:chan[i].envelope.lVRamp); const unsigned char rVRampInit=(unsigned char)(chan[i].overwrite.state.rVRamp?chan[i].overwrite.envelope.rVRamp:chan[i].envelope.rVRamp); From ec6460da703127666ebafc0e7b407e93f9cad406 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 30 Oct 2022 03:00:33 +0900 Subject: [PATCH 51/74] Actually fixes overwrite command --- src/engine/platform/es5506.cpp | 66 +++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index f20c56085..65a5b7e94 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -659,36 +659,55 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); // initialize overwrite - // Filter - const DivInstrumentES5506::Filter::FilterMode filterModeInit=chan[i].overwrite.state.mode?chan[i].overwrite.filter.mode:chan[i].filter.mode; - const signed int k1Init=chan[i].overwrite.state.k1?chan[i].overwrite.filter.k1:chan[i].filter.k1; - const signed int k2Init=chan[i].overwrite.state.k2?chan[i].overwrite.filter.k2:chan[i].filter.k2; - // Envelope - const unsigned short ecountInit=chan[i].overwrite.state.ecount?chan[i].overwrite.envelope.ecount:chan[i].envelope.ecount; - const unsigned char lVRampInit=(unsigned char)(chan[i].overwrite.state.lVRamp?chan[i].overwrite.envelope.lVRamp:chan[i].envelope.lVRamp); - const unsigned char rVRampInit=(unsigned char)(chan[i].overwrite.state.rVRamp?chan[i].overwrite.envelope.rVRamp:chan[i].envelope.rVRamp); - const unsigned char k1RampInit=(unsigned char)(chan[i].overwrite.state.k1Ramp?chan[i].overwrite.envelope.k1Ramp:chan[i].envelope.k1Ramp); - const unsigned char k2RampInit=(unsigned char)(chan[i].overwrite.state.k2Ramp?chan[i].overwrite.envelope.k2Ramp:chan[i].envelope.k2Ramp); - const bool k1SlowInit=chan[i].overwrite.state.k1Ramp?chan[i].overwrite.envelope.k1Slow:chan[i].envelope.k1Slow; - const bool k2SlowInit=chan[i].overwrite.state.k2Ramp?chan[i].overwrite.envelope.k2Slow:chan[i].envelope.k2Slow; + if (chan[i].overwrite.state.overwrited) { + // Filter + if (chan[i].overwrite.state.mode) { + chan[i].filter.mode=chan[i].overwrite.filter.mode; + } + if (chan[i].overwrite.state.k1) { + chan[i].filter.k1=chan[i].overwrite.filter.k1; + } + if (chan[i].overwrite.state.k2) { + chan[i].filter.k2=chan[i].overwrite.filter.k2; + } + // Envelope + if (chan[i].overwrite.state.ecount) { + chan[i].envelope.ecount=chan[i].overwrite.envelope.ecount; + } + if (chan[i].overwrite.state.lVRamp) { + chan[i].envelope.lVRamp=chan[i].overwrite.envelope.lVRamp; + } + if (chan[i].overwrite.state.rVRamp) { + chan[i].envelope.rVRamp=chan[i].overwrite.envelope.rVRamp; + } + if (chan[i].overwrite.state.k1Ramp) { + chan[i].envelope.k1Ramp=chan[i].overwrite.envelope.k1Ramp; + chan[i].envelope.k1Slow=chan[i].overwrite.envelope.k1Slow; + } + if (chan[i].overwrite.state.k2Ramp) { + chan[i].envelope.k2Ramp=chan[i].overwrite.envelope.k2Ramp; + chan[i].envelope.k2Slow=chan[i].overwrite.envelope.k2Slow; + } + chan[i].overwrite.state.overwrited=0; + } // initialize envelope - pageWrite(0x00|i,0x03,lVRampInit<<8); - pageWrite(0x00|i,0x05,rVRampInit<<8); - pageWrite(0x00|i,0x0a,(k1RampInit<<8)|(k1SlowInit?1:0)); - pageWrite(0x00|i,0x08,(k2RampInit<<8)|(k2SlowInit?1:0)); + pageWrite(0x00|i,0x03,(unsigned char)(chan[i].envelope.lVRamp)<<8); + pageWrite(0x00|i,0x05,(unsigned char)(chan[i].envelope.rVRamp)<<8); + pageWrite(0x00|i,0x0a,((unsigned char)(chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0)); + pageWrite(0x00|i,0x08,((unsigned char)(chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); // initialize filter - pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(filterModeInit<<8),0xc300); + pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300); if ((chan[i].std.ex2.mode!=0) && (chan[i].std.ex2.had)) { - k2=CLAMP(k2Init+chan[i].k2Offs,0,65535); + k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); } else { - k2=k2Init; + k2=chan[i].filter.k2; } pageWrite(0x00|i,0x07,k2); chan[i].k2Prev=k2; if ((chan[i].std.ex1.mode!=0) && (chan[i].std.ex1.had)) { - k1=CLAMP(k1Init+chan[i].k1Offs,0,65535); + k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); } else { - k1=k1Init; + k1=chan[i].filter.k1; } pageWrite(0x00|i,0x09,k1); chan[i].k1Prev=k1; @@ -715,7 +734,7 @@ void DivPlatformES5506::tick(bool sysTick) { loopFlag|=0x0002; } // Run sample - pageWrite(0x00|i,0x06,ecountInit); // Clear ECOUNT + pageWrite(0x00|i,0x06,chan[i].envelope.ecount); // Clear ECOUNT pageWriteMask(0x00|i,0x5f,0x00,loopFlag,0x3cff); } } @@ -726,9 +745,6 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; - if (chan[i].overwrite.state.overwrited!=0) { - chan[i].overwrite.state.overwrited=0; - } chan[i].freqChanged=false; } if (!chan[i].keyOn && chan[i].active) { From 893582fc68925ff0f5c1e0d09d4a5b58a813c445 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 30 Oct 2022 03:06:47 +0900 Subject: [PATCH 52/74] Fix overwrite condition --- src/engine/platform/es5506.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 65a5b7e94..764f11161 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -885,7 +885,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { break; // Filter commands case DIV_CMD_ES5506_FILTER_MODE: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.mode) { chan[c.chan].overwrite.filter.mode=chan[c.chan].filter.mode; chan[c.chan].overwrite.state.mode=1; @@ -896,7 +896,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].filterChanged.mode=1; break; case DIV_CMD_ES5506_FILTER_K1: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.k1) { chan[c.chan].overwrite.filter.k1=chan[c.chan].filter.k1; chan[c.chan].overwrite.state.k1=1; @@ -907,7 +907,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].filterChanged.k1=1; break; case DIV_CMD_ES5506_FILTER_K2: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.k2) { chan[c.chan].overwrite.filter.k2=chan[c.chan].filter.k2; chan[c.chan].overwrite.state.k2=1; @@ -925,7 +925,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { break; // Envelope commands case DIV_CMD_ES5506_ENVELOPE_COUNT: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.ecount) { chan[c.chan].overwrite.envelope.ecount=chan[c.chan].envelope.ecount; chan[c.chan].overwrite.state.ecount=1; @@ -936,7 +936,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.ecount=1; break; case DIV_CMD_ES5506_ENVELOPE_LVRAMP: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.lVRamp) { chan[c.chan].overwrite.envelope.lVRamp=chan[c.chan].envelope.lVRamp; chan[c.chan].overwrite.state.lVRamp=1; @@ -947,7 +947,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.lVRamp=1; break; case DIV_CMD_ES5506_ENVELOPE_RVRAMP: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.rVRamp) { chan[c.chan].overwrite.envelope.rVRamp=chan[c.chan].envelope.rVRamp; chan[c.chan].overwrite.state.rVRamp=1; @@ -958,7 +958,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.rVRamp=1; break; case DIV_CMD_ES5506_ENVELOPE_K1RAMP: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.k1Ramp) { chan[c.chan].overwrite.envelope.k1Ramp=chan[c.chan].envelope.k1Ramp; chan[c.chan].overwrite.envelope.k1Slow=chan[c.chan].envelope.k1Slow; @@ -972,7 +972,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.k1Ramp=1; break; case DIV_CMD_ES5506_ENVELOPE_K2RAMP: - if (!chan[c.chan].keyOn) { + if (!chan[c.chan].active) { if (!chan[c.chan].overwrite.state.k2Ramp) { chan[c.chan].overwrite.envelope.k2Ramp=chan[c.chan].envelope.k2Ramp; chan[c.chan].overwrite.envelope.k2Slow=chan[c.chan].envelope.k2Slow; From 5cc8f7163bc81af814ac4cb44c7ea494eca1d174 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 30 Oct 2022 18:47:52 +0900 Subject: [PATCH 53/74] Add notes for silent --- src/engine/platform/es5506.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 764f11161..cd4da7ed1 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1195,7 +1195,7 @@ void DivPlatformES5506::renderSamples() { memset(sampleMem,0,getSampleMemCapacity()); memset(sampleOffES5506,0,256*sizeof(unsigned int)); - size_t memPos=128; + size_t memPos=128; // add silent at begin and end of each bank for reverse playback for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; unsigned int length=s->length16; From 35b2de803794a90518c3c71721517f2f9c509458 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 4 Dec 2022 16:58:54 +0900 Subject: [PATCH 54/74] Sync with master --- src/engine/platform/es5506.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 455473712..8133c40ab 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1146,6 +1146,9 @@ void DivPlatformES5506::notifyInsDeletion(void* ins) { } void DivPlatformES5506::setFlags(const DivConfig& flags) { + chipClock=16000000; + CHECK_CUSTOM_CLOCK; + rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice initChanMax=MAX(4,flags.getInt("channels",0x1f)&0x1f); chanMax=initChanMax; pageWriteMask(0x00,0x60,0x0b,chanMax); @@ -1242,8 +1245,6 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, const DivCo dumpWrites=false; skipRegisterWrites=false; - chipClock=16000000; - rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice for (int i=0; i<32; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; From 317e9d01e2756a73637687851aecac7efddd6007 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 4 Dec 2022 16:59:21 +0900 Subject: [PATCH 55/74] Fix crash --- src/engine/platform/es5506.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 8133c40ab..0a16648a6 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1245,12 +1245,13 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, const DivCo dumpWrites=false; skipRegisterWrites=false; + setFlags(flags); + for (int i=0; i<32; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; oscBuf[i]->rate=rate; } - setFlags(flags); reset(); return 32; From 5672590cdc4ba258fb1ddf809f1cd9cf167c4f16 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 4 Dec 2022 17:00:29 +0900 Subject: [PATCH 56/74] Fix again --- src/engine/platform/es5506.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 0a16648a6..8382a57bd 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1149,6 +1149,10 @@ void DivPlatformES5506::setFlags(const DivConfig& flags) { chipClock=16000000; CHECK_CUSTOM_CLOCK; rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice + for (int i=0; i<32; i++) { + oscBuf[i]->rate=rate; + } + initChanMax=MAX(4,flags.getInt("channels",0x1f)&0x1f); chanMax=initChanMax; pageWriteMask(0x00,0x60,0x0b,chanMax); @@ -1245,14 +1249,13 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, const DivCo dumpWrites=false; skipRegisterWrites=false; - setFlags(flags); - for (int i=0; i<32; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; - oscBuf[i]->rate=rate; } + setFlags(flags); + reset(); return 32; } From f6cfc72b39819c7b42b95bc77c62e43fef228eaa Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 13 Dec 2022 14:53:00 +0900 Subject: [PATCH 57/74] Sync with master --- src/engine/platform/es5506.h | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 626f014b8..b26fc0d4d 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -30,7 +30,7 @@ #include "vgsound_emu/src/es550x/es5506.hpp" class DivPlatformES5506: public DivDispatch, public es550x_intf { - struct Channel { + struct Channel : public SharedChannelFreq, public SharedChannelVolume { struct PCM { bool isNoteMap; int index, next; @@ -64,9 +64,9 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { nextPos(0), loopMode(DIV_SAMPLE_LOOP_MAX) {} } pcm; - int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, currNote, ins, wave; + int nextFreq, nextNote, currNote, wave; unsigned int volMacroMax, panMacroMax; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop; + bool useWave, isReverseLoop; unsigned int cr; struct NoteChanged { // Note changed flags @@ -177,8 +177,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { signed int k1Offs, k2Offs; signed int k1Slide, k2Slide; signed int k1Prev, k2Prev; - unsigned int vol, lVol, rVol; - unsigned int outVol, outLVol, outRVol; + unsigned int lVol, rVol; + unsigned int outLVol, outRVol; unsigned int resLVol, resRVol; signed int oscOut; DivInstrumentES5506::Filter filter; @@ -197,25 +197,15 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { k2Prev=0xffff; } Channel(): + SharedChannelFreq(), + SharedChannelVolume(0xff), pcm(PCM()), - freq(0), - baseFreq(0), nextFreq(0), - pitch(0), - pitch2(0), - note(0), nextNote(0), currNote(0), - ins(-1), wave(-1), volMacroMax(0xffff), panMacroMax(0xffff), - active(false), - insChanged(true), - freqChanged(false), - keyOn(false), - keyOff(false), - inPorta(false), useWave(false), isReverseLoop(false), cr(0), @@ -231,17 +221,17 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { k2Slide(0), k1Prev(0xffff), k2Prev(0xffff), - vol(0xff), lVol(0xff), rVol(0xff), - outVol(0xffff), outLVol(0xffff), outRVol(0xffff), resLVol(0xffff), resRVol(0xffff), oscOut(0), filter(DivInstrumentES5506::Filter()), - envelope(DivInstrumentES5506::Envelope()) {} + envelope(DivInstrumentES5506::Envelope()) { + outVol=0xffff; + } }; Channel chan[32]; DivDispatchOscBuffer* oscBuf[32]; From 1c4138dcff08f11615b9c535879735a9d79d1bf0 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 14 Dec 2022 14:13:17 +0900 Subject: [PATCH 58/74] Sync with master --- src/engine/chipUtils.h | 2 +- src/engine/platform/es5506.h | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/engine/chipUtils.h b/src/engine/chipUtils.h index 814935e61..57d4731c0 100644 --- a/src/engine/chipUtils.h +++ b/src/engine/chipUtils.h @@ -33,7 +33,7 @@ template struct SharedChannel { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; T vol, outVol; DivMacroInt std; - void macroInit(DivInstrument* which) { + virtual void macroInit(DivInstrument* which) { std.init(which); pitch2=0; } diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index b26fc0d4d..abd9ffb77 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -30,7 +30,7 @@ #include "vgsound_emu/src/es550x/es5506.hpp" class DivPlatformES5506: public DivDispatch, public es550x_intf { - struct Channel : public SharedChannelFreq, public SharedChannelVolume { + struct Channel : public SharedChannel { struct PCM { bool isNoteMap; int index, next; @@ -183,10 +183,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { signed int oscOut; DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; - DivMacroInt std; - void macroInit(DivInstrument* which) { - std.init(which); - pitch2=0; + virtual void macroInit(DivInstrument* which) override { + SharedChannel::macroInit(which); if (std.ex1.mode==2) { k1Offs=0; } @@ -197,8 +195,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { k2Prev=0xffff; } Channel(): - SharedChannelFreq(), - SharedChannelVolume(0xff), + SharedChannel(0xff), pcm(PCM()), nextFreq(0), nextNote(0), From e454fdb3d5fcf7dcd1c426670564846e64c31f53 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 14 Dec 2022 14:16:01 +0900 Subject: [PATCH 59/74] Reduce debug duplication --- src/gui/debug.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 895965311..d02d7ab73 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -863,15 +863,10 @@ void putDispatchChan(void* data, int chanNum, int type) { case DIV_SYSTEM_ES5506: { DivPlatformES5506::Channel* ch=(DivPlatformES5506::Channel*)data; ImGui::Text("> ES5506"); - ImGui::Text("* freq: %.5x",ch->freq); - ImGui::Text(" - base: %d",ch->baseFreq); - ImGui::Text(" - next: %d",ch->nextFreq); - ImGui::Text(" - pitch: %d",ch->pitch); - ImGui::Text(" - pitch2: %d",ch->pitch2); - ImGui::Text("* note: %d",ch->note); - ImGui::Text(" - next: %d",ch->nextNote); - ImGui::Text(" - curr: %d",ch->currNote); - ImGui::Text("- ins: %d",ch->ins); + COMMON_CHAN_DEBUG; + ImGui::Text("- nextFreq: %d",ch->nextFreq); + ImGui::Text("- nextNote: %d",ch->nextNote); + ImGui::Text("- currNote: %d",ch->currNote); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- VolMacroMax: %d",ch->volMacroMax); ImGui::Text("- PanMacroMax: %d",ch->panMacroMax); @@ -916,18 +911,14 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - RVRamp: %d",ch->overwrite.envelope.rVRamp); ImGui::Text(" - K1Ramp: %d",ch->overwrite.envelope.k1Ramp); ImGui::Text(" - K2Ramp: %d",ch->overwrite.envelope.k2Ramp); - ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- LVol: %.2x",ch->lVol); ImGui::Text("- RVol: %.2x",ch->rVol); - ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- outLVol: %.2x",ch->outLVol); ImGui::Text("- outRVol: %.2x",ch->outRVol); ImGui::Text("- ResLVol: %.2x",ch->resLVol); ImGui::Text("- ResRVol: %.2x",ch->resRVol); ImGui::Text("- oscOut: %d",ch->oscOut); - ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); - ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); - ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + COMMON_CHAN_DEBUG_BOOL; ImGui::TextColored(ch->volChanged.lVol?colorOn:colorOff,">> LVolChanged"); ImGui::TextColored(ch->volChanged.rVol?colorOn:colorOff,">> RVolChanged"); ImGui::TextColored(ch->filterChanged.mode?colorOn:colorOff,">> FilterModeChanged"); From 2e7a0c37e3b544c77ca09c0f267b965490828453 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 15 Dec 2022 17:35:01 +0900 Subject: [PATCH 60/74] Add DIV_CMD_SAMPLE_DIR command and macro --- src/engine/platform/es5506.cpp | 27 ++++++++++++++++++++------- src/engine/platform/es5506.h | 4 +++- src/engine/sysDef.cpp | 3 ++- src/gui/debug.cpp | 2 ++ src/gui/insEdit.cpp | 6 +++--- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 8382a57bd..855d7b45d 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -407,6 +407,12 @@ void DivPlatformES5506::tick(bool sysTick) { pageWriteMask(0x00|i,0x5f,0x00,chan[i].pcm.pause?0x0002:0x0000,0x0002); } } + if (chan[i].pcm.direction!=(bool)(chan[i].std.alg.val&2)) { + chan[i].pcm.direction=chan[i].std.alg.val&2; + if (!chan[i].keyOn) { + pageWriteMask(0x00|i,0x5f,0x00,chan[i].pcm.isReversed()?0x0040:0x0000,0x0040); + } + } } if (chan[i].pcm.isNoteMap) { // note map macros @@ -510,7 +516,7 @@ void DivPlatformES5506::tick(bool sysTick) { } if (sampleVaild) { if (!chan[i].keyOn) { - pageWrite(0x20|i,0x03,(chan[i].pcm.reversed)?chan[i].pcm.end:chan[i].pcm.start); + pageWrite(0x20|i,0x03,(chan[i].pcm.isReversed())?chan[i].pcm.end:chan[i].pcm.start); } chan[i].pcmChanged.slice=1; } @@ -544,7 +550,7 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].pcmChanged.loopBank) { if (!chan[i].keyOn) { - unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); + unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.isReversed()?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { case DIV_SAMPLE_LOOP_FORWARD: // Forward loop @@ -641,11 +647,11 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].freq=CLAMP(parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,chan[i].pcm.freqOffs),0,0x1ffff); if (chan[i].keyOn) { if (chan[i].pcm.index>=0 && chan[i].pcm.indexsong.sampleLen) { - unsigned int startPos=chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start; + unsigned int startPos=chan[i].pcm.isReversed()?chan[i].pcm.end:chan[i].pcm.start; if (chan[i].pcm.nextPos) { const unsigned int start=chan[i].pcm.start; const unsigned int end=chan[i].pcm.length; - startPos=start+((chan[i].pcm.reversed?(end-chan[i].pcm.nextPos):(chan[i].pcm.nextPos))<<11); + startPos=start+((chan[i].pcm.isReversed()?(end-chan[i].pcm.nextPos):(chan[i].pcm.nextPos))<<11); chan[i].pcm.nextPos=0; } chan[i].k1Prev=0xffff; @@ -713,7 +719,7 @@ void DivPlatformES5506::tick(bool sysTick) { chan[i].k1Prev=k1; pageWrite(0x00|i,0x02,chan[i].resLVol); pageWrite(0x00|i,0x04,chan[i].resRVol); - unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; + unsigned int loopFlag=chan[i].pcm.isReversed()?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { case DIV_SAMPLE_LOOP_FORWARD: // Forward loop @@ -1036,8 +1042,8 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].active) { const unsigned int start=chan[c.chan].pcm.start; const unsigned int end=chan[c.chan].pcm.length; - const unsigned int pos=chan[c.chan].pcm.reversed?(end-c.value):c.value; - if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && pos0) || ((!chan[c.chan].pcm.isReversed()) && pos { struct PCM { + bool isReversed() { return reversed^direction; } bool isNoteMap; int index, next; int note; double freqOffs; double nextFreqOffs; - bool reversed, pause; + bool reversed, pause, direction; unsigned int bank; unsigned int start; unsigned int end; @@ -55,6 +56,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { nextFreqOffs(1.0), reversed(false), pause(false), + direction(false), bank(0), start(0), end(0), diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 62615d2f7..f9a88ed79 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1497,7 +1497,8 @@ void DivEngine::registerSystems() { {0x24, {DIV_CMD_ES5506_ENVELOPE_K1RAMP, "24xx: Set envelope filter coefficient k1 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, {0x25, {DIV_CMD_ES5506_ENVELOPE_K1RAMP, "25xx: Set envelope filter coefficient k1 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}}, {0x26, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "26xx: Set envelope filter coefficient k2 ramp (signed) (00 to FF)",effectVal,constVal<0>}}, - {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "27xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}} + {0x27, {DIV_CMD_ES5506_ENVELOPE_K2RAMP, "27xx: Set envelope filter coefficient k2 ramp (signed, slower) (00 to FF)",effectVal,constVal<1>}}, + {0xdf, {DIV_CMD_SAMPLE_DIR, "DFxx: Set sample playback direction (0: normal; 1: reverse)"}} }; EffectHandlerMap es5506PostEffectHandlerMap={ {0x12, {DIV_CMD_ES5506_PAUSE, "120x: Set pause (bit 0)",effectValAnd<1>}} diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 436afde02..8fa585673 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -947,6 +947,8 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->pcmChanged.loopBank?colorOn:colorOff,">> PCMLoopBankChanged"); ImGui::TextColored(ch->isReverseLoop?colorOn:colorOff,">> IsReverseLoop"); ImGui::TextColored(ch->pcm.reversed?colorOn:colorOff,">> PCMReversed"); + ImGui::TextColored(ch->pcm.pause?colorOn:colorOff,">> PCMPause"); + ImGui::TextColored(ch->pcm.direction?colorOn:colorOff,">> PCMDirection"); ImGui::TextColored(ch->envelope.k1Slow?colorOn:colorOff,">> EnvK1Slow"); ImGui::TextColored(ch->envelope.k2Slow?colorOn:colorOff,">> EnvK2Slow"); ImGui::TextColored(ch->overwrite.envelope.k1Slow?colorOn:colorOff,">> EnvK1SlowOverwrite"); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 63bbc7f62..3c41d1d5c 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -291,8 +291,8 @@ const char* es5506EnvelopeModes[3]={ "k1 slowdown", "k2 slowdown", NULL }; -const char* es5506ControlModes[2]={ - "pause", NULL +const char* es5506ControlModes[3]={ + "pause", "reverse", NULL }; const int orderedOps[4]={ @@ -5411,7 +5411,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes)); - macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); } if (ins->type==DIV_INS_MSM5232) { macroList.push_back(FurnaceGUIMacroDesc("Noise",&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); From e53efe2bcb9b61f929a758d90d9bb34ebf4bf541 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Dec 2022 15:00:58 +0900 Subject: [PATCH 61/74] sync with master --- src/engine/platform/es5506.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 855d7b45d..b59128277 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1064,6 +1064,12 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_GET_VOLMAX: return 255; 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_ALWAYS_SET_VOLUME: return 1; break; From f80a686cf58ff9d25ef2942e7b3aa6d3a574ce20 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 17 Dec 2022 18:37:08 +0900 Subject: [PATCH 62/74] Fix build --- src/engine/platform/ay.h | 3 ++- src/engine/platform/ay8930.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 430d5631c..e8d7efcec 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -80,7 +80,8 @@ class DivPlatformAY8910: public DivDispatch { nextPSGMode(PSGMode(1)), dac(DAC()), autoEnvNum(0), - autoEnvDen(0) {} + autoEnvDen(0), + konCycles(0) {} }; Channel chan[3]; bool isMuted[3]; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index d51ebf0de..0bd2171a1 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -90,7 +90,8 @@ class DivPlatformAY8930: public DivDispatch { dac(DAC()), autoEnvNum(0), autoEnvDen(0), - duty(4) {} + duty(4), + konCycles(0) {} }; Channel chan[3]; bool isMuted[3]; From d4defdf4c04b23c194be3c3a833dd197b21f5c4d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 18 Dec 2022 06:27:49 +0900 Subject: [PATCH 63/74] Fix build --- src/engine/platform/qsound.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 18eb886b4..dbdffd051 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -35,6 +35,7 @@ class DivPlatformQSound: public DivDispatch { SharedChannel(255), resVol(4095), sample(-1), + wave(-1), panning(0x10), echo(0), useWave(false), From f992346772b9db6e10d3e5a88af7962bd1cdddbb Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Dec 2022 18:51:23 +0900 Subject: [PATCH 64/74] Addressing comments --- extern/Nuked-OPN2 | 1 + src/engine/dispatch.h | 24 ++++++++++++------------ src/engine/playback.cpp | 24 ++++++++++++------------ src/engine/song.h | 3 +-- 4 files changed, 26 insertions(+), 26 deletions(-) create mode 160000 extern/Nuked-OPN2 diff --git a/extern/Nuked-OPN2 b/extern/Nuked-OPN2 new file mode 160000 index 000000000..b0e9de0f8 --- /dev/null +++ b/extern/Nuked-OPN2 @@ -0,0 +1 @@ +Subproject commit b0e9de0f816943ad3820ddfefa0fff276d659250 diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 60c2865c1..566d57538 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -185,18 +185,6 @@ enum DivDispatchCmds { DIV_CMD_N163_GLOBAL_WAVE_LOADLEN, DIV_CMD_N163_GLOBAL_WAVE_LOADMODE, - DIV_CMD_ES5506_FILTER_MODE, // (value) - DIV_CMD_ES5506_FILTER_K1, // (value, mask) - DIV_CMD_ES5506_FILTER_K2, // (value, mask) - DIV_CMD_ES5506_FILTER_K1_SLIDE, // (value, negative) - DIV_CMD_ES5506_FILTER_K2_SLIDE, // (value, negative) - DIV_CMD_ES5506_ENVELOPE_COUNT, // (count) - DIV_CMD_ES5506_ENVELOPE_LVRAMP, // (ramp) - DIV_CMD_ES5506_ENVELOPE_RVRAMP, // (ramp) - DIV_CMD_ES5506_ENVELOPE_K1RAMP, // (ramp, slowdown) - DIV_CMD_ES5506_ENVELOPE_K2RAMP, // (ramp, slowdown) - DIV_CMD_ES5506_PAUSE, // (value) - DIV_CMD_SU_SWEEP_PERIOD_LOW, // (which, val) DIV_CMD_SU_SWEEP_PERIOD_HIGH, // (which, val) DIV_CMD_SU_SWEEP_BOUND, // (which, val) @@ -225,6 +213,18 @@ enum DivDispatchCmds { DIV_CMD_MACRO_OFF, // (which) DIV_CMD_MACRO_ON, // (which) + DIV_CMD_ES5506_FILTER_MODE, // (value) + DIV_CMD_ES5506_FILTER_K1, // (value, mask) + DIV_CMD_ES5506_FILTER_K2, // (value, mask) + DIV_CMD_ES5506_FILTER_K1_SLIDE, // (value, negative) + DIV_CMD_ES5506_FILTER_K2_SLIDE, // (value, negative) + DIV_CMD_ES5506_ENVELOPE_COUNT, // (count) + DIV_CMD_ES5506_ENVELOPE_LVRAMP, // (ramp) + DIV_CMD_ES5506_ENVELOPE_RVRAMP, // (ramp) + DIV_CMD_ES5506_ENVELOPE_K1RAMP, // (ramp, slowdown) + DIV_CMD_ES5506_ENVELOPE_K2RAMP, // (ramp, slowdown) + DIV_CMD_ES5506_PAUSE, // (value) + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 77cd5b34d..66d944477 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -185,18 +185,6 @@ const char* cmdName[]={ "N163_GLOBAL_WAVE_LOADLEN", "N163_GLOBAL_WAVE_LOADMODE", - "ES5506_FILTER_MODE", - "ES5506_FILTER_K1", - "ES5506_FILTER_K2", - "ES5506_FILTER_K1_SLIDE", - "ES5506_FILTER_K2_SLIDE", - "ES5506_ENVELOPE_COUNT", - "ES5506_ENVELOPE_LVRAMP", - "ES5506_ENVELOPE_RVRAMP", - "ES5506_ENVELOPE_K1RAMP", - "ES5506_ENVELOPE_K2RAMP", - "ES5506_PAUSE", - "SU_SWEEP_PERIOD_LOW", "SU_SWEEP_PERIOD_HIGH", "SU_SWEEP_BOUND", @@ -225,6 +213,18 @@ const char* cmdName[]={ "MACRO_OFF", "MACRO_ON", + "ES5506_FILTER_MODE", + "ES5506_FILTER_K1", + "ES5506_FILTER_K2", + "ES5506_FILTER_K1_SLIDE", + "ES5506_FILTER_K2_SLIDE", + "ES5506_ENVELOPE_COUNT", + "ES5506_ENVELOPE_LVRAMP", + "ES5506_ENVELOPE_RVRAMP", + "ES5506_ENVELOPE_K1RAMP", + "ES5506_ENVELOPE_K2RAMP", + "ES5506_PAUSE", + "ALWAYS_SET_VOLUME" }; diff --git a/src/engine/song.h b/src/engine/song.h index d9702215c..d7c287368 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -124,8 +124,7 @@ enum DivSystem { DIV_SYSTEM_YM2610_CSM, DIV_SYSTEM_YM2610B_CSM, DIV_SYSTEM_YM2203_CSM, - DIV_SYSTEM_YM2608_CSM, - DIV_SYSTEM_MAX // boundary for max system number + DIV_SYSTEM_YM2608_CSM }; struct DivSubSong { From 0b948086d62fb3c91373d364800f2152fa42e442 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Dec 2022 19:05:16 +0900 Subject: [PATCH 65/74] Remove accidentally added thing --- extern/Nuked-OPN2 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 extern/Nuked-OPN2 diff --git a/extern/Nuked-OPN2 b/extern/Nuked-OPN2 deleted file mode 160000 index b0e9de0f8..000000000 --- a/extern/Nuked-OPN2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0e9de0f816943ad3820ddfefa0fff276d659250 From 880ea5632da7604e4436401160d6a81ccead8d55 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 12 Jan 2023 23:32:05 +0900 Subject: [PATCH 66/74] Fix presets --- src/gui/presets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5c5c2b7de..e114cfc14 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -2014,7 +2014,7 @@ void FurnaceGUI::initSystemPresets() { ); ENTRY( "Sammy/Seta/Visco SSV", { - CH(DIV_SYSTEM_ES5506, 64, 0, "channels=31") + CH(DIV_SYSTEM_ES5506, 1.0f, 0, "channels=31") } ); ENTRY( @@ -2431,7 +2431,7 @@ void FurnaceGUI::initSystemPresets() { ); ENTRY( "Ensoniq ES5506 (OTTO)", { - CH(DIV_SYSTEM_ES5506, 64, 0, "channels=31") + CH(DIV_SYSTEM_ES5506, 1.0f, 0, "channels=31") } ); CATEGORY_END; From a50465496c8b834508c2305ff001ed1a24280045 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 14 Jan 2023 11:51:10 +0900 Subject: [PATCH 67/74] Addressing commits --- src/engine/instrument.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index ee355a6cb..23c353971 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -19,8 +19,6 @@ #ifndef _INSTRUMENT_H #define _INSTRUMENT_H -#include -#include "sample.h" #include "safeWriter.h" #include "dataErrors.h" #include "../ta-utils.h" @@ -379,7 +377,6 @@ struct DivInstrumentAmiga { freq(f), map(m) {} }; - short initSample; bool useNoteMap; bool useSample; From 16da587dec3f2f787f5093994328366cb23b6cf3 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 16 Jan 2023 10:08:10 +0900 Subject: [PATCH 68/74] Possibly fix reversed loop with reversed playback --- src/engine/platform/es5506.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index d3005a268..58997aa30 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -214,7 +214,7 @@ void DivPlatformES5506::e_pin(bool state) { if (!queuedRead.empty()) { unsigned char ch=queuedRead.front()&0x1f; if (chan[ch].isReverseLoop) { // Reversed loop - pageWriteMask(0x00|ch,0x5f,0x00,(0x0040)|0x08,0x78); + pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.direction?0x0000:0x0040)|0x08,0x78); chan[ch].isReverseLoop=false; } queuedRead.pop(); From 95773034517ce44490440ca51bd6f502fd7647b8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 24 Jan 2023 08:16:56 +0900 Subject: [PATCH 69/74] Update copyright years --- src/engine/platform/es5506.cpp | 2 +- src/engine/platform/es5506.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 58997aa30..3674ab17f 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -1,6 +1,6 @@ /** * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2022 tildearrow and contributors + * Copyright (C) 2021-2023 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 diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index dd1ef0176..30405497c 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -1,6 +1,6 @@ /** * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2022 tildearrow and contributors + * Copyright (C) 2021-2023 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 From f8b9901e4b384b6945b7c69dc0666bd34633b747 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 5 Feb 2023 10:04:31 +0900 Subject: [PATCH 70/74] Fix command order --- src/engine/dispatch.h | 10 +++++----- src/engine/playback.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index e3d6df9d4..6cb1b4e99 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -212,6 +212,11 @@ enum DivDispatchCmds { DIV_CMD_MACRO_OFF, // (which) DIV_CMD_MACRO_ON, // (which) + DIV_CMD_SURROUND_PANNING, // (out, val) + + DIV_CMD_FM_AM2_DEPTH, // (depth) + DIV_CMD_FM_PM2_DEPTH, // (depth) + DIV_CMD_ES5506_FILTER_MODE, // (value) DIV_CMD_ES5506_FILTER_K1, // (value, mask) DIV_CMD_ES5506_FILTER_K2, // (value, mask) @@ -224,11 +229,6 @@ enum DivDispatchCmds { DIV_CMD_ES5506_ENVELOPE_K2RAMP, // (ramp, slowdown) DIV_CMD_ES5506_PAUSE, // (value) - DIV_CMD_SURROUND_PANNING, // (out, val) - - DIV_CMD_FM_AM2_DEPTH, // (depth) - DIV_CMD_FM_PM2_DEPTH, // (depth) - DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ac1534879..954c727b6 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -212,6 +212,11 @@ const char* cmdName[]={ "MACRO_OFF", "MACRO_ON", + "SURROUND_PANNING", + + "FM_AM2_DEPTH", + "FM_PM2_DEPTH", + "ES5506_FILTER_MODE", "ES5506_FILTER_K1", "ES5506_FILTER_K2", @@ -224,11 +229,6 @@ const char* cmdName[]={ "ES5506_ENVELOPE_K2RAMP", "ES5506_PAUSE", - "SURROUND_PANNING", - - "FM_AM2_DEPTH", - "FM_PM2_DEPTH", - "ALWAYS_SET_VOLUME" }; From 2c5dc0875acc252bf470cec7a39c30ff15759110 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Feb 2023 09:16:28 +0900 Subject: [PATCH 71/74] Address comments --- src/engine/chipUtils.h | 2 +- src/engine/platform/es5506.h | 11 ----------- src/engine/platform/ym2610.cpp | 8 ++++---- src/engine/platform/ym2610b.cpp | 8 ++++---- src/engine/sample.h | 3 +-- src/gui/guiConst.cpp | 2 +- src/gui/insEdit.cpp | 24 +++--------------------- 7 files changed, 14 insertions(+), 44 deletions(-) diff --git a/src/engine/chipUtils.h b/src/engine/chipUtils.h index 90c52953c..4ddc0738d 100644 --- a/src/engine/chipUtils.h +++ b/src/engine/chipUtils.h @@ -55,7 +55,7 @@ template struct SharedChannel { freqChanged=true; } } - virtual void macroInit(DivInstrument* which) { + void macroInit(DivInstrument* which) { std.init(which); pitch2=0; arpOff=0; diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 30405497c..d5ac2b9ba 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -185,17 +185,6 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { signed int oscOut; DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; - virtual void macroInit(DivInstrument* which) override { - SharedChannel::macroInit(which); - if (std.ex1.mode==2) { - k1Offs=0; - } - if (std.ex1.mode==2) { - k2Offs=0; - } - k1Prev=0xffff; - k2Prev=0xffff; - } Channel(): SharedChannel(0xff), pcm(PCM()), diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 87ce2b704..94da94447 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -820,7 +820,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -851,7 +851,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -891,7 +891,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -922,7 +922,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index de169984e..79792df01 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -887,7 +887,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -918,7 +918,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -958,7 +958,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); @@ -989,7 +989,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { 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+0xff)&~0xff)-1; + 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)); diff --git a/src/engine/sample.h b/src/engine/sample.h index fa955d01e..35eda8c5e 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -53,8 +53,7 @@ enum DivResampleFilters { DIV_RESAMPLE_CUBIC, DIV_RESAMPLE_BLEP, DIV_RESAMPLE_SINC, - DIV_RESAMPLE_BEST, - DIV_RESAMPLE_MAX // for identify boundary + DIV_RESAMPLE_BEST }; struct DivSampleHistory { diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 4f0a6b916..0735df06c 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -158,7 +158,7 @@ const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={ "16-bit PCM" }; -const char* resampleStrats[DIV_RESAMPLE_MAX]={ +const char* resampleStrats[]={ "none", "linear", "cubic spline", diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9fb803bea..fb19b4ba9 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4384,7 +4384,7 @@ void FurnaceGUI::drawInsEdit() { sName=e->song.sample[sampleMap.map]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { + if (ImGui::BeginCombo("##SM",sName.c_str())) { String id; if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER sampleMap.map=-1; @@ -4400,11 +4400,10 @@ void FurnaceGUI::drawInsEdit() { } /*ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt(fmt::sprintf("##SampleMap_Freq_%d",i).c_str(),&sampleMap.freq,50,500)) { PARAMETER + if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER if (sampleMap.freq<0) sampleMap.freq=0; if (sampleMap.freq>262144) sampleMap.freq=262144; - } - */ + }*/ ImGui::PopID(); } ImGui::EndTable(); @@ -5146,23 +5145,6 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SAA1099) waveMax=2; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; - if ((ins->type==DIV_INS_AMIGA && !ins->amiga.useWave) || ins->type==DIV_INS_ES5506) { - if (!ins->amiga.useWave) { - waveLabel="Sample index"; - waveMax=ins->amiga.useNoteMap?120:MAX(0,(int)(e->song.sampleLen)-1); - } else { - waveMax=MAX(0,(int)(e->song.waveLen)-1); - } - } else if (ins->type==DIV_INS_GB || - (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || - ins->type==DIV_INS_X1_010 || - ins->type==DIV_INS_N163 || - ins->type==DIV_INS_FDS || - ins->type==DIV_INS_SWAN || - ins->type==DIV_INS_PCE || - ins->type==DIV_INS_SCC) { - waveMax=MAX(0,(int)(e->song.waveLen)-1); - } if (ins->type==DIV_INS_MULTIPCM) waveMax=0; if (ins->type==DIV_INS_ADPCMA) waveMax=0; if (ins->type==DIV_INS_ADPCMB) waveMax=0; From 8beb46d8f61763e031912b12145e5f53399bcb62 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Feb 2023 09:40:12 +0900 Subject: [PATCH 72/74] Fix per-channel OSC --- src/engine/platform/es5506.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 3674ab17f..2eb07d19f 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -148,13 +148,6 @@ void DivPlatformES5506::e_pin(bool state) { const signed int lOut=es5506.voice_lout(prevChanCycle); const signed int rOut=es5506.voice_rout(prevChanCycle); chan[prevChanCycle].oscOut=CLAMP((lOut+rOut)>>5,-32768,32767); - if (es5506.voice_end()) { - if (prevChanCycle<31) { - for (int c=31; c>prevChanCycle; c--) { - chan[c].oscOut=0; - } - } - } } } if (es5506.e_rising_edge()) { // host interface From a15f1755d07830757d56bb86e0b253c0ccf651d8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Feb 2023 12:39:42 +0900 Subject: [PATCH 73/74] Fix per-channel OSC (again) --- src/engine/platform/es5506.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 2eb07d19f..ead11a2ed 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -114,6 +114,9 @@ const char** DivPlatformES5506::getRegisterSheet() { void DivPlatformES5506::acquire(short** buf, size_t len) { for (size_t h=0; hchanMax; i--) { + oscBuf[i]->data[oscBuf[i]->needle++]=0; + } // convert 32 bit access to 8 bit host interface while (!hostIntf32.empty()) { QueuedHostIntf w=hostIntf32.front(); @@ -136,7 +139,7 @@ void DivPlatformES5506::acquire(short** buf, size_t len) { buf[(o<<1)|0][h]=es5506.lout(o); buf[(o<<1)|1][h]=es5506.rout(o); } - for (int i=0; i<32; i++) { + for (int i=chanMax; i>=0; i--) { oscBuf[i]->data[oscBuf[i]->needle++]=(short)(chan[i].oscOut&0xffff); } } From 0029e7fe85217ef406c3c0ee454d563b5396f6be Mon Sep 17 00:00:00 2001 From: cam900 Date: Mon, 6 Feb 2023 12:40:33 +0900 Subject: [PATCH 74/74] typecasting --- src/engine/platform/es5506.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index ead11a2ed..3b775eb0b 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -114,7 +114,7 @@ const char** DivPlatformES5506::getRegisterSheet() { void DivPlatformES5506::acquire(short** buf, size_t len) { for (size_t h=0; hchanMax; i--) { + for (int i=31; i>(int)chanMax; i--) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } // convert 32 bit access to 8 bit host interface