diff --git a/CMakeLists.txt b/CMakeLists.txt index d55fee0df..a74d3817d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -791,7 +791,6 @@ src/engine/platform/k007232.cpp src/engine/platform/ga20.cpp src/engine/platform/sm8521.cpp src/engine/platform/supervision.cpp -src/engine/platform/scvwave.cpp src/engine/platform/scvtone.cpp src/engine/platform/pv1000.cpp src/engine/platform/k053260.cpp diff --git a/papers/format.md b/papers/format.md index 2ab3bb084..048acb245 100644 --- a/papers/format.md +++ b/papers/format.md @@ -259,8 +259,7 @@ size | description | - 0xe1: PS1 - 24 channels (UNAVAILABLE) | - 0xe2: C64 (6581) with PCM - 4 channels | - 0xe3: Watara Supervision - 4 channels - | - 0xe4: µPD1771C-017 (wave mode) - 1 channel - | - 0xe5: µPD1771C-017 (tone mode) - 4 channels + | - 0xe5: µPD1771C-017 - 4 channels | - 0xf0: SID2 - 3 channels | - 0xf1: 5E01 - 5 channels | - 0xf5: SID3 - 7 channels diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index e8d79b1d3..dda41ea65 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -77,7 +77,6 @@ #include "platform/k007232.h" #include "platform/ga20.h" #include "platform/supervision.h" -#include "platform/scvwave.h" #include "platform/scvtone.h" #include "platform/sm8521.h" #include "platform/pv1000.h" @@ -707,10 +706,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do dispatch=new DivPlatformSupervision; break; case DIV_SYSTEM_UPD1771C: - dispatch=new DivPlatformSCVWave; - break; - case DIV_SYSTEM_UPD1771C_TONE: - dispatch=new DivPlatformSCVTone; + dispatch=new DivPlatformSCV; break; case DIV_SYSTEM_SM8521: dispatch=new DivPlatformSM8521; diff --git a/src/engine/platform/scvtone.cpp b/src/engine/platform/scvtone.cpp index 96ba326d5..686137412 100644 --- a/src/engine/platform/scvtone.cpp +++ b/src/engine/platform/scvtone.cpp @@ -26,17 +26,15 @@ //#define rWrite(a,v) pendingWrites[a]=v; #define rWrite(a,v) if (!skipRegisterWrites) {packet[a]=v; writePacket=true; if (dumpWrites) {addWrite(a,v);} } -#define CHIP_DIVIDER 512 - const char* regCheatSheetUPD1771cTone[]={ NULL }; -const char** DivPlatformSCVTone::getRegisterSheet() { +const char** DivPlatformSCV::getRegisterSheet() { return regCheatSheetUPD1771cTone; } -void DivPlatformSCVTone::acquire(short** buf, size_t len) { +void DivPlatformSCV::acquire(short** buf, size_t len) { for (int i=0; i<4; i++) { oscBuf[i]->begin(len); } @@ -61,8 +59,9 @@ void DivPlatformSCVTone::acquire(short** buf, size_t len) { } } -void DivPlatformSCVTone::tick(bool sysTick) { +void DivPlatformSCV::tick(bool sysTick) { for (int i=0; i<4; i++) { + int CHIP_DIVIDER=(i<3)?512:64; chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31); @@ -72,7 +71,7 @@ void DivPlatformSCVTone::tick(bool sysTick) { } else if (chan[i].std.arp.had) { if (!chan[i].inPorta) { int f=parent->calcArp(chan[i].note,chan[i].std.arp.val); - if (i==3) { + if (i==3 && !waveMode) { chan[i].baseFreq=f; } else { chan[i].baseFreq=NOTE_PERIODIC(f); @@ -84,7 +83,7 @@ void DivPlatformSCVTone::tick(bool sysTick) { chan[i].wave=chan[i].std.wave.val&7; } if (chan[i].std.duty.had) { - chan[i].duty=chan[i].std.duty.val&1; + waveMode=chan[i].std.duty.val&1; } if (chan[i].std.ex1.had) { chan[i].pos=chan[i].std.ex1.val&31; @@ -99,40 +98,70 @@ void DivPlatformSCVTone::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - if (i==3) { - chan[i].freq=(chan[i].baseFreq+chan[i].pitch+chan[i].pitch2+143); - if (!parent->song.oldArpStrategy) { - if (chan[i].fixedArp) { - chan[i].freq=(chan[i].baseNoteOverride)+chan[i].pitch+chan[i].pitch2; - } else { - chan[i].freq+=chan[i].arpOff; + if (waveMode) { + if (i==3) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + } + if (chan[i].keyOn) kon[i]=1; + if (chan[i].keyOff) kon[i]=0; + if (chan[i].keyOn) chan[i].keyOn=false; + if (chan[i].keyOff) chan[i].keyOff=false; + chan[i].freqChanged=false; + } else { + if (i==3) { + chan[i].freq=(chan[i].baseFreq+chan[i].pitch+chan[i].pitch2+143); + if (!parent->song.oldArpStrategy) { + if (chan[i].fixedArp) { + chan[i].freq=(chan[i].baseNoteOverride)+chan[i].pitch+chan[i].pitch2; + } else { + chan[i].freq+=chan[i].arpOff; + } } + } else { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + } + if (i==3) { + if (chan[i].freq<0) chan[i].freq=0; + } else { + if (chan[i].freq<1) chan[i].freq=1; + } + if (chan[i].freq>255) chan[i].freq=255; + if (chan[i].keyOn) chan[i].keyOn=false; + if (chan[i].keyOff) chan[i].keyOff=false; + chan[i].freqChanged=false; + } + } + + if (waveMode) { + if (kon[i]) { + if (i==3) { + rWrite(0,2); + rWrite(1,(chan[i].wave<<5)|chan[i].pos); + // TODO: improve + float p = ((float)chan[i].freq)/((float)(31-chan[i].pos))*31.0; + rWrite(2,MIN(MAX((int)p,0),255)); + rWrite(3,chan[i].outVol); } } else { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + if (i == 0) { + rWrite(0,0); + } } - if (i==3) { - if (chan[i].freq<0) chan[i].freq=0; - } else { - if (chan[i].freq<1) chan[i].freq=1; - } - if (chan[i].freq>255) chan[i].freq=255; - if (chan[i].keyOn) chan[i].keyOn=false; - if (chan[i].keyOff) chan[i].keyOff=false; - chan[i].freqChanged=false; } } - rWrite(0,1); - rWrite(1,chan[3].wave<<5); - rWrite(2,(0xff-chan[3].freq)); - rWrite(3,(chan[3].active && !isMuted[3])?(chan[3].outVol&0x1f):0); - rWrite(4,chan[0].freq-1); - rWrite(5,chan[1].freq-1); - rWrite(6,chan[2].freq-1); - rWrite(7,(chan[0].active && !isMuted[0])?chan[0].outVol:0); - rWrite(8,(chan[1].active && !isMuted[1])?chan[1].outVol:0); - rWrite(9,(chan[2].active && !isMuted[2])?chan[2].outVol:0); + if (!waveMode) { + rWrite(0,1); + rWrite(1,chan[3].wave<<5); + rWrite(2,(0xff-chan[3].freq)); + rWrite(3,(chan[3].active && !isMuted[3])?(chan[3].outVol&0x1f):0); + rWrite(4,chan[0].freq-1); + rWrite(5,chan[1].freq-1); + rWrite(6,chan[2].freq-1); + rWrite(7,(chan[0].active && !isMuted[0])?chan[0].outVol:0); + rWrite(8,(chan[1].active && !isMuted[1])?chan[1].outVol:0); + rWrite(9,(chan[2].active && !isMuted[2])?chan[2].outVol:0); + } // if need be, write packet if (writePacket) { @@ -150,12 +179,13 @@ void DivPlatformSCVTone::tick(bool sysTick) { } } -int DivPlatformSCVTone::dispatch(DivCommand c) { +int DivPlatformSCV::dispatch(DivCommand c) { + int CHIP_DIVIDER=(c.chan<3)?512:64; switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C); if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=c.chan==3?(c.value):NOTE_PERIODIC(c.value); + chan[c.chan].baseFreq=(c.chan==3 && !waveMode)?(c.value):NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } @@ -170,7 +200,6 @@ int DivPlatformSCVTone::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); chan[c.chan].active=false; chan[c.chan].keyOff=true; chan[c.chan].macroInit(NULL); @@ -207,7 +236,7 @@ int DivPlatformSCVTone::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=(c.chan==3)?c.value2:(NOTE_PERIODIC(c.value2)); + int destFreq=(c.chan==3 && !waveMode)?c.value2:(NOTE_PERIODIC(c.value2)); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -238,7 +267,7 @@ int DivPlatformSCVTone::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { int newNote=c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)); - chan[c.chan].baseFreq=(c.chan==3)?newNote:(NOTE_PERIODIC(newNote)); + chan[c.chan].baseFreq=(c.chan==3 && !waveMode)?newNote:(NOTE_PERIODIC(newNote)); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; @@ -248,7 +277,7 @@ int DivPlatformSCVTone::dispatch(DivCommand c) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C)); } if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) { - if (c.chan==3) { + if (c.chan==3 && !waveMode) { chan[c.chan].baseFreq=chan[c.chan].note; } else { chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); @@ -274,43 +303,42 @@ int DivPlatformSCVTone::dispatch(DivCommand c) { return 1; } -void DivPlatformSCVTone::muteChannel(int ch, bool mute) { +void DivPlatformSCV::muteChannel(int ch, bool mute) { isMuted[ch]=mute; } -void DivPlatformSCVTone::forceIns() { +void DivPlatformSCV::forceIns() { for (int i=0; i<4; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; - //chwrite(i,0x05,isMuted[i]?0:chan[i].pan); } } -void* DivPlatformSCVTone::getChanState(int ch) { +void* DivPlatformSCV::getChanState(int ch) { return &chan[ch]; } -DivMacroInt* DivPlatformSCVTone::getChanMacroInt(int ch) { +DivMacroInt* DivPlatformSCV::getChanMacroInt(int ch) { return &chan[ch].std; } -DivDispatchOscBuffer* DivPlatformSCVTone::getOscBuffer(int ch) { +DivDispatchOscBuffer* DivPlatformSCV::getOscBuffer(int ch) { return oscBuf[ch]; } -unsigned char* DivPlatformSCVTone::getRegisterPool() { +unsigned char* DivPlatformSCV::getRegisterPool() { return regPool; } -int DivPlatformSCVTone::getRegisterPoolSize() { +int DivPlatformSCV::getRegisterPoolSize() { return 16; } -void DivPlatformSCVTone::reset() { +void DivPlatformSCV::reset() { writes.clear(); memset(regPool,0,16); for (int i=0; i<4; i++) { - chan[i]=DivPlatformSCVTone::Channel(); + chan[i]=DivPlatformSCV::Channel(); chan[i].std.setEngine(parent); } if (dumpWrites) { @@ -319,25 +347,28 @@ void DivPlatformSCVTone::reset() { scv.device_reset(); memset(tempL,0,32*sizeof(int)); memset(tempR,0,32*sizeof(int)); + memset(kon,0,4); + memset(initWrite,1,4); memset(packet,0,16); writePacket=false; + waveMode=false; } -int DivPlatformSCVTone::getOutputCount() { +int DivPlatformSCV::getOutputCount() { return 1; } -bool DivPlatformSCVTone::keyOffAffectsArp(int ch) { +bool DivPlatformSCV::keyOffAffectsArp(int ch) { return true; } -void DivPlatformSCVTone::notifyInsDeletion(void* ins) { +void DivPlatformSCV::notifyInsDeletion(void* ins) { for (int i=0; i<4; i++) { chan[i].std.notifyInsDeletion((DivInstrument*)ins); } } -void DivPlatformSCVTone::setFlags(const DivConfig& flags) { +void DivPlatformSCV::setFlags(const DivConfig& flags) { chipClock=6000000; CHECK_CUSTOM_CLOCK; rate=chipClock/4; @@ -347,15 +378,15 @@ void DivPlatformSCVTone::setFlags(const DivConfig& flags) { //upd1771c_sound_set_clock(&scv,(unsigned int)chipClock,8); } -void DivPlatformSCVTone::poke(unsigned int addr, unsigned short val) { +void DivPlatformSCV::poke(unsigned int addr, unsigned short val) { rWrite(addr,val); } -void DivPlatformSCVTone::poke(std::vector& wlist) { +void DivPlatformSCV::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } -int DivPlatformSCVTone::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { +int DivPlatformSCV::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { parent=p; dumpWrites=false; skipRegisterWrites=false; @@ -368,11 +399,11 @@ int DivPlatformSCVTone::init(DivEngine* p, int channels, int sugRate, const DivC return 1; } -void DivPlatformSCVTone::quit() { +void DivPlatformSCV::quit() { for (int i=0; i<4; i++) { delete oscBuf[i]; } } -DivPlatformSCVTone::~DivPlatformSCVTone() { +DivPlatformSCV::~DivPlatformSCV() { } diff --git a/src/engine/platform/scvtone.h b/src/engine/platform/scvtone.h index 2ffd8bda9..52e31cce4 100644 --- a/src/engine/platform/scvtone.h +++ b/src/engine/platform/scvtone.h @@ -24,7 +24,7 @@ #include "../../fixedQueue.h" #include "sound/upd1771.h" -class DivPlatformSCVTone: public DivDispatch { +class DivPlatformSCV: public DivDispatch { struct Channel: public SharedChannel { unsigned int wave; int pos, duty; @@ -50,11 +50,13 @@ class DivPlatformSCVTone: public DivDispatch { int tempR[32]; int coreQuality; unsigned char regPool[16]; + unsigned char kon[4]; + unsigned char initWrite[4]; upd1771c_device scv; unsigned char packet[16]; - bool writePacket; + bool writePacket, waveMode; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); @@ -79,7 +81,7 @@ class DivPlatformSCVTone: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); - ~DivPlatformSCVTone(); + ~DivPlatformSCV(); }; #endif diff --git a/src/engine/platform/scvwave.cpp b/src/engine/platform/scvwave.cpp deleted file mode 100644 index 5525a5dc6..000000000 --- a/src/engine/platform/scvwave.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2025 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "scvwave.h" -#include "../engine.h" -#include "../../ta-log.h" -#include "furIcons.h" -#include - -//#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) if (!skipRegisterWrites) {packet[a]=v; writePacket=true; if (dumpWrites) {addWrite(a,v);} } - -#define CHIP_DIVIDER 64 - -const char* regCheatSheetUPD1771c[]={ - NULL -}; - -const char** DivPlatformSCVWave::getRegisterSheet() { - return regCheatSheetUPD1771c; -} - -void DivPlatformSCVWave::acquire(short** buf, size_t len) { - oscBuf[0]->begin(len); - - for (size_t h=0; hputSample(h,buf[0][h]); - } - - oscBuf[0]->end(len); -} - -void DivPlatformSCVWave::tick(bool sysTick) { - for (int i=0; i<1; i++) { - chan[i].std.next(); - if (chan[i].std.vol.had) { - chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31); - } - if (NEW_ARP_STRAT) { - chan[i].handleArp(); - } else if (chan[i].std.arp.had) { - if (!chan[i].inPorta) { - int f=parent->calcArp(chan[i].note,chan[i].std.arp.val); - chan[i].baseFreq=NOTE_PERIODIC(f); - } - chan[i].freqChanged=true; - } - if (chan[i].std.wave.had) { - chan[i].wave=chan[i].std.wave.val&7; - } - if (chan[i].std.duty.had) { - chan[i].duty=chan[i].std.duty.val&1; - } - if (chan[i].std.ex1.had) { - chan[i].pos=chan[i].std.ex1.val&31; - } - if (chan[i].std.pitch.had) { - if (chan[i].std.pitch.mode) { - chan[i].pitch2+=chan[i].std.pitch.val; - CLAMP_VAR(chan[i].pitch2,-32768,32767); - } else { - chan[i].pitch2=chan[i].std.pitch.val; - } - chan[i].freqChanged=true; - } - if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE); - if (i==0) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); - } - if (chan[i].keyOn) kon[i]=1; - if (chan[i].keyOff) kon[i]=0; - if (chan[i].keyOn) chan[i].keyOn=false; - if (chan[i].keyOff) chan[i].keyOff=false; - chan[i].freqChanged=false; - } - - if (kon[i]) { - if (i==0) { - if (chan[i].duty == 0) { - rWrite(0,2); - rWrite(1,(chan[i].wave<<5)|chan[i].pos); - // TODO: improve - float p = ((float)chan[i].freq)/((float)(31-chan[i].pos))*31.0; - rWrite(2,MIN(MAX((int)p,0),255)); - rWrite(3,chan[i].outVol); - } else if (chan[i].duty == 1) { - rWrite(0,1); - rWrite(1,(chan[i].wave<<5)); - rWrite(2,MIN(MAX(chan[i].freq>>7,0),255)); - rWrite(3,chan[i].outVol); - } else { - rWrite(0,0); - } - } - } else { - if (i == 0) { - rWrite(0,0); - } - } - - } - - // if need be, write packet - if (writePacket) { - writePacket=false; - int len=1; - if (packet[0]==2) { - len=4; - } else if (packet[0]==1) { - len=10; - } - - for (int i=0; igetIns(chan[c.chan].ins,DIV_INS_UPD1771C); - if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=c.chan==3?c.value:NOTE_PERIODIC(c.value); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - } - chan[c.chan].active=true; - chan[c.chan].keyOn=true; - //chwrite(c.chan,0x04,0x80|chan[c.chan].vol); - chan[c.chan].macroInit(ins); - if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { - chan[c.chan].outVol=chan[c.chan].vol; - } - chan[c.chan].insChanged=false; - break; - } - case DIV_CMD_NOTE_OFF: - if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); - chan[c.chan].active=false; - chan[c.chan].keyOff=true; - chan[c.chan].macroInit(NULL); - break; - case DIV_CMD_NOTE_OFF_ENV: - case DIV_CMD_ENV_RELEASE: - chan[c.chan].std.release(); - break; - case DIV_CMD_INSTRUMENT: - if (chan[c.chan].ins!=c.value || c.value2==1) { - chan[c.chan].ins=c.value; - chan[c.chan].insChanged=true; - } - break; - case DIV_CMD_VOLUME: - if (chan[c.chan].vol!=c.value) { - chan[c.chan].vol=c.value; - if (!chan[c.chan].std.vol.has) { - chan[c.chan].outVol=c.value; - if (chan[c.chan].active) { - //chwrite(c.chan,0x04,0x80|chan[c.chan].outVol); - } - } - } - break; - case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.vol.has) { - return chan[c.chan].vol; - } - return chan[c.chan].outVol; - break; - case DIV_CMD_PITCH: - chan[c.chan].pitch=c.value; - chan[c.chan].freqChanged=true; - break; - case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_PERIODIC(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_STD_NOISE_MODE: - chan[c.chan].wave=c.value&7; - chan[c.chan].duty=c.value>>4&1; - break; - case DIV_CMD_N163_WAVE_POSITION: - chan[c.chan].pos=c.value; - break; - case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))); - chan[c.chan].freqChanged=true; - chan[c.chan].note=c.value; - break; - case DIV_CMD_PRE_PORTA: - if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_UPD1771C)); - } - if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); - chan[c.chan].inPorta=c.value; - break; - case DIV_CMD_GET_VOLMAX: - return 31; - break; - case DIV_CMD_MACRO_OFF: - chan[c.chan].std.mask(c.value,true); - break; - case DIV_CMD_MACRO_ON: - chan[c.chan].std.mask(c.value,false); - break; - case DIV_CMD_MACRO_RESTART: - chan[c.chan].std.restart(c.value); - break; - default: - break; - } - return 1; -} - -void DivPlatformSCVWave::muteChannel(int ch, bool mute) { - isMuted[ch]=mute; -} - -void DivPlatformSCVWave::forceIns() { - for (int i=0; i<1; i++) { - chan[i].insChanged=true; - chan[i].freqChanged=true; - //chwrite(i,0x05,isMuted[i]?0:chan[i].pan); - } -} - -void* DivPlatformSCVWave::getChanState(int ch) { - return &chan[ch]; -} - -DivMacroInt* DivPlatformSCVWave::getChanMacroInt(int ch) { - return &chan[ch].std; -} - -DivDispatchOscBuffer* DivPlatformSCVWave::getOscBuffer(int ch) { - return oscBuf[ch]; -} - -unsigned char* DivPlatformSCVWave::getRegisterPool() { - return regPool; -} - -int DivPlatformSCVWave::getRegisterPoolSize() { - return 16; -} - -void DivPlatformSCVWave::reset() { - writes.clear(); - memset(regPool,0,16); - for (int i=0; i<1; i++) { - chan[i]=DivPlatformSCVWave::Channel(); - chan[i].std.setEngine(parent); - } - if (dumpWrites) { - addWrite(0xffffffff,0); - } - scv.device_reset(); - memset(tempL,0,32*sizeof(int)); - memset(tempR,0,32*sizeof(int)); - memset(kon,0,1*sizeof(unsigned char)); - memset(initWrite,1,1*sizeof(unsigned char)); - memset(packet,0,16); - writePacket=false; -} - -int DivPlatformSCVWave::getOutputCount() { - return 1; -} - -bool DivPlatformSCVWave::keyOffAffectsArp(int ch) { - return true; -} - -void DivPlatformSCVWave::notifyInsDeletion(void* ins) { - for (int i=0; i<1; i++) { - chan[i].std.notifyInsDeletion((DivInstrument*)ins); - } -} - -void DivPlatformSCVWave::setFlags(const DivConfig& flags) { - chipClock=6000000; - CHECK_CUSTOM_CLOCK; - rate=chipClock/4; - for (int i=0; i<1; i++) { - oscBuf[i]->setRate(rate); - } -} - -void DivPlatformSCVWave::poke(unsigned int addr, unsigned short val) { - rWrite(addr,val); -} - -void DivPlatformSCVWave::poke(std::vector& wlist) { - for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); -} - -int DivPlatformSCVWave::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { - parent=p; - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<1; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - setFlags(flags); - reset(); - return 1; -} - -void DivPlatformSCVWave::quit() { - for (int i=0; i<1; i++) { - delete oscBuf[i]; - } -} - -DivPlatformSCVWave::~DivPlatformSCVWave() { -} diff --git a/src/engine/platform/scvwave.h b/src/engine/platform/scvwave.h deleted file mode 100644 index 69408da2a..000000000 --- a/src/engine/platform/scvwave.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2025 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _SCV_WAVE_H -#define _SCV_WAVE_H - -#include "../dispatch.h" -#include "../../fixedQueue.h" -#include "sound/upd1771.h" - -class DivPlatformSCVWave: public DivDispatch { - struct Channel: public SharedChannel { - unsigned int wave; - int pos, duty; - Channel(): - SharedChannel(15), - wave(0), - pos(0), - duty(0) {} - }; - Channel chan[1]; - DivDispatchOscBuffer* oscBuf[1]; - bool isMuted[4]; - struct QueuedWrite { - unsigned char addr; - unsigned char val; - QueuedWrite(): addr(0), val(9) {} - QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} - }; - FixedQueue writes; - - int curChan; - int tempL[32]; - int tempR[32]; - int coreQuality; - unsigned char regPool[16]; - unsigned char kon[1]; - unsigned char initWrite[1]; - upd1771c_device scv; - - unsigned char packet[16]; - - bool writePacket; - - friend void putDispatchChip(void*,int); - friend void putDispatchChan(void*,int,int); - public: - void acquire(short** buf, size_t len); - int dispatch(DivCommand c); - void* getChanState(int chan); - DivMacroInt* getChanMacroInt(int ch); - DivDispatchOscBuffer* getOscBuffer(int chan); - unsigned char* getRegisterPool(); - int getRegisterPoolSize(); - void reset(); - void forceIns(); - void tick(bool sysTick=true); - void muteChannel(int ch, bool mute); - int getOutputCount(); - bool keyOffAffectsArp(int ch); - void setFlags(const DivConfig& flags); - void notifyInsDeletion(void* ins); - void poke(unsigned int addr, unsigned short val); - void poke(std::vector& wlist); - const char** getRegisterSheet(); - int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); - void quit(); - ~DivPlatformSCVWave(); -}; - -#endif diff --git a/src/engine/platform/sound/upd1771.cpp b/src/engine/platform/sound/upd1771.cpp index 7dcc878db..af0e331f8 100644 --- a/src/engine/platform/sound/upd1771.cpp +++ b/src/engine/platform/sound/upd1771.cpp @@ -597,8 +597,8 @@ void upd1771c_device::sound_stream_update(short* output, int len) // TODO: improve this for (int sampindex = 0; sampindex < len; sampindex++) { - //"wavetable-LFSR" component - int wlfsr_val = ((int)noise_tbl[m_nw_timbre][m_nw_tpos]) - 127;//data too wide + // "wavetable-LFSR" component + int wlfsr_val = ((int)noise_tbl[m_nw_timbre][m_nw_tpos]) - 127; // data too wide m_nw_ppos++; if (m_nw_ppos >= m_nw_period) @@ -609,7 +609,7 @@ void upd1771c_device::sound_stream_update(short* output, int len) m_nw_ppos = 0; } - //mix in each of the noise's 3 pulse components + // mix in each of the noise's 3 pulse components signed char res[3]; for (int i = 0; i < 3; ++i) { @@ -621,16 +621,16 @@ void upd1771c_device::sound_stream_update(short* output, int len) m_n_value[i] = !m_n_value[i]; } } - //not quite, but close. + // not quite! chout[0]=res[0] * m_n_volume[0] * 4; chout[1]=res[1] * m_n_volume[1] * 4; chout[2]=res[2] * m_n_volume[2] * 4; - chout[3]=wlfsr_val * m_nw_volume; + chout[3]=wlfsr_val * m_nw_volume * 2; output[sampindex]= - ((chout[3]) + // TODO: this is mixed with "mix" instruction rather than add - (chout[0]) + - (chout[1]) + - (chout[2])) * 32 * 2; + ( + ((chout[0] + chout[1] + chout[2]) * 32) + + chout[3] + ) * 2; } diff --git a/src/engine/song.h b/src/engine/song.h index d9cfe319f..e13d8b101 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -146,7 +146,6 @@ enum DivSystem { DIV_SYSTEM_UPD1771C, DIV_SYSTEM_SID3, DIV_SYSTEM_C64_PCM, - DIV_SYSTEM_UPD1771C_TONE, DIV_SYSTEM_MAX }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1f6500b4e..3ba955d63 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -2058,12 +2058,12 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_UPD1771C]=new DivSysDef( - _("NEC μPD1771C-017 (wave mode)"), NULL, 0xe4, 0, 1, false, true, 0, false, 0, 0, 0, - _("a microcontroller which has been used as a sound generator in the Super Cassette Vision. this is the waveform mode."), - {_("Wave/Noise")}, - {"W"}, - {DIV_CH_NOISE}, - {DIV_INS_UPD1771C}, + _("NEC μPD1771C-017"), NULL, 0xe5, 0, 4, false, true, 0, false, 0, 0, 0, + _("a microcontroller which has been used as a sound generator in the Super Cassette Vision."), + {_("Square 1"), _("Square 2"), _("Square 3"), _("Wave/Noise")}, + {"S1", "S2", "S3", "NO"}, + {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, + {DIV_INS_UPD1771C, DIV_INS_UPD1771C, DIV_INS_UPD1771C, DIV_INS_UPD1771C}, {}, { {0x10, {DIV_CMD_STD_NOISE_MODE, _("10xx: Set duty/waveform (bit 0-3: waveform; bit 4: mode)")}}, @@ -2071,17 +2071,6 @@ void DivEngine::registerSystems() { } ); - sysDefs[DIV_SYSTEM_UPD1771C_TONE]=new DivSysDef( - _("NEC μPD1771C-017 (tone mode)"), NULL, 0xe5, 0, 4, false, true, 0, false, 0, 0, 0, - _("a microcontroller which has been used as a sound generator in the Super Cassette Vision. this is the tone mode."), - {_("Square 1"), _("Square 2"), _("Square 3"), _("Noise")}, - {"S1", "S2", "S3", "NO"}, - {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, - {DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_BEEPER, DIV_INS_UPD1771C}, - {}, - {} - ); - sysDefs[DIV_SYSTEM_SM8521]=new DivSysDef( _("Sharp SM8521"), NULL, 0xc8, 0, 3, false, true, 0, false, 0, 32, 16, _("a SoC with wavetable sound hardware."), diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index bbe61c6e5..561bb632f 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -1320,7 +1320,6 @@ const int availableSystems[]={ DIV_SYSTEM_OPL4_DRUMS, DIV_SYSTEM_SUPERVISION, DIV_SYSTEM_UPD1771C, - DIV_SYSTEM_UPD1771C_TONE, DIV_SYSTEM_SID3, 0 // don't remove this last one! }; @@ -1426,7 +1425,6 @@ const int chipsSpecial[]={ DIV_SYSTEM_SID2, DIV_SYSTEM_SUPERVISION, DIV_SYSTEM_UPD1771C, - DIV_SYSTEM_UPD1771C_TONE, DIV_SYSTEM_SID3, 0 // don't remove this last one! }; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 6b3740f84..3f2cc20b7 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1569,15 +1569,10 @@ void FurnaceGUI::initSystemPresets() { } ); ENTRY( - "Epoch Super Cassette Vision (wave mode)", { + "Epoch Super Cassette Vision", { CH(DIV_SYSTEM_UPD1771C, 1.0f, 0, "") } ); - ENTRY( - "Epoch Super Cassette Vision (tone mode)", { - CH(DIV_SYSTEM_UPD1771C_TONE, 1.0f, 0, "") - } - ); CATEGORY_END; CATEGORY_BEGIN(_("Arcade systems"),_("INSERT COIN")); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index d816aea67..0e263a702 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2665,7 +2665,6 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl case DIV_SYSTEM_BIFURCATOR: case DIV_SYSTEM_POWERNOISE: case DIV_SYSTEM_UPD1771C: - case DIV_SYSTEM_UPD1771C_TONE: break; case DIV_SYSTEM_YMU759: case DIV_SYSTEM_ESFM: diff --git a/src/gui/sysMiscInfo.cpp b/src/gui/sysMiscInfo.cpp index 8dbbb6309..2c7ccbe8e 100644 --- a/src/gui/sysMiscInfo.cpp +++ b/src/gui/sysMiscInfo.cpp @@ -282,11 +282,11 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) { break; case DIV_SYSTEM_ESFM: return "ES1xxx"; + break; case DIV_SYSTEM_SUPERVISION: return "Watara Supervision"; break; case DIV_SYSTEM_UPD1771C: - case DIV_SYSTEM_UPD1771C_TONE: return "μPD1771C-017"; break; default: