diff --git a/CMakeLists.txt b/CMakeLists.txt index 67d2db363..8053c4482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -652,6 +652,7 @@ src/engine/platform/sound/sm8521.c src/engine/platform/sound/supervision.c +src/engine/platform/sound/upd1771.cpp src/engine/platform/sound/upd1771c.c src/engine/platform/sound/d65modified.c @@ -790,7 +791,8 @@ src/engine/platform/k007232.cpp src/engine/platform/ga20.cpp src/engine/platform/sm8521.cpp src/engine/platform/supervision.cpp -src/engine/platform/upd1771c.cpp +src/engine/platform/scvwave.cpp +src/engine/platform/scvtone.cpp src/engine/platform/pv1000.cpp src/engine/platform/k053260.cpp src/engine/platform/ted.cpp diff --git a/papers/format.md b/papers/format.md index 67b84fb82..2ab3bb084 100644 --- a/papers/format.md +++ b/papers/format.md @@ -257,9 +257,10 @@ size | description | - 0xdf: YM2612 XGM extended - 13 channels (UNAVAILABLE) | - 0xe0: QSound - 19 channels | - 0xe1: PS1 - 24 channels (UNAVAILABLE) - | - 0xe2: C64 (6581) with PCM - 4 channels (UNAVAILABLE) + | - 0xe2: C64 (6581) with PCM - 4 channels | - 0xe3: Watara Supervision - 4 channels - | - 0xe4: µPD1771C - 1 channel + | - 0xe4: µPD1771C-017 (wave mode) - 1 channel + | - 0xe5: µPD1771C-017 (tone mode) - 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 9b955bf7b..e4e21da69 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -77,7 +77,8 @@ #include "platform/k007232.h" #include "platform/ga20.h" #include "platform/supervision.h" -#include "platform/upd1771c.h" +#include "platform/scvwave.h" +#include "platform/scvtone.h" #include "platform/sm8521.h" #include "platform/pv1000.h" #include "platform/k053260.h" @@ -732,7 +733,10 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do dispatch=new DivPlatformSupervision; break; case DIV_SYSTEM_UPD1771C: - dispatch=new DivPlatformUPD1771c; + dispatch=new DivPlatformSCVWave; + break; + case DIV_SYSTEM_UPD1771C_TONE: + dispatch=new DivPlatformSCVTone; break; case DIV_SYSTEM_SM8521: dispatch=new DivPlatformSM8521; diff --git a/src/engine/platform/upd1771c.cpp b/src/engine/platform/scvtone.cpp similarity index 87% rename from src/engine/platform/upd1771c.cpp rename to src/engine/platform/scvtone.cpp index 1e2a96fd3..14ce16d0e 100644 --- a/src/engine/platform/upd1771c.cpp +++ b/src/engine/platform/scvtone.cpp @@ -17,7 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "upd1771c.h" +#include "scvtone.h" #include "../engine.h" #include "../../ta-log.h" #include "furIcons.h" @@ -28,15 +28,15 @@ #define CHIP_DIVIDER 64 -const char* regCheatSheetUPD1771c[]={ +const char* regCheatSheetUPD1771cTone[]={ NULL }; -const char** DivPlatformUPD1771c::getRegisterSheet() { - return regCheatSheetUPD1771c; +const char** DivPlatformSCVTone::getRegisterSheet() { + return regCheatSheetUPD1771cTone; } -void DivPlatformUPD1771c::acquire(short** buf, size_t len) { +void DivPlatformSCVTone::acquire(short** buf, size_t len) { for (size_t h=0; hgetIns(chan[c.chan].ins,DIV_INS_UPD1771C); @@ -262,11 +262,11 @@ int DivPlatformUPD1771c::dispatch(DivCommand c) { return 1; } -void DivPlatformUPD1771c::muteChannel(int ch, bool mute) { +void DivPlatformSCVTone::muteChannel(int ch, bool mute) { isMuted[ch]=mute; } -void DivPlatformUPD1771c::forceIns() { +void DivPlatformSCVTone::forceIns() { for (int i=0; i<1; i++) { chan[i].insChanged=true; chan[i].freqChanged=true; @@ -274,31 +274,31 @@ void DivPlatformUPD1771c::forceIns() { } } -void* DivPlatformUPD1771c::getChanState(int ch) { +void* DivPlatformSCVTone::getChanState(int ch) { return &chan[ch]; } -DivMacroInt* DivPlatformUPD1771c::getChanMacroInt(int ch) { +DivMacroInt* DivPlatformSCVTone::getChanMacroInt(int ch) { return &chan[ch].std; } -DivDispatchOscBuffer* DivPlatformUPD1771c::getOscBuffer(int ch) { +DivDispatchOscBuffer* DivPlatformSCVTone::getOscBuffer(int ch) { return oscBuf[ch]; } -unsigned char* DivPlatformUPD1771c::getRegisterPool() { +unsigned char* DivPlatformSCVTone::getRegisterPool() { return regPool; } -int DivPlatformUPD1771c::getRegisterPoolSize() { +int DivPlatformSCVTone::getRegisterPoolSize() { return 16; } -void DivPlatformUPD1771c::reset() { +void DivPlatformSCVTone::reset() { writes.clear(); memset(regPool,0,16); for (int i=0; i<1; i++) { - chan[i]=DivPlatformUPD1771c::Channel(); + chan[i]=DivPlatformSCVTone::Channel(); chan[i].std.setEngine(parent); } if (dumpWrites) { @@ -311,21 +311,21 @@ void DivPlatformUPD1771c::reset() { memset(initWrite,1,1*sizeof(unsigned char)); } -int DivPlatformUPD1771c::getOutputCount() { +int DivPlatformSCVTone::getOutputCount() { return 2; } -bool DivPlatformUPD1771c::keyOffAffectsArp(int ch) { +bool DivPlatformSCVTone::keyOffAffectsArp(int ch) { return true; } -void DivPlatformUPD1771c::notifyInsDeletion(void* ins) { +void DivPlatformSCVTone::notifyInsDeletion(void* ins) { for (int i=0; i<1; i++) { chan[i].std.notifyInsDeletion((DivInstrument*)ins); } } -void DivPlatformUPD1771c::setFlags(const DivConfig& flags) { +void DivPlatformSCVTone::setFlags(const DivConfig& flags) { chipClock=6000000; CHECK_CUSTOM_CLOCK; rate=chipClock/32; @@ -335,15 +335,15 @@ void DivPlatformUPD1771c::setFlags(const DivConfig& flags) { upd1771c_sound_set_clock(&scv,(unsigned int)chipClock,8); } -void DivPlatformUPD1771c::poke(unsigned int addr, unsigned short val) { +void DivPlatformSCVTone::poke(unsigned int addr, unsigned short val) { rWrite(addr,val); } -void DivPlatformUPD1771c::poke(std::vector& wlist) { +void DivPlatformSCVTone::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); } -int DivPlatformUPD1771c::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { +int DivPlatformSCVTone::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { parent=p; dumpWrites=false; skipRegisterWrites=false; @@ -356,11 +356,11 @@ int DivPlatformUPD1771c::init(DivEngine* p, int channels, int sugRate, const Div return 1; } -void DivPlatformUPD1771c::quit() { +void DivPlatformSCVTone::quit() { for (int i=0; i<1; i++) { delete oscBuf[i]; } } -DivPlatformUPD1771c::~DivPlatformUPD1771c() { +DivPlatformSCVTone::~DivPlatformSCVTone() { } diff --git a/src/engine/platform/scvtone.h b/src/engine/platform/scvtone.h new file mode 100644 index 000000000..48b3ac194 --- /dev/null +++ b/src/engine/platform/scvtone.h @@ -0,0 +1,84 @@ +/** + * 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_TONE_H +#define _SCV_TONE_H + +#include "../dispatch.h" +#include "../../fixedQueue.h" +#include "sound/upd1771c.h" + +class DivPlatformSCVTone: public DivDispatch { + struct Channel: public SharedChannel { + unsigned int wave; + int pos, duty; + Channel(): + SharedChannel(15), + wave(0), + pos(0), + duty(0) {} + }; + Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; + 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[4]; + unsigned char initWrite[4]; + struct upd1771c_t scv; + + + 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(); + ~DivPlatformSCVTone(); +}; + +#endif diff --git a/src/engine/platform/scvwave.cpp b/src/engine/platform/scvwave.cpp new file mode 100644 index 000000000..c759ed479 --- /dev/null +++ b/src/engine/platform/scvwave.cpp @@ -0,0 +1,383 @@ +/** + * 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) { + for (size_t h=0; hdata[oscBuf[0]->needle++]=s; + buf[0][h]=s; + buf[1][h]=s;*/ + } +} + +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].freqChanged || initWrite[i] || chan[i].keyOn) { + if (chan[i].duty == 0) { + rWrite(0,2); + rWrite(1,(chan[i].wave<<5)|chan[i].pos); + 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); + } + initWrite[i]=0; + } + if (chan[i].keyOff) { + rWrite(0,0); + } + 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)(32-chan[i].pos))*32.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]->rate=rate; + } + //upd1771c_sound_set_clock(&scv,(unsigned int)chipClock,8); +} + +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/upd1771c.h b/src/engine/platform/scvwave.h similarity index 91% rename from src/engine/platform/upd1771c.h rename to src/engine/platform/scvwave.h index 712110d91..69408da2a 100644 --- a/src/engine/platform/upd1771c.h +++ b/src/engine/platform/scvwave.h @@ -17,14 +17,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _UPD1771C_H -#define _UPD1771C_H +#ifndef _SCV_WAVE_H +#define _SCV_WAVE_H #include "../dispatch.h" #include "../../fixedQueue.h" -#include "sound/upd1771c.h" +#include "sound/upd1771.h" -class DivPlatformUPD1771c: public DivDispatch { +class DivPlatformSCVWave: public DivDispatch { struct Channel: public SharedChannel { unsigned int wave; int pos, duty; @@ -52,8 +52,11 @@ class DivPlatformUPD1771c: public DivDispatch { unsigned char regPool[16]; unsigned char kon[1]; unsigned char initWrite[1]; - struct upd1771c_t scv; + upd1771c_device scv; + unsigned char packet[16]; + + bool writePacket; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); @@ -78,7 +81,7 @@ class DivPlatformUPD1771c: public DivDispatch { const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); - ~DivPlatformUPD1771c(); + ~DivPlatformSCVWave(); }; #endif diff --git a/src/engine/platform/sound/upd1771.cpp b/src/engine/platform/sound/upd1771.cpp new file mode 100644 index 000000000..478a08cd2 --- /dev/null +++ b/src/engine/platform/sound/upd1771.cpp @@ -0,0 +1,508 @@ +// license:BSD-3-Clause +// copyright-holders:David Viens +/********************************************************************** + + NEC uPD1771-017 as used in the Epoch Super Cassette Vision (SCV) + + Made using recording/analysis on a Yeno (PAL Super Cassette Vision) + by plgDavid + + Full markings on my 2 specimens are + "NEC JAPAN 8431K9 D1771C 017" (31st week of 1984, mask rom #017) + + I've since (October 2012) got a Grandstand Firefox F-7 Handheld game + (AKA Epoch GalagaX6/Epoch Astro Thunder 7/Tandy Astro Thunder), + (http://www.handheldmuseum.com/Grandstand/Firefox.htm) + which includes a + "NEC JAPAN 8319K9 D1771C 011" (19th week of 1983, mask rom #011) + Thanks to user 'Blanka' from Dragonslairfans for the nice catch! + (http://www.dragonslairfans.com/smfor/index.php?topic=3061.0) + + Since the chip generates tones using ROM wavetables, + it is perfectly possible to generate other sounds with different rom code and data. + + Most upd17XXX devices are typically 4bit NEC MCUs, however based on information + in "Electronic Speech Synthesis" by Geoff Bristow (ISBN 0-07-007912-9, pages 148-152) + the upd1770/1771 is not one of these 4-bit ones. + + The uPD1770/uPD1771 SSM is a 16-bit-wide rom/ram mcu with 8kb (4kw) of rom code, + 64 bytes of ram (16x16bit words addressable as 16 or 2x8 bits each, the + remaining 32 bytes acting as an 8-level stack), 182 instructions, a complex + noise and tone internal interrupt system, external interrupts, + and two 8-bit ports with multiple modes allowing for chips to operate as master + or slave devices. + SSM stands for "Sound Synthesis Microcomputer". + + People who I *THINK* worked on the uPD1771 and what part I think they worked on: + Toshio Oura - Project Lead(?), VSRSSS/TSRSSS speech synthesis engine (on upd1776C), master/slave i/o controls, author of bristow article and primary author of the IEEE article + Hatsuhide Igarashi - Clock oscillator and pad layout, coauthor on the IEEE article, other IEEE stuff + Tomoaki Isozaki - ? (senior NEC engineer?), coauthor on the IEEE article + Sachiyuki Toufuku - ?, coauthor on the IEEE article + Tojiro Mukawa - IGFETs and the DAC + M. Sakai ? - digital filtering for VSRSSS? (IEEE 4131979, 1169295) + M. Endo ? - digital design system or speech synthesis? (IEEE 4069656, another? person: IEEE 150330, 225838) + H. Aoyama ? - logic design system used to assemble/lay out the chip? (IEEE 1585393) + I. Fujitaka ? (no IEEE) + Eiji Sugimoto - cpu design? 1156033 1155824 + F. Tsukuda ? (no IEEE) + N. Miyake ? switched capacitor stuff? (IEEE nnnnnn) + + + The uPD1771 internal workings are described to some extent by the Bristow book + and the IEEE article "A Single-Chip Sound Synthesis Microcomputer" which complements the book + and are covered by at least four US patents: + 4184152 - on IGFET-based DAC stuff + 4488061 - on the IGFET-based drive circuit part of the DAC. + 4408094 - covers the 3 pin DAC with the volume control/vref pin. Not all that interesting, + except it might describe to some extent how the (9->5bit?) PWM works in the text. + 4470113 - covers the multiplexed PB0/1/2/3 pins and their use as /CS /WR /RD and ALE + note as I have marked the pins below I assume the final pins connected + to /CS /WR /RD and /ALE are PB7,6,5,4 but this is just a guess of mine: + The actual order may well match the patent. + 4577343 - covers the VSRSSS implementation as discussed in the Bristow book. + This patent has an internal diagram of the workings of the chips and + a limited description of how many registers etc it has. + 4805508 - on the operation of the tone divider register and correction for accurate period when + the tone interrupt frequency is not perfectly divisible from the clock. + These next two may not be specific to the 1771 or even related at all! + 4321562 - on a self-adjusting circuit for internal coupling to the clock crystal inputs. + This may be a generic NEC invention and probably isn't limited to the upd1771. + 4656491 - on a new method of distributing resistors and transistors on anti-ESD pin buffers + This may be a generic NEC invention and probably isn't limited to the upd1771. + + + Based on the 4577343 patent mostly, plus the bristow and IEEE article: + * these are the registers: + 8bits: + AH, AL (forming the 16-bit A' accumulator), + B, C (a pair of general purpose registers), + 4bits (may be technically part of ALU): + H -> points to one of the 16 words of ram + 1bit: + L -> selector of left or right half of the ram word + ?bits: + D (having to do with the DAC) + N (3 bits? having to do with the pseudorandom noise interrupt, namely setting the clock divider ratio for the PRNG clock vs cpu clock) + MODE (5 or more bits? enabling/disabling/acking the noise interrupt, and the tone interrupts (there are four!)) + SP (the stack pointer, probably 5 bits, points to the stack ram; may encompass H and L as above!) + FLO: unsure. quite possibly 'flag overflow' used for branching. there likely exists other flags as well... + ODF: 'output data flag?', selects which half of a selected ram word is output to the dac not really sure of this? + + + Mask roms known: + uPD1776C: mentioned in the bristow book, implements VSRSSS speech concatenation + (see US Patent 4577343 which is a patent on this VSRSSS implementation) + uPD1771C-006: used in NEC APC for sound as the "MPU" + -011: used on Firefox F-4/Astro Thunder handheld + -015: unknown, known to exist from part scalper sites only. + -017: used on Epoch Super Cassette Vision for sound; This audio driver HLEs that part only. + + Used pinout in the SCV: + + NC 1 28 NC + NC 2 27 NC + NC 3 26 ACK + !WR 4 25 D7 + !CS 5 24 D6 + RESET 6 23 D5 + NC 7 22 D4 + VCC 8 21 D3 + 6Mhz XIN 9 20 D2 + 6Mhz XOUT 10 19 D1 + AUDOUT 11 18 D0 + NC(recheck!)12 17 GND + AUDOUT(inv) 13 16 VCC + GND 14 15 ? tied to pin 16 (VCC) through a resistor (pullup?) + + Pinout based on guesses and information in "Electronic Speech Synthesis" by Geoff Bristow + (ISBN 0-07-007912-9, pages 148-152), and the data on page 233 of the Nec APC technical manual at + http://bitsavers.trailing-edge.com/pdf/nec/APC/819-000100-1003_APC_System_Reference_Guide_Apr83.pdf + I/O pin purpose based on testing by kevtris. + [x] is unsure: + PB3 <> 1 28 <> PB2 + PB4(/ALE) <> 2 27 <> PB1 + PB5(/RD) <> 3 26 <> PB0 + PB6(/WR) <> 4 25 <> D7(PA7) + PB7(/CS) <> 5 24 <> D6(PA6) + /RESET -> 6 23 <> D5(PA5) + [/TSTOUT?] <- 7 22 <> D4(PA4) + VCC -- 8 21 <> D3(PA3) + XI(CLK) -> 9 20 <> D2(PA2) + XO <- 10 19 <> D1(PA1) + D/A OUT + <- 11 18 <> D0(PA0) + D/A POWER -- 12 17 <- CH2 + D/A OUT - <- 13 16 <> /EXTINT and [/TSTOUT2?] (test out is related to pin 15 state) + GND -- 14 15 <- CH1 tied to pin 16 (VCC) through a resistor, on APC to VCC thru a 12k resistor and thru a 10uf cap to gnd + + CH1 and CH2 are mode selects, purpose based on testing by kevtris: + CH1 CH2 + H L - 'master' mode, pb4-pb7 are i/o? /EXTINT is an input + L L - 'slave' mode where pb4-pb7 are /ale /rd /wr /cs? /EXTINT may be an output in this mode? + X H - test mode: the 512 byte 16-bit wide ROM is output sequentially on pins pa7-pa0 and pb7-pb0 for the high and low bytes of each word respectively + D/A POWER is the FET source for the D/A OUT+ and D/A OUT- push-pull dac drains; it should be tied to VCC or thereabouts + + In the SCV (info from plgDavid): + pin 5 is tied to the !SCPU pin on the Epoch TV chip pin 29 (0x3600 writes) + pin 6 is tied to the PC3 pin of the upD7801 CPU + pin 26 is tied to the INT1 pin of the upD7801 (CPU pin 12), + + 1,2,3,28,27 don't generate any digital signals + 6 seems to be lowered 2.5 ms before an audio write + 7 is always low. + 12 is always high + + (NOTE: the photomicrograph in the bristow book makes it fairly clear due to + pad thicknessess that the real VCC is pin 8 and the real GND is pin 14. + The function of pin 7 is unknown. + + Pins 11 and 13 go to a special circuit, which according to kevtris's analysis + of my schematics, consist of a balanced output (not unlike XLR cables), + which are then combined together then sent to the RF box. + (The bristow book explains that there are two DAC pins and one DAC + VREF/volume pin. The dac+ and dac- are pins 11 and 13, and based on the + photomicrograph it looks like dac vref is probably pin 12) + + HLE: + All writes are made through address 0x3600 on the upD7801 + Instead of using register=value, this chip require sending multiple + bytes for each command, one after the other. + +**********************************************************************/ + +#include "upd1771.h" + +//#define VERBOSE 1 + +namespace { + +/* + Each of the 8 waveforms have been extracted from the uPD1771c-017 internal + ROM, from offset 0x1fd (start of first waveform) to offset 0x2fc (end of + last waveform). + (note: given test mode dumping offset non-clarity it may be 0x200-0x2ff) + The waveforms are stored in an 8-bit sign-magnitude format, so if in ROM the + upper bit is 0x80, invert the lower 7 bits to get the 2's complement result + seen here. + Note that only the last 4 waveforms appear to have been intended for use as + waveforms; the first four look as if they're playing back a piece of code as + wave data. +*/ +static const signed char WAVEFORMS[8][32]={ +{ 0, 0,-123,-123, -61, -23, 125, 107, 94, 83,-128,-128,-128, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,-128,-128,-128, 0, 0, 0, 0, 0, 0}, +{ 37, 16, 32, -21, 32, 52, 4, 4, 33, 18, 60, 56, 0, 8, 5, 16, 65, 19, 69, 16, -2, 19, 37, 16, 97, 19, 0, 87, 127, -3, 1, 2}, +{ 0, 8, 1, 52, 4, 0, 0, 77, 81,-109, 47, 97, -83,-109, 38, 97, 0, 52, 4, 0, 1, 4, 1, 22, 2, -46, 33, 97, 0, 8, -85, -99}, +{ 47, 97, 40, 97, -3, 25, 64, 17, 0, 52, 12, 5, 12, 5, 12, 5, 12, 5, 12, 5, 8, 4,-114, 19, 0, 52,-122, 21, 2, 5, 0, 8}, +{ -52, -96,-118,-128,-111, -74, -37, -5, 31, 62, 89, 112, 127, 125, 115, 93, 57, 23, 0, -16, -8, 15, 37, 54, 65, 70, 62, 54, 43, 31, 19, 0}, +{ -81,-128, -61, 13, 65, 93, 127, 47, 41, 44, 52, 55, 56, 58, 58, 34, 0, 68, 76, 72, 61, 108, 55, 29, 32, 39, 43, 49, 50, 51, 51, 0}, +{ -21, -45, -67, -88,-105,-114,-122,-128,-123,-116,-103, -87, -70, -53, -28, -9, 22, 46, 67, 86, 102, 114, 123, 125, 127, 117, 104, 91, 72, 51, 28, 0}, +{ -78,-118,-128,-102, -54, -3, 40, 65, 84, 88, 84, 80, 82, 88, 94, 103, 110, 119, 122, 125, 122, 122, 121, 123, 125, 126, 127, 127, 125, 118, 82, 0} +}; + + +#define NOISE_SIZE 255 + + +static const unsigned char noise_tbl[]= +{ + 0x1c,0x86,0x8a,0x8f,0x98,0xa1,0xad,0xbe,0xd9,0x8a,0x66,0x4d,0x40,0x33,0x2b,0x23, + 0x1e,0x8a,0x90,0x97,0xa4,0xae,0xb8,0xd6,0xec,0xe9,0x69,0x4a,0x3e,0x34,0x2d,0x27, + 0x24,0x24,0x89,0x8e,0x93,0x9c,0xa5,0xb0,0xc1,0xdd,0x40,0x36,0x30,0x29,0x27,0x24, + 0x8b,0x90,0x96,0x9e,0xa7,0xb3,0xc4,0xe1,0x25,0x21,0x8a,0x8f,0x93,0x9d,0xa5,0xb2, + 0xc2,0xdd,0xdd,0x98,0xa2,0xaf,0xbf,0xd8,0xfd,0x65,0x4a,0x3c,0x31,0x2b,0x24,0x22, + 0x1e,0x87,0x8c,0x91,0x9a,0xa3,0xaf,0xc0,0xdb,0xbe,0xd9,0x8c,0x66,0x4d,0x40,0x34, + 0x2c,0x24,0x1f,0x88,0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4d,0x3d,0x34,0x2d, + 0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0xc1,0xda,0xff,0x67,0x4d, + 0x3d,0x33,0x2d,0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xdd,0xa3,0xb0, + 0xc0,0xd9,0xfe,0x66,0x4b,0x3c,0x32,0x2b,0x24,0x23,0x1e,0x88,0x8d,0x92,0x9b,0xa4, + 0xb0,0xc1,0xdc,0xad,0xbe,0xda,0x22,0x20,0x1c,0x85,0x8a,0x8f,0x98,0xa1,0xad,0xbe, + 0xda,0x20,0x1b,0x85,0x8d,0x97,0xa1,0xaf,0xbf,0xd8,0xfd,0x64,0x49,0x3a,0x30,0x2a, + 0x23,0x21,0x1d,0x86,0x8b,0x91,0x9a,0xa2,0xae,0xc0,0xdb,0x33,0x2b,0x24,0x1f,0x88, + 0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4c,0x3e,0x33,0x2d,0x25,0x24,0x1f,0x89, + 0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0x85,0x8e,0x98,0xa2,0xb0,0xc0,0xd9,0xfe,0x64, + 0x4b,0x3b,0x31,0x2a,0x23,0x22,0x1e,0x88,0x8c,0x91,0x9b,0xa3,0xaf,0xc1,0xdc,0xdc +}; + + +#define STATE_SILENCE 0 +#define STATE_NOISE 1 +#define STATE_TONE 2 +#define STATE_ADPCM 3 + +} // anonymous namespace + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd1771c_device::device_reset() +{ + m_index = 0; + m_expected_bytes = 0; + m_pc3 = 0; + m_t_tpos = 0; + m_t_ppos = 0; + m_state = STATE_SILENCE; + m_nw_tpos = 0; + memset(m_n_value, 0x00, sizeof(m_n_value)); + memset(m_n_ppos, 0x00, sizeof(m_n_ppos)); +} + + + +uint8_t upd1771c_device::read() +{ + return 0x80; // TODO +} + +/* +*************TONE***************** +Tone consists of a wavetable playback mechanism. +Each wavetable is a looping period of 32 samples but can be played with an offset from any point in the table +effectively shrinking the sample loop, thus allowing different pitch "macros ranges" to be played. +This method is rather crude because the spectrum of the sound get heavily altered... +unless that was the intent. + +Tone Write (4 bytes): + +Byte0: 0x02 + +Byte1: 0bTTTOOOOO + MSB 3 bits of Timbre (8 wavetables) + LSB 5 bits offset in the table. + +Byte2: 0bPPPPPPPP + 8bits of clock divider/period + Anything under <= 0x20 give the same value + +Byte3: 0b???VVVVV + MSB 3 bits unknown + LSB 5 bits of "Volume" + + Note: volume is not a volume in a normal sense but some kind + of bit cropping/rounding. +*/ + + +/* +*************NOISE***************** +Noise consists on 4 different components +A weird Wavetable LFSR (for lack of a better term), +and three independent (but equal) low frequency +50/50 pulse wavs. + +The 4 components are mixed in a mysterious way, +a weird ORing with volume having a huge effect. + +Byte0: 0x01 + +Byte1: 0bTTTOOOOO + MSB 3 bits of LFSR Timbre (8 wavetables) + LSB 5 bits ????????? + +Byte2: 0bPPPPPPPP + 8bits of clock divider/period + +Byte3: 0b???VVVVV + MSB 3 bits unknown + LSB 5 bits of "Volume" + + +Byte4: 0bPPPPPPPP Low Freq0 period(if not 0 this periodically resets the Wavetable LFSR) +Byte5: 0bPPPPPPPP Low Freq1 period(if not 0 this periodically resets the Wavetable LFSR) +Byte6: 0bPPPPPPPP Low Freq2 period(if not 0 this periodically resets the Wavetable LFSR) + +Byte7: 0b???VVVVV Low Freq0 volume +Byte8: 0b???VVVVV Low Freq1 volume +Byte9: 0b???VVVVV Low Freq2 volume +*/ + +void upd1771c_device::write(uint8_t data) +{ + //LOG("upd1771_w: received byte 0x%02x\n", data); + + if (m_index < MAX_PACKET_SIZE) + m_packet[m_index++] = data; + else + { + //logerror("upd1771_w: received byte 0x%02x overload!\n", data); + return; + } + + switch (m_packet[0]) + { + case 0: + m_state = STATE_SILENCE; + m_index = 0; + //logerror( "upd1771_w: ----------------silence state reset\n"); + break; + + case 1: + if (m_index == 10) + { + m_state = STATE_NOISE; + m_index = 0; + + m_nw_timbre = (m_packet[1] & 0xe0) >> 5; + m_nw_period = ((uint32_t)m_packet[2] + 1) << 7; + m_nw_volume = m_packet[3] & 0x1f; + + //very long clocked periods.. used for engine drones + m_n_period[0] = (((uint32_t)m_packet[4]) + 1) << 7; + m_n_period[1] = (((uint32_t)m_packet[5]) + 1) << 7; + m_n_period[2] = (((uint32_t)m_packet[6]) + 1) << 7; + + m_n_volume[0] = m_packet[7] & 0x1f; + m_n_volume[1] = m_packet[8] & 0x1f; + m_n_volume[2] = m_packet[9] & 0x1f; + + //logerror( "upd1771_w: ----------------noise state reset\n"); + } else { + // supposedly timer adjusts here, to 512 cycles + } + + break; + + case 2: + if (m_index == 4) + { + //logerror( "upd1771_w: ----------------tone state reset\n"); + m_t_timbre = (m_packet[1] & 0xe0) >> 5; + m_t_offset = (m_packet[1] & 0x1f); + m_t_period = m_packet[2]; + //smaller periods don't all equal to 0x20 + if (m_t_period < 0x20) + m_t_period = 0x20; + + m_t_volume = m_packet[3] & 0x1f; + m_state = STATE_TONE; + m_index = 0; + } else { + // supposedly timer adjusts here, to 512 cycles + } + break; + + case 0x1f: + //6Khz(ish) DIGI playback + + //end capture + { + bool have_all_data = false; + if (m_index >= 2 && m_packet[m_index - 2] == 0xfe && m_packet[m_index - 1] == 0x00) + { + //TODO play capture! + if (m_index >= 6) + { + // offsets 2 and 3 in the transferred pcm data seem to contain the number of samples + uint16_t count = (m_packet[4] << 8) | m_packet[3]; + count--; + m_packet[3] = count & 0xff; + m_packet[4] = (count >> 8); + if (count == 0) + { + m_index = 0; + m_packet[0] = 0; + m_state = STATE_ADPCM; + have_all_data = true; + } + } + } + if (!have_all_data) { + // supposedly timer adjusts here, to 512 cycles + } + } + break; + + //garbage: wipe stack + default: + m_state = STATE_SILENCE; + m_index = 0; + break; + } +} + + +void upd1771c_device::pcm_write(int state) +{ + //RESET upon HIGH + if (state != m_pc3) + { + //logerror("upd1771_pc3 change!: state = %d\n", state); + m_index = 0; + m_packet[0] = 0; + m_state = STATE_SILENCE; + } + + m_pc3 = state; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void upd1771c_device::sound_stream_update(short* output, int len) +{ + switch (m_state) + { + case STATE_TONE: + //logerror( "upd1771_STATE_TONE samps:%d %d %d %d %d %d\n",(int)samples, + // (int)m_t_timbre,(int)m_t_offset,(int)m_t_volume,(int)m_t_period,(int)m_t_tpos); + + for (int sampindex = 0; sampindex < len; sampindex++) + { + output[sampindex]=(WAVEFORMS[m_t_timbre][m_t_tpos]) * m_t_volume * 8; + + m_t_ppos++; + if (m_t_ppos >= m_t_period) + { + m_t_tpos++; + if (m_t_tpos == 32) + m_t_tpos = m_t_offset; + + m_t_ppos = 0; + } + } + break; + + case STATE_NOISE: + for (int sampindex = 0; sampindex < len; sampindex++) + { + //"wavetable-LFSR" component + int wlfsr_val = ((int)noise_tbl[m_nw_tpos]) - 127;//data too wide + + m_nw_ppos++; + if (m_nw_ppos >= m_nw_period) + { + m_nw_tpos++; + if (m_nw_tpos == NOISE_SIZE) + m_nw_tpos = 0; + m_nw_ppos = 0; + } + + //mix in each of the noise's 3 pulse components + char res[3]; + for (int i = 0; i < 3; ++i) + { + res[i] = m_n_value[i] * 127; + m_n_ppos[i]++; + if (m_n_ppos[i] >= m_n_period[i]) + { + m_n_ppos[i] = 0; + m_n_value[i] = !m_n_value[i]; + } + } + //not quite, but close. + output[sampindex]= + ((wlfsr_val * m_nw_volume) | + (res[0] * m_n_volume[0]) | + (res[1] * m_n_volume[1]) | + (res[2] * m_n_volume[2])) * 8; + } + break; + + default: + //fill buffer with silence + memset(output,0,sizeof(short)*len); + break; + } +} diff --git a/src/engine/platform/sound/upd1771.h b/src/engine/platform/sound/upd1771.h new file mode 100644 index 000000000..5f078fc4c --- /dev/null +++ b/src/engine/platform/sound/upd1771.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + NEC uPD1771 + +**********************************************************************/ + +#ifndef MAME_SOUND_UPD1771_H +#define MAME_SOUND_UPD1771_H + +#include + + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class upd1771c_device +{ +public: + uint8_t read(); + void write(uint8_t data); + void pcm_write(int state); + + // device-level overrides + void device_reset(); + + // sound stream update overrides + void sound_stream_update(short* output, int len); + +private: + static constexpr unsigned MAX_PACKET_SIZE = 0x8000; + + // internal state + + uint8_t m_packet[MAX_PACKET_SIZE]; + uint32_t m_index; + uint8_t m_expected_bytes; + + uint8_t m_state;//0:silence, 1 noise, 2 tone + uint8_t m_pc3; + + //tone + uint8_t m_t_timbre; //[0; 7] + uint8_t m_t_offset; //[0; 32] + uint16_t m_t_period; //[0;255] + uint8_t m_t_volume; //[0; 31] + uint8_t m_t_tpos;//timbre pos + uint16_t m_t_ppos;//period pos + + //noise wavetable LFSR + uint8_t m_nw_timbre; //[0; 7] + uint8_t m_nw_volume; //[0; 31] + uint32_t m_nw_period; + uint32_t m_nw_tpos; //timbre pos + uint32_t m_nw_ppos; //period pos + + //noise pulse components + uint8_t m_n_value[3]; //[0;1] + uint16_t m_n_volume[3]; //[0; 31] + uint32_t m_n_period[3]; + uint32_t m_n_ppos[3]; //period pos +}; + +#endif // MAME_SOUND_UPD1771_H diff --git a/src/engine/platform/sound/upd1771c.c b/src/engine/platform/sound/upd1771c.c deleted file mode 100644 index 0ed1c9f5e..000000000 --- a/src/engine/platform/sound/upd1771c.c +++ /dev/null @@ -1,300 +0,0 @@ -// SOME CODE IS TAKEN FROM MAME'S EMULATION OF THE UPD1771C -// MADE BY AART1256 IN 2024 - -#include "upd1771c.h" - -#include - -/* - Each of the 8 waveforms have been extracted from the uPD1771c-017 internal - ROM, from offset 0x1fd (start of first waveform) to offset 0x2fc (end of - last waveform). - (note: given test mode dumping offset non-clarity it may be 0x200-0x2ff) - The waveforms are stored in an 8-bit sign-magnitude format, so if in ROM the - upper bit is 0x80, invert the lower 7 bits to get the 2's complement result - seen here. - Note that only the last 4 waveforms appear to have been intended for use as - waveforms; the first four look as if they're playing back a piece of code as - wave data. -*/ -const signed char WAVEFORMS[8][32]={ -{ 0, 0,-123,-123, -61, -23, 125, 107, 94, 83,-128,-128,-128, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,-128,-128,-128, 0, 0, 0, 0, 0, 0}, -{ 37, 16, 32, -21, 32, 52, 4, 4, 33, 18, 60, 56, 0, 8, 5, 16, 65, 19, 69, 16, -2, 19, 37, 16, 97, 19, 0, 87, 127, -3, 1, 2}, -{ 0, 8, 1, 52, 4, 0, 0, 77, 81,-109, 47, 97, -83,-109, 38, 97, 0, 52, 4, 0, 1, 4, 1, 22, 2, -46, 33, 97, 0, 8, -85, -99}, -{ 47, 97, 40, 97, -3, 25, 64, 17, 0, 52, 12, 5, 12, 5, 12, 5, 12, 5, 12, 5, 8, 4,-114, 19, 0, 52,-122, 21, 2, 5, 0, 8}, -{ -52, -96,-118,-128,-111, -74, -37, -5, 31, 62, 89, 112, 127, 125, 115, 93, 57, 23, 0, -16, -8, 15, 37, 54, 65, 70, 62, 54, 43, 31, 19, 0}, -{ -81,-128, -61, 13, 65, 93, 127, 47, 41, 44, 52, 55, 56, 58, 58, 34, 0, 68, 76, 72, 61, 108, 55, 29, 32, 39, 43, 49, 50, 51, 51, 0}, -{ -21, -45, -67, -88,-105,-114,-122,-128,-123,-116,-103, -87, -70, -53, -28, -9, 22, 46, 67, 86, 102, 114, 123, 125, 127, 117, 104, 91, 72, 51, 28, 0}, -{ -78,-118,-128,-102, -54, -3, 40, 65, 84, 88, 84, 80, 82, 88, 94, 103, 110, 119, 122, 125, 122, 122, 121, 123, 125, 126, 127, 127, 125, 118, 82, 0} -}; - - -#define NOISE_SIZE 255 - - -/* -const unsigned char noise_tbl[]= -{ - 0x1c,0x86,0x8a,0x8f,0x98,0xa1,0xad,0xbe,0xd9,0x8a,0x66,0x4d,0x40,0x33,0x2b,0x23, - 0x1e,0x8a,0x90,0x97,0xa4,0xae,0xb8,0xd6,0xec,0xe9,0x69,0x4a,0x3e,0x34,0x2d,0x27, - 0x24,0x24,0x89,0x8e,0x93,0x9c,0xa5,0xb0,0xc1,0xdd,0x40,0x36,0x30,0x29,0x27,0x24, - 0x8b,0x90,0x96,0x9e,0xa7,0xb3,0xc4,0xe1,0x25,0x21,0x8a,0x8f,0x93,0x9d,0xa5,0xb2, - 0xc2,0xdd,0xdd,0x98,0xa2,0xaf,0xbf,0xd8,0xfd,0x65,0x4a,0x3c,0x31,0x2b,0x24,0x22, - 0x1e,0x87,0x8c,0x91,0x9a,0xa3,0xaf,0xc0,0xdb,0xbe,0xd9,0x8c,0x66,0x4d,0x40,0x34, - 0x2c,0x24,0x1f,0x88,0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4d,0x3d,0x34,0x2d, - 0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0xc1,0xda,0xff,0x67,0x4d, - 0x3d,0x33,0x2d,0x26,0x24,0x20,0x89,0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xdd,0xa3,0xb0, - 0xc0,0xd9,0xfe,0x66,0x4b,0x3c,0x32,0x2b,0x24,0x23,0x1e,0x88,0x8d,0x92,0x9b,0xa4, - 0xb0,0xc1,0xdc,0xad,0xbe,0xda,0x22,0x20,0x1c,0x85,0x8a,0x8f,0x98,0xa1,0xad,0xbe, - 0xda,0x20,0x1b,0x85,0x8d,0x97,0xa1,0xaf,0xbf,0xd8,0xfd,0x64,0x49,0x3a,0x30,0x2a, - 0x23,0x21,0x1d,0x86,0x8b,0x91,0x9a,0xa2,0xae,0xc0,0xdb,0x33,0x2b,0x24,0x1f,0x88, - 0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4c,0x3e,0x33,0x2d,0x25,0x24,0x1f,0x89, - 0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0x85,0x8e,0x98,0xa2,0xb0,0xc0,0xd9,0xfe,0x64, - 0x4b,0x3b,0x31,0x2a,0x23,0x22,0x1e,0x88,0x8c,0x91,0x9b,0xa3,0xaf,0xc1,0xdc,0xdc -}; -*/ - -const unsigned char noise_tbl[8][256] = { -{ - 0x84, 0x87, 0x8c, 0x93, 0x9a, 0xa4, 0xb2, 0xc8, 0x8a, 0x6c, 0x58, 0x4e, 0x43, 0x3d, 0x37, 0x33, - 0x86, 0x8d, 0x95, 0x9d, 0xa8, 0xb5, 0xc9, 0xe7, 0x6d, 0x58, 0x4b, 0x43, 0x3e, 0x38, 0x37, 0x34, - 0x87, 0x8b, 0x8f, 0x96, 0x9d, 0xa7, 0xb5, 0xcb, 0x4d, 0x45, 0x40, 0x3a, 0x39, 0x35, 0x89, 0x8d, - 0x91, 0x98, 0x9f, 0xa9, 0xb7, 0xcd, 0x37, 0x34, 0x87, 0x8c, 0x90, 0x97, 0x9e, 0xa8, 0xb5, 0xcb, - 0xca, 0x93, 0x9b, 0xa6, 0xb3, 0xc7, 0xe5, 0x6b, 0x56, 0x49, 0x41, 0x3c, 0x36, 0x35, 0x32, 0x86, - 0x89, 0x8e, 0x95, 0x9c, 0xa6, 0xb4, 0xc9, 0xb2, 0xc8, 0x8a, 0x6c, 0x58, 0x4d, 0x43, 0x3d, 0x37, - 0x33, 0x86, 0x8d, 0x95, 0x9d, 0xa8, 0xb5, 0xc9, 0xe7, 0x6d, 0x58, 0x4b, 0x43, 0x3e, 0x38, 0x37, - 0x34, 0x87, 0x8b, 0x8f, 0x97, 0x9e, 0xa8, 0xb5, 0xcb, 0xb5, 0xc9, 0xe6, 0x6d, 0x58, 0x4b, 0x43, - 0x3d, 0x38, 0x37, 0x33, 0x87, 0x8b, 0x8f, 0x96, 0x9e, 0xa7, 0xb5, 0xcb, 0x9c, 0xa7, 0xb3, 0xc8, - 0xe6, 0x6c, 0x56, 0x4a, 0x42, 0x3d, 0x37, 0x36, 0x33, 0x86, 0x8a, 0x8e, 0x95, 0x9c, 0xa6, 0xb4, - 0xca, 0xa4, 0xb2, 0xc8, 0x35, 0x33, 0x30, 0x84, 0x88, 0x8c, 0x93, 0x9a, 0xa5, 0xb2, 0xc8, 0x34, - 0x30, 0x84, 0x8a, 0x93, 0x9a, 0xa5, 0xb2, 0xc6, 0xe4, 0x6a, 0x55, 0x49, 0x41, 0x3b, 0x36, 0x34, - 0x31, 0x85, 0x89, 0x8d, 0x94, 0x9b, 0xa5, 0xb3, 0xc9, 0x43, 0x3d, 0x37, 0x33, 0x86, 0x8d, 0x95, - 0x9d, 0xa8, 0xb4, 0xc9, 0xe7, 0x6d, 0x57, 0x4b, 0x43, 0x3e, 0x38, 0x37, 0x33, 0x87, 0x8b, 0x8f, - 0x96, 0x9d, 0xa7, 0xb5, 0xcb, 0x85, 0x8b, 0x93, 0x9b, 0xa6, 0xb3, 0xc7, 0xe5, 0x6b, 0x56, 0x4a, - 0x41, 0x3c, 0x36, 0x35, 0x32, 0x86, 0x89, 0x8e, 0x95, 0x9c, 0xa6, 0xb4, 0xca, 0x30 -}, - -{ - 0x95, 0x95, 0x98, 0x9c, 0x9e, 0xa3, 0xaa, 0xb4, 0xb3, 0x98, 0x9c, 0xa1, 0xa7, 0xb1, 0xc0, 0x57, - 0x4f, 0x49, 0x48, 0x44, 0x42, 0x40, 0x40, 0x94, 0x95, 0x96, 0x9a, 0x9d, 0xa2, 0xa9, 0xb3, 0xa8, - 0xb1, 0x66, 0x59, 0x50, 0x4c, 0x4a, 0x46, 0x44, 0x41, 0x94, 0x97, 0x9b, 0x9e, 0xa4, 0xaa, 0xb3, - 0xc2, 0x59, 0x52, 0x4c, 0x4a, 0x46, 0x45, 0x43, 0x43, 0x96, 0x97, 0x99, 0x9d, 0x9f, 0xa5, 0xab, - 0xb5, 0xaa, 0xb4, 0xc2, 0x5a, 0x52, 0x4c, 0x4b, 0x47, 0x45, 0x43, 0x43, 0x96, 0x97, 0x99, 0x9d, - 0xa0, 0xa5, 0xab, 0xb5, 0x9d, 0xa3, 0xa9, 0xb3, 0xc2, 0x59, 0x51, 0x4b, 0x4a, 0x46, 0x44, 0x42, - 0x42, 0x96, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0xb4, 0xa2, 0xa9, 0xb3, 0x41, 0x40, 0x40, 0x93, - 0x94, 0x96, 0x9a, 0x9d, 0xa2, 0xa8, 0xb2, 0x41, 0x3e, 0x92, 0x94, 0x99, 0x9b, 0xa2, 0xa7, 0xb1, - 0xc0, 0x57, 0x4f, 0x4a, 0x48, 0x44, 0x42, 0x40, 0x40, 0x94, 0x95, 0x97, 0x9a, 0x9d, 0xa2, 0xa9, - 0xb3, 0x48, 0x45, 0x43, 0x41, 0x94, 0x97, 0x9b, 0x9d, 0xa3, 0xa9, 0xb3, 0xc1, 0x59, 0x51, 0x4b, - 0x4a, 0x45, 0x44, 0x42, 0x42, 0x95, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0xb4, 0x92, 0x95, 0x99, - 0x9c, 0xa2, 0xa8, 0xb1, 0xc0, 0x57, 0x4f, 0x4a, 0x48, 0x44, 0x42, 0x41, 0x41, 0x94, 0x95, 0x97, - 0x9b, 0x9e, 0xa3, 0xa9, 0xb3, 0x3e, 0x92, 0x93, 0x95, 0x98, 0x9b, 0xa0, 0xa7, 0xb1, 0x65, 0x58, - 0x50, 0x4b, 0x49, 0x45, 0x43, 0x41, 0x94, 0x97, 0x9b, 0x9e, 0xa4, 0xa9, 0xb3, 0xc2, 0x59, 0x51, - 0x4b, 0x4a, 0x46, 0x45, 0x42, 0x42, 0x96, 0x96, 0x99, 0x9c, 0x9f, 0xa4, 0xab, 0xb5, 0x4d, 0x4b, - 0x47, 0x45, 0x43, 0x43, 0x97, 0x97, 0x9a, 0x9d, 0xa0, 0xa5, 0xac, 0xb6, 0x41, 0x42 - -}, - -{ - 0x93, 0x93, 0x93, 0x94, 0x95, 0x99, 0x9c, 0xa1, 0xa8, 0x4e, 0x48, 0x45, 0x43, 0x44, 0x42, 0x42, - 0x95, 0x95, 0x95, 0x96, 0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x43, 0x41, 0x41, 0x95, 0x94, 0x94, 0x95, - 0x97, 0x9b, 0x9d, 0xa3, 0xa9, 0x4f, 0x4a, 0x46, 0x45, 0x45, 0x43, 0x43, 0x97, 0x96, 0x96, 0x97, - 0x99, 0x9a, 0x9c, 0x9f, 0xa7, 0x94, 0x93, 0x94, 0x96, 0x9a, 0x9d, 0xa2, 0xa9, 0x4f, 0x49, 0x45, - 0x44, 0x45, 0x43, 0x43, 0x96, 0x96, 0x96, 0x96, 0x98, 0x99, 0x9c, 0x9f, 0xa7, 0x93, 0x93, 0x93, - 0x93, 0x95, 0x96, 0x99, 0x9c, 0xa4, 0x50, 0x4b, 0x49, 0x45, 0x44, 0x42, 0x42, 0x95, 0x95, 0x95, - 0x96, 0x97, 0x9b, 0x9e, 0xa3, 0xaa, 0x50, 0x4b, 0x46, 0x46, 0x46, 0x44, 0x44, 0x97, 0x97, 0x97, - 0x97, 0x99, 0x9a, 0x9d, 0x9f, 0xa8, 0x47, 0x46, 0x46, 0x44, 0x44, 0x98, 0x98, 0x97, 0x98, 0x9a, - 0x9b, 0x9d, 0xa0, 0xa8, 0x42, 0x96, 0x95, 0x95, 0x96, 0x98, 0x98, 0x9b, 0x9e, 0xa6, 0xa6, 0x93, - 0x95, 0x99, 0x9c, 0xa1, 0xa7, 0x4e, 0x48, 0x44, 0x43, 0x44, 0x41, 0x42, 0x95, 0x95, 0x95, 0x95, - 0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x9d, 0xa5, 0x52, 0x4c, 0x4b, 0x46, 0x45, 0x42, 0x43, 0x97, 0x96, - 0x96, 0x97, 0x98, 0x9c, 0x9f, 0xa4, 0xab, 0x51, 0x4b, 0x48, 0x46, 0x47, 0x44, 0x45, 0x98, 0x98, - 0x98, 0x98, 0x9a, 0x9b, 0x9e, 0xa0, 0xa8, 0x9f, 0xa4, 0xab, 0x51, 0x4c, 0x48, 0x47, 0x47, 0x45, - 0x45, 0x99, 0x98, 0x98, 0x99, 0x9a, 0x9b, 0x9e, 0xa1, 0xa9, 0x98, 0x9d, 0x9f, 0xa4, 0xab, 0x51, - 0x4b, 0x47, 0x47, 0x47, 0x45, 0x45, 0x98, 0x98, 0x98, 0x98, 0x9a, 0x9b, 0x9e, 0xa1, 0xa8, 0x9c, - 0x9f, 0xa7, 0x42, 0x42, 0x95, 0x95, 0x95, 0x96, 0x97, 0x98, 0x9b, 0x9e, 0xa6, 0x3f - -}, - -{ - 0x94, 0x93, 0x92, 0x92, 0x93, 0x95, 0x96, 0x99, 0x9c, 0x43, 0x43, 0x43, 0x41, 0x41, 0x42, 0x95, - 0x95, 0x95, 0x94, 0x94, 0x94, 0x95, 0x97, 0x97, 0x9a, 0x40, 0x40, 0x41, 0x95, 0x95, 0x94, 0x95, - 0x95, 0x97, 0x97, 0x9a, 0x9e, 0x45, 0x44, 0x44, 0x42, 0x42, 0x43, 0x97, 0x96, 0x96, 0x96, 0x96, - 0x95, 0x96, 0x98, 0x99, 0x9c, 0x94, 0x94, 0x94, 0x94, 0x96, 0x97, 0x9a, 0x9d, 0x44, 0x43, 0x44, - 0x42, 0x42, 0x43, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x96, 0x98, 0x98, 0x9b, 0x93, 0x93, 0x93, - 0x92, 0x92, 0x93, 0x95, 0x95, 0x98, 0x49, 0x44, 0x43, 0x44, 0x42, 0x42, 0x43, 0x96, 0x96, 0x96, - 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9f, 0x46, 0x45, 0x45, 0x43, 0x44, 0x44, 0x98, 0x98, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x99, 0x9a, 0x9d, 0x45, 0x43, 0x43, 0x44, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, - 0x97, 0x99, 0x9a, 0x9d, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x96, 0x97, 0x9a, 0x9a, 0x92, - 0x93, 0x94, 0x95, 0x98, 0x9c, 0x43, 0x42, 0x43, 0x40, 0x40, 0x41, 0x95, 0x95, 0x94, 0x94, 0x94, - 0x93, 0x94, 0x96, 0x97, 0x9a, 0x96, 0x99, 0x4a, 0x45, 0x44, 0x44, 0x42, 0x42, 0x43, 0x97, 0x96, - 0x96, 0x96, 0x97, 0x98, 0x99, 0x9c, 0xa0, 0x47, 0x46, 0x46, 0x44, 0x44, 0x45, 0x98, 0x98, 0x98, - 0x98, 0x97, 0x97, 0x98, 0x99, 0x9a, 0x9d, 0x9a, 0x9c, 0xa0, 0x47, 0x46, 0x46, 0x44, 0x44, 0x45, - 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x98, 0x9a, 0x9a, 0x9e, 0x97, 0x98, 0x99, 0x9c, 0xa0, 0x47, - 0x46, 0x46, 0x44, 0x44, 0x45, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, 0x98, 0x9a, 0x9a, 0x9d, 0x98, - 0x99, 0x9c, 0x42, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x95, 0x96, 0x97, 0x9a, 0x40 - -}, - -{ - 0xe6, 0x1c, 0x87, 0xcb, 0x42, 0x9b, 0x87, 0x35, 0xd8, 0x1c, 0xa3, 0x58, 0x84, 0xa4, 0x28, 0x71, - 0xd9, 0x3e, 0x82, 0xbb, 0x28, 0xd2, 0x80, 0x63, 0xe0, 0x38, 0x71, 0xcb, 0x22, 0x81, 0x9b, 0x83, - 0xa4, 0x28, 0x71, 0xd8, 0x3e, 0x81, 0xbb, 0x28, 0xd2, 0x80, 0x63, 0xe0, 0x37, 0x71, 0xcb, 0x22, - 0x81, 0x9b, 0xa3, 0x57, 0x83, 0xa3, 0x28, 0x70, 0xd8, 0x3e, 0x81, 0xba, 0x28, 0xd1, 0x80, 0x63, - 0xe0, 0x37, 0x70, 0xcb, 0x22, 0x81, 0x9b, 0x23, 0x82, 0x9b, 0x28, 0xd2, 0x80, 0x63, 0xe1, 0x38, - 0x71, 0xcc, 0x23, 0x81, 0x9b, 0x9c, 0x88, 0x36, 0xd9, 0x1d, 0xa4, 0x58, 0x84, 0xa5, 0x28, 0x72, - 0xd9, 0x3f, 0x82, 0xbb, 0x29, 0xd2, 0x81, 0x64, 0xe1, 0x38, 0x72, 0xcc, 0x23, 0x82, 0x9b, 0xcc, - 0x43, 0x9c, 0x88, 0x36, 0xd8, 0x1d, 0xa4, 0x58, 0x84, 0xa5, 0x29, 0x71, 0xd9, 0x3f, 0x82, 0xbc, - 0x29, 0xd2, 0x81, 0x64, 0xe1, 0x39, 0x72, 0xcc, 0x23, 0x82, 0x9c, 0x37, 0xd9, 0x1d, 0xa4, 0x59, - 0x85, 0xa6, 0x29, 0x72, 0xda, 0x40, 0x83, 0xbc, 0x2a, 0xd3, 0x82, 0x64, 0xe2, 0x39, 0x72, 0xcc, - 0x24, 0x82, 0x9c, 0x82, 0x64, 0xe1, 0x3a, 0x72, 0xcc, 0x24, 0x82, 0x9c, 0x40, 0xe8, 0x1e, 0x89, - 0xcd, 0x44, 0x9d, 0x89, 0x37, 0xd9, 0x1e, 0xa5, 0x59, 0x85, 0xa6, 0x2a, 0x73, 0xda, 0x40, 0x84, - 0xbd, 0x2a, 0xd3, 0x82, 0x65, 0xe2, 0x39, 0x73, 0xcd, 0x24, 0x83, 0x9c, 0x40, 0x83, 0xbd, 0x2a, - 0xd3, 0x82, 0x65, 0xe2, 0x39, 0x73, 0xcd, 0x24, 0x83, 0x9c, 0xd2, 0x81, 0x63, 0xe0, 0x39, 0x71, - 0xcc, 0x23, 0x82, 0x9b, 0x9b, 0x1d, 0xa4, 0x59, 0x84, 0xa5, 0x29, 0x72, 0xd9, 0x3f, 0x83, 0xbc, - 0x29, 0xd3, 0x81, 0x64, 0xe1, 0x39, 0x72, 0xcc, 0x24, 0x82, 0x9c, 0x82, 0x9c, 0x3f - -}, - -{ - 0xe7, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x88, 0x1b, 0x8a, - 0xe6, 0x88, 0x1a, 0x8a, 0x1c, 0x8b, 0xe7, 0x89, 0x1b, 0x8b, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x89, - 0x1b, 0x8a, 0xe6, 0x89, 0x1b, 0x8a, 0xe6, 0x89, 0x1a, 0x8a, 0xe6, 0x88, 0x1a, 0x89, 0xe5, 0x88, - 0x1a, 0x89, 0xe5, 0x88, 0x1a, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe4, 0x87, 0x19, - 0x89, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x1a, 0x8a, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x88, - 0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe4, 0x87, 0x19, 0x89, 0xe4, 0x87, 0x19, 0xe4, 0x87, 0x19, - 0xe4, 0x87, 0x1a, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0x1a, 0x89, 0xe5, 0x88, - 0x1a, 0x89, 0xe5, 0x88, 0x1a, 0x89, 0xe5, 0x87, 0x1a, 0x89, 0xe4, 0x88, 0x19, 0x89, 0xe4, 0x87, - 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, - 0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x88, 0xe3, 0x86, - 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, - 0x18, 0x87, 0xe2, 0x85, 0x18, 0x87, 0xe3, 0x85, 0x17, 0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe4, - 0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, - 0x86, 0x18, 0x87, 0xe3, 0x85, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, 0x87, 0xe3, - 0x85, 0x18, 0x87, 0x19, 0x88, 0xe3, 0x86, 0x19, 0x88, 0xe3, 0x86, 0x18, 0x87, 0xe3, 0x86, 0x18, - 0x87, 0x1a, 0x89, 0xe4, 0x87, 0x19, 0x88, 0xe4, 0x87, 0x19, 0x1b, 0x89, 0x1c, 0x8b - -}, - -{ - 0xa1, 0xe6, 0xcf, 0x79, 0x58, 0x4a, 0x78, 0x7a, 0x53, 0x7b, 0xc2, 0xc3, 0x82, 0x36, 0x48, 0x84, - 0xcb, 0xa6, 0x67, 0x2e, 0x49, 0x7c, 0xaa, 0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xaa, 0x71, 0xa7, - 0x67, 0x2f, 0x4a, 0x7c, 0xab, 0x94, 0x87, 0x74, 0x62, 0x6d, 0xa4, 0xab, 0x72, 0x7b, 0xaa, 0x93, - 0x87, 0x72, 0x61, 0x6c, 0xa4, 0xaa, 0x71, 0x72, 0x7b, 0xc2, 0xc3, 0x81, 0x36, 0x48, 0x84, 0xcb, - 0xa6, 0x67, 0x2e, 0x49, 0x7b, 0xaa, 0x93, 0x87, 0x72, 0x61, 0x6c, 0xa4, 0xaa, 0x71, 0xaa, 0x71, - 0x59, 0xa0, 0xe5, 0xce, 0x78, 0x57, 0x49, 0x77, 0x79, 0x52, 0x7a, 0xc1, 0xc2, 0x81, 0x35, 0x47, - 0x83, 0xca, 0xa6, 0x66, 0x2d, 0x48, 0x7b, 0xa9, 0x92, 0x86, 0x72, 0x61, 0x6b, 0xa3, 0xa9, 0x70, - 0x82, 0x36, 0x49, 0x84, 0xcc, 0xa7, 0x67, 0x2e, 0x4a, 0x7c, 0xab, 0x94, 0x87, 0x73, 0x62, 0x6c, - 0xa4, 0xab, 0x72, 0xc2, 0xc3, 0x82, 0x36, 0x48, 0x84, 0xcb, 0xa6, 0x67, 0x2e, 0x4a, 0x7c, 0xaa, - 0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xaa, 0x71, 0xa3, 0xaa, 0x70, 0x49, 0x7b, 0xa9, 0x92, 0x86, - 0x72, 0x61, 0x6b, 0xa3, 0xaa, 0x70, 0x4b, 0x78, 0x7a, 0x53, 0x7c, 0xc2, 0xc3, 0x82, 0x36, 0x49, - 0x84, 0xcc, 0xa6, 0x67, 0x2f, 0x4a, 0x7c, 0xaa, 0x93, 0x87, 0x73, 0x62, 0x6c, 0xa4, 0xab, 0x72, - 0x7b, 0x5a, 0x4c, 0x7a, 0x7c, 0x55, 0x7e, 0xc4, 0xc5, 0x83, 0x38, 0x4a, 0x85, 0xcd, 0xa8, 0x69, - 0x30, 0x4b, 0x7d, 0xac, 0x95, 0x88, 0x74, 0x63, 0x6e, 0xa5, 0xac, 0x73, 0x7c, 0x55, 0x7d, 0xc4, - 0xc5, 0x83, 0x37, 0x4a, 0x85, 0xcd, 0xa8, 0x68, 0x30, 0x4b, 0x7d, 0xac, 0x95, 0x88, 0x74, 0x63, - 0x6e, 0xa6, 0xac, 0x73, 0xab, 0x94, 0x87, 0x73, 0x62, 0x6d, 0xa5, 0xab, 0x72, 0x5a - -}, - -{ - 0xbf, 0xdc, 0xd4, 0xaa, 0x82, 0x81, 0x35, 0x34, 0x4d, 0x75, 0x95, 0xcb, 0xde, 0xc9, 0x91, 0x72, - 0x4a, 0x30, 0x6b, 0x57, 0x69, 0x7d, 0x65, 0x3f, 0x33, 0x4f, 0x69, 0x81, 0xc1, 0xde, 0xd6, 0xac, - 0x83, 0x82, 0x37, 0x36, 0x4f, 0x77, 0x96, 0xcd, 0xe0, 0xca, 0x93, 0x73, 0x4c, 0x31, 0x6d, 0x58, - 0x6a, 0x4f, 0x68, 0x80, 0xc0, 0xdd, 0xd5, 0xab, 0x82, 0x82, 0x36, 0x35, 0x4e, 0x76, 0x95, 0xcc, - 0xdf, 0xca, 0x92, 0x73, 0x4b, 0x31, 0x6c, 0x57, 0x6a, 0xe0, 0xca, 0x92, 0x73, 0x4c, 0x31, 0x6c, - 0x58, 0x6a, 0xad, 0xd5, 0xdb, 0xbc, 0x7b, 0x63, 0x3c, 0x31, 0x4e, 0x66, 0x7e, 0xbe, 0xdb, 0xd3, - 0xaa, 0x81, 0x80, 0x34, 0x33, 0x4c, 0x75, 0x94, 0xcb, 0xde, 0xc8, 0x91, 0x71, 0x4a, 0x2f, 0x6b, - 0x56, 0x68, 0x35, 0x4e, 0x76, 0x95, 0xcc, 0xdf, 0xca, 0x92, 0x72, 0x4b, 0x30, 0x6c, 0x57, 0x6a, - 0xcc, 0xdf, 0xca, 0x91, 0x72, 0x4b, 0x30, 0x6c, 0x57, 0x69, 0x69, 0x7e, 0xbe, 0xdb, 0xd3, 0xa9, - 0x81, 0x80, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xcb, 0xdd, 0xc8, 0x90, 0x71, 0x4a, 0x2f, 0x6b, 0x55, - 0x68, 0x56, 0x69, 0xac, 0xd4, 0xd9, 0xbb, 0x7a, 0x62, 0x3c, 0x30, 0x4c, 0x65, 0x7d, 0xbd, 0xda, - 0xd2, 0xa8, 0x80, 0x7f, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xca, 0xdd, 0xc8, 0x90, 0x71, 0x49, 0x2e, - 0x6a, 0x55, 0x67, 0xd3, 0xa9, 0x81, 0x80, 0x34, 0x33, 0x4c, 0x74, 0x94, 0xca, 0xde, 0xc8, 0x91, - 0x71, 0x4a, 0x2f, 0x6a, 0x56, 0x68, 0xbd, 0xda, 0xd2, 0xa8, 0x7f, 0x7e, 0x33, 0x32, 0x4b, 0x73, - 0x92, 0xc9, 0xdc, 0xc7, 0x8f, 0x70, 0x49, 0x2e, 0x69, 0x54, 0x67, 0x6a, 0x56, 0x68, 0x93, 0xca, - 0xdd, 0xc8, 0x90, 0x70, 0x49, 0x2e, 0x6a, 0x55, 0x68, 0x3d, 0x31, 0x4e, 0x67, 0x7f - -}, - -}; - -void upd1771c_reset(struct upd1771c_t *scv) { - memset(scv->upd1771c_packets,0,16); - scv->upd1771c_mode = 0; - scv->upd1771c_pos = 0; - scv->upd1771c_posc = 0; - scv->upd1771c_wave = 0; - scv->upd1771c_vol = 0; - scv->upd1771c_period = 0; - scv->upd1771c_off = 0; - scv->upd1771c_npos = 0; - //scv->upd1771c_repsamp = 0; -} - -void upd1771c_write_packet(struct upd1771c_t *scv, uint8_t ind, uint8_t val) { - scv->upd1771c_packets[ind&15] = val; - switch (scv->upd1771c_packets[0]) { - case 1: - if (ind == 3) { - scv->upd1771c_mode = 1; - scv->upd1771c_wave = (scv->upd1771c_packets[1]&0xe0)>>5; - scv->upd1771c_off = 0; //? - scv->upd1771c_period = scv->upd1771c_packets[2]; - scv->upd1771c_vol = scv->upd1771c_packets[3]&0x1f; - } - break; - case 2: - if (ind == 3) { - scv->upd1771c_mode = 2; - scv->upd1771c_wave = (scv->upd1771c_packets[1]&0xe0)>>5; - scv->upd1771c_off = scv->upd1771c_packets[1]&0x1f; - scv->upd1771c_period = scv->upd1771c_packets[2]<0x20?0x20:scv->upd1771c_packets[2]; - scv->upd1771c_vol = scv->upd1771c_packets[3]&0x1f; - } - break; - default: - case 0: - scv->upd1771c_mode = 0; - break; - } -} - -void upd1771c_sound_set_clock(struct upd1771c_t *scv, unsigned int clock, unsigned int divi) { - scv->upd1771c_repsamp = divi; -} - -int16_t upd1771c_sound_stream_update(struct upd1771c_t *scv) { - int16_t s = 0; - for (int i = 0; i < scv->upd1771c_repsamp; i++) { - s = 0; - switch (scv->upd1771c_mode) { - case 2: - s = ((int16_t)WAVEFORMS[scv->upd1771c_wave][scv->upd1771c_posc])*scv->upd1771c_vol; - scv->upd1771c_pos++; - if (scv->upd1771c_pos >= scv->upd1771c_period) { - scv->upd1771c_pos=0; - scv->upd1771c_posc++; - if (scv->upd1771c_posc == 32) - scv->upd1771c_posc = scv->upd1771c_off; - } - break; - case 1: - scv->upd1771c_pos++; - if (scv->upd1771c_pos >= ((((uint32_t)scv->upd1771c_period) + 1)*128)) { - scv->upd1771c_pos=0; - scv->upd1771c_posc++; - if (scv->upd1771c_posc == NOISE_SIZE) - scv->upd1771c_posc = 0; - } - uint16_t p = scv->upd1771c_posc; - p = p>=254?253:p; - s = ((int16_t)(noise_tbl[scv->upd1771c_wave][p])-127)*scv->upd1771c_vol; - // inaccurate noise mixing :/ - // s |= (scv->upd1771c_npos&128)?127*scv->upd1771c_vol:0; - break; - case 0: - default: - break; - } - } - return s; -} - diff --git a/src/engine/platform/sound/upd1771c.h b/src/engine/platform/sound/upd1771c.h deleted file mode 100644 index d0ea80f78..000000000 --- a/src/engine/platform/sound/upd1771c.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __UPD1771C_SOUND_H__ -#define __UPD1771C_SOUND_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -struct upd1771c_t { - uint8_t upd1771c_packets[16]; - uint8_t upd1771c_mode; - uint32_t upd1771c_pos; - uint8_t upd1771c_off; - uint8_t upd1771c_posc; - uint8_t upd1771c_wave; - uint8_t upd1771c_vol; - uint8_t upd1771c_period; - uint8_t upd1771c_npos; - int upd1771c_repsamp; -}; - -void upd1771c_reset(struct upd1771c_t *scv); -void upd1771c_write_packet(struct upd1771c_t *scv, uint8_t ind, uint8_t val); -int16_t upd1771c_sound_stream_update(struct upd1771c_t *scv); -void upd1771c_sound_set_clock(struct upd1771c_t *scv, unsigned int clock, unsigned int divi); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/src/engine/song.h b/src/engine/song.h index a32b519c0..b557fd5df 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -146,6 +146,7 @@ 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 49f05c67d..59b295aa5 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -2061,8 +2061,8 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_UPD1771C]=new DivSysDef( - _("NEC μPD1771C"), NULL, 0xe4, 0, 1, false, true, 0, false, 0, 0, 0, - _("this was an SoC with some funky wavetable/noise hardware"), + _("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}, @@ -2074,6 +2074,17 @@ 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")}, + {"W"}, + {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/about.cpp b/src/gui/about.cpp index b9574ea61..045343d34 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -139,6 +139,7 @@ const char* aboutLine[]={ _N("MAME YMZ280B core by Aaron Giles"), _N("MAME GA20 core by Acho A. Tang and R. Belmont"), _N("MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert"), + _N("MAME µPD1771C-017 HLE core by David Viens"), _N("SAASound by Dave Hooper and Simon Owen"), _N("SameBoy by Lior Halphon"), _N("Mednafen PCE, WonderSwan, T6W28 and Virtual Boy audio cores"), diff --git a/src/gui/gui.h b/src/gui/gui.h index 38b8f0f9a..dfebfebab 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -71,7 +71,7 @@ #define FM_PREVIEW_SIZE 512 #define CHECK_HIDDEN_SYSTEM(x) \ - (x==DIV_SYSTEM_YMU759 || x==DIV_SYSTEM_UPD1771C || x==DIV_SYSTEM_DUMMY || x==DIV_SYSTEM_SEGAPCM_COMPAT || x==DIV_SYSTEM_PONG) + (x==DIV_SYSTEM_YMU759 || x==DIV_SYSTEM_DUMMY || x==DIV_SYSTEM_SEGAPCM_COMPAT || x==DIV_SYSTEM_PONG) enum FurnaceGUIRenderBackend { GUI_BACKEND_SDL=0, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 561bb632f..bbe61c6e5 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -1320,6 +1320,7 @@ 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! }; @@ -1425,6 +1426,7 @@ 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 bb2b4cb39..6b3740f84 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1561,13 +1561,23 @@ void FurnaceGUI::initSystemPresets() { } ); ENTRY( - _("Sord M5"), { - CH(DIV_SYSTEM_SMS, 1.0f, 0, - "customClock=1773447\n" - "chipType=1\n" - ) - } - ); + _("Sord M5"), { + CH(DIV_SYSTEM_SMS, 1.0f, 0, + "customClock=1773447\n" + "chipType=1\n" + ) + } + ); + ENTRY( + "Epoch Super Cassette Vision (wave mode)", { + 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 f3aed6155..eb2aef8e0 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2649,6 +2649,7 @@ 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 3b71d9575..8dbbb6309 100644 --- a/src/gui/sysMiscInfo.cpp +++ b/src/gui/sysMiscInfo.cpp @@ -286,7 +286,8 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) { return "Watara Supervision"; break; case DIV_SYSTEM_UPD1771C: - return "μPD1771C"; + case DIV_SYSTEM_UPD1771C_TONE: + return "μPD1771C-017"; break; default: return FurnaceGUI::getSystemName(sys); diff --git a/src/main.cpp b/src/main.cpp index 217f37511..fce15ed5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -315,6 +315,7 @@ TAParamResult pVersion(String) { printf("- MAME YMZ280B core by Aaron Giles (BSD 3-clause)\n"); printf("- MAME GA20 core by Acho A. Tang and R. Belmont (BSD 3-clause)\n"); printf("- MAME SegaPCM core by Hiromitsu Shioya and Olivier Galibert (BSD 3-clause)\n"); + printf("- MAME µPD1771C-017 HLE core by David Viens (BSD 3-clause)\n"); printf("- QSound core by superctr (BSD 3-clause)\n"); printf("- VICE VIC-20 by Rami Rasanen and viznut (GPLv2)\n"); printf("- VICE TED by Andreas Boose, Tibor Biczo and Marco van den Heuvel (GPLv2)\n");