diff --git a/CMakeLists.txt b/CMakeLists.txt index 2035b83a7..3a549afbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,6 +525,7 @@ src/engine/platform/ymz280b.cpp src/engine/platform/namcowsg.cpp src/engine/platform/rf5c68.cpp src/engine/platform/snes.cpp +src/engine/platform/k007232.cpp src/engine/platform/pcmdac.cpp src/engine/platform/dummy.cpp ) diff --git a/papers/doc/6-sample/README.md b/papers/doc/6-sample/README.md index 4fbb6c914..ec6f230a6 100644 --- a/papers/doc/6-sample/README.md +++ b/papers/doc/6-sample/README.md @@ -25,6 +25,7 @@ as of Furnace 0.6, the following sound chips have sample support: - tildearrow Sound Unit - VERA (last channel only) - Y8950 (last channel only) +- Konami K007232 - a few more that I've forgotten to mention ## compatible sample mode diff --git a/papers/doc/7-systems/README.md b/papers/doc/7-systems/README.md index 1ec5aa305..29c08c2ee 100644 --- a/papers/doc/7-systems/README.md +++ b/papers/doc/7-systems/README.md @@ -12,6 +12,7 @@ this is a list of sound chips that Furnace supports, including effects. - [Generic PCM DAC](dac.md) - [Famicom Disk System](fds.md) - [Game Boy](game-boy.md) +- [Konami K007232](k007232.md) - [Konami SCC](scc.md) - [Konami VRC6](vrc6.md) - [Atari Lynx](lynx.md) diff --git a/papers/doc/7-systems/k007232.md b/papers/doc/7-systems/k007232.md new file mode 100644 index 000000000..adf7d95fb --- /dev/null +++ b/papers/doc/7-systems/k007232.md @@ -0,0 +1,11 @@ +# Konami K007232 + +a 2-channel PCM sound chip from Konami which was used in some of their 1986-1990 arcade boards. + +Its sample format is unique; the topmost bit is the end marker, and the low 7 bits are used for generating sound (unsigned format). + +It has 7 bit digital output per each channel and no volume register on chip, so it needs external logic to control channel volume. + +# effects + +- Nothing for now diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 029e1e85f..22a96c715 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -71,6 +71,7 @@ #include "platform/rf5c68.h" #include "platform/snes.h" #include "platform/vb.h" +#include "platform/k007232.h" #include "platform/pcmdac.h" #include "platform/dummy.h" #include "../ta-log.h" @@ -422,6 +423,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do case DIV_SYSTEM_SNES: dispatch=new DivPlatformSNES; break; + case DIV_SYSTEM_K007232: + dispatch=new DivPlatformK007232; + break; case DIV_SYSTEM_PCM_DAC: dispatch=new DivPlatformPCMDAC; break; diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index dc991f6ad..76168173f 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -911,6 +911,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { break; case DIV_INS_T6W28: break; + case DIV_INS_K007232: + featureSM=true; + featureSL=true; + break; case DIV_INS_MAX: break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 829223f22..a4c1effc8 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -75,6 +75,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_RF5C68=42, DIV_INS_MSM5232=43, DIV_INS_T6W28=44, + DIV_INS_K007232=45, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/k007232.cpp b/src/engine/platform/k007232.cpp new file mode 100644 index 000000000..f7feaebcb --- /dev/null +++ b/src/engine/platform/k007232.cpp @@ -0,0 +1,568 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "k007232.h" +#include "../engine.h" +#include "../../ta-log.h" +#include + +#define rWrite(a,v) {if(!skipRegisterWrites) {writes.emplace(a,v); if(dumpWrites) addWrite(a,v);}} + +#define CHIP_DIVIDER 64 + +const char* regCheatSheetK007232[]={ + // on-chip + "CHX_FreqL", "X*6+0", + "CHX_FreqH", "X*6+1", + "CHX_StartL", "X*6+2", + "CHX_StartM", "X*6+3", + "CHX_StartH", "X*6+4", + "CHX_Keyon", "X*6+5", + "SLEV", "C", // external IO + "Loop", "D", + // off-chip + "CHX_Volume", "X*2+10", + "CHX_Bank", "X*2+12", + NULL +}; + +const char** DivPlatformK007232::getRegisterSheet() { + return regCheatSheetK007232; +} + +inline void DivPlatformK007232::chWrite(unsigned char ch, unsigned int addr, unsigned char val) { + if (!skipRegisterWrites) { + if ((ch<2) && (addr<6)) { + rWrite((ch*6)+(addr&7),val); + } + } +} + +void DivPlatformK007232::acquire(short* bufL, short* bufR, size_t start, size_t len) { + for (size_t h=start; h>4)&0xf)),(k007232.output(1)*((vol2>>4)&0xf))}; + bufL[h]=(lout[0]+lout[1])<<4; + bufR[h]=(rout[0]+rout[1])<<4; + for (int i=0; i<2; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<4; + } + } else { + const unsigned char vol=regPool[0xc]; + const signed int out[2]={(k007232.output(0)*(vol&0xf)),(k007232.output(1)*((vol>>4)&0xf))}; + bufL[h]=bufR[h]=(out[0]+out[1])<<4; + for (int i=0; i<2; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<5; + } + } + } +} + +u8 DivPlatformK007232::read_sample(u8 ne, u32 address) { + if ((sampleMem!=NULL) && (addresscalcArp(chan[i].note,chan[i].std.arp.val)); + } + chan[i].freqChanged=true; + } + 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; + } + // volume and panning registers are off-chip + if (chan[i].std.panL.had) { + chan[i].panning&=0xf0; + chan[i].panning|=chan[i].std.panL.val&15; + if ((!isMuted[i]) && stereo) { + chan[i].volumeChanged=true; + } + } + if (chan[i].std.panR.had) { + chan[i].panning&=0x0f; + chan[i].panning|=(chan[i].std.panR.val&15)<<4; + if ((!isMuted[i]) && stereo) { + chan[i].volumeChanged=true; + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active) { + chan[i].audPos=0; + chan[i].setPos=true; + } + } + if (chan[i].volumeChanged) { + chan[i].resVol=isMuted[i]?0:chan[i].outVol&0xf; + if (stereo) { + chan[i].lvol=((chan[i].resVol&0xf)*((chan[i].panning>>0)&0xf))/15; + chan[i].rvol=((chan[i].resVol&0xf)*((chan[i].panning>>4)&0xf))/15; + const int newPan=(chan[i].lvol&0xf)|((chan[i].rvol&0xf)<<4); + if (chan[i].prevPan!=newPan) { + rWrite(0x10+i,(chan[i].lvol&0xf)|((chan[i].rvol&0xf)<<4)); + chan[i].prevPan=newPan; + } + } + else { + const unsigned char prevVolume=lastVolume; + lastVolume=(lastVolume&~(0xf<<(i<<2)))|((chan[i].resVol&0xf)<<(i<<2)); + if (prevVolume!=lastVolume) { + rWrite(0xc,lastVolume); + } + } + chan[i].volumeChanged=false; + } + if (chan[i].setPos) { + // force keyon + chan[i].keyOn=true; + chan[i].setPos=false; + } else { + chan[i].audPos=0; + } + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { + double off=1.0; + int sample=chan[i].sample; + if (sample>=0 && samplesong.sampleLen) { + DivSample* s=parent->getSample(sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/s->centerRate; + } + } + DivSample* s=parent->getSample(chan[i].sample); + chan[i].freq=0x1000-(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER)); + if (chan[i].freq>4095) chan[i].freq=4095; + if (chan[i].freq<0) chan[i].freq=0; + if (chan[i].keyOn) { + unsigned int bank=0; + unsigned int start=0; + unsigned int loop=0; + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + bank=sampleOffK007232[chan[i].sample]>>17; + start=sampleOffK007232[chan[i].sample]&0x1ffff; + loop=start+s->length8; + } + if (chan[i].audPos>0) { + start=start+MIN(chan[i].audPos,MIN(131072-1,s->length8)); + } + start=MIN(start,MIN(getSampleMemCapacity(),131072)-1); + loop=MIN(loop,MIN(getSampleMemCapacity(),131072)-1); + // force keyoff first + chWrite(i,2,0xff); + chWrite(i,3,0xff); + chWrite(i,4,0x1); + chWrite(i,5,0); + // keyon + const unsigned char prevLoop=lastLoop; + if (s->isLoopable()) { + loop=start+s->loopStart; + lastLoop|=(1<>8)&0xf); + chan[i].prevFreq=chan[i].freq; + } + chWrite(i,2,start&0xff); + chWrite(i,3,start>>8); + chWrite(i,4,start>>16); + chWrite(i,5,0); + if (s->isLoopable() && start!=loop) { + chWrite(i,2,loop&0xff); + chWrite(i,3,loop>>8); + chWrite(i,4,loop>>16); + } + if (!chan[i].std.vol.had) { + chan[i].outVol=chan[i].vol; + if (!isMuted[i]) { + chan[i].volumeChanged=true; + } + } + chan[i].keyOn=false; + } + if (chan[i].keyOff) { + chWrite(i,2,0xff); + chWrite(i,3,0xff); + chWrite(i,4,0x1); + chWrite(i,5,0); + const unsigned char prevLoop=lastLoop; + lastLoop&=~(1<>8)&0xf); + chan[i].prevFreq=chan[i].freq; + } + chan[i].freqChanged=false; + } + } + } +} + +int DivPlatformK007232::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15; + chan[c.chan].sample=ins->amiga.getSample(c.value); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } + if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { + chan[c.chan].sample=-1; + } + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + if (!isMuted[c.chan]) { + chan[c.chan].volumeChanged=true; + } + } + break; + } + case DIV_CMD_NOTE_OFF: + chan[c.chan].sample=-1; + 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; + } + 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 (!isMuted[c.chan]) { + chan[c.chan].volumeChanged=true; + } + } + } + break; + case DIV_CMD_GET_VOLUME: + if (chan[c.chan].std.vol.has) { + return chan[c.chan].vol; + } + return chan[c.chan].outVol; + break; + case DIV_CMD_PANNING: + chan[c.chan].panning=(c.value>>4)|(c.value2&0xf0); + if (!isMuted[c.chan] && stereo) { + chan[c.chan].volumeChanged=true; + } + break; + case DIV_CMD_PITCH: + chan[c.chan].pitch=c.value; + chan[c.chan].freqChanged=true; + break; + case DIV_CMD_NOTE_PORTA: { + const 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_LEGATO: { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(0))); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + break; + } + case DIV_CMD_PRE_PORTA: + if (chan[c.chan].active && c.value2) { + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); + } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); + chan[c.chan].inPorta=c.value; + break; + case DIV_CMD_SAMPLE_POS: + chan[c.chan].audPos=c.value; + chan[c.chan].setPos=true; + break; + case DIV_CMD_GET_VOLMAX: + return 255; + break; + case DIV_ALWAYS_SET_VOLUME: + return 1; + break; + default: + break; + } + return 1; +} + +void DivPlatformK007232::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + chan[ch].volumeChanged=true; +} + +void DivPlatformK007232::forceIns() { + while (!writes.empty()) writes.pop(); + for (int i=0; i<2; i++) { + chan[i].insChanged=true; + chan[i].freqChanged=true; + chan[i].sample=-1; + } +} + +void* DivPlatformK007232::getChanState(int ch) { + return &chan[ch]; +} + +DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) { + return &chan[ch].std; +} + +DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) { + return oscBuf[ch]; +} + +void DivPlatformK007232::reset() { + while (!writes.empty()) { + writes.pop(); + } + memset(regPool,0,20); + k007232.reset(); + lastLoop=0; + lastVolume=0; + for (int i=0; i<2; i++) { + chan[i]=DivPlatformK007232::Channel(); + chan[i].std.setEngine(parent); + // keyoff all channels + chWrite(i,0,0); + chWrite(i,1,0); + chWrite(i,2,0xff); + chWrite(i,3,0xff); + chWrite(i,4,1); + chWrite(i,5,0); + } +} + +bool DivPlatformK007232::isStereo() { + return stereo; +} + +void DivPlatformK007232::notifyInsChange(int ins) { + for (int i=0; i<2; i++) { + if (chan[i].ins==ins) { + chan[i].insChanged=true; + } + } +} + +void DivPlatformK007232::notifyWaveChange(int wave) { + // TODO when wavetables are added + // TODO they probably won't be added unless the samples reside in RAM +} + +void DivPlatformK007232::notifyInsDeletion(void* ins) { + for (int i=0; i<2; i++) { + chan[i].std.notifyInsDeletion((DivInstrument*)ins); + } +} + +void DivPlatformK007232::setFlags(const DivConfig& flags) { + chipClock=COLOR_NTSC; + CHECK_CUSTOM_CLOCK; + rate=chipClock/4; + stereo=flags.getBool("stereo",false); + for (int i=0; i<2; i++) { + oscBuf[i]->rate=rate; + } +} + +void DivPlatformK007232::poke(unsigned int addr, unsigned short val) { + rWrite(addr&0x1f,val); +} + +void DivPlatformK007232::poke(std::vector& wlist) { + for (DivRegWrite& i: wlist) rWrite(i.addr&0x1f,i.val); +} + +unsigned char* DivPlatformK007232::getRegisterPool() { + return regPool; +} + +int DivPlatformK007232::getRegisterPoolSize() { + return 20; +} + +const void* DivPlatformK007232::getSampleMem(int index) { + return index == 0 ? sampleMem : NULL; +} + +size_t DivPlatformK007232::getSampleMemCapacity(int index) { + return index == 0 ? 16777216 : 0; +} + +size_t DivPlatformK007232::getSampleMemUsage(int index) { + return index == 0 ? sampleMemLen : 0; +} + +bool DivPlatformK007232::isSampleLoaded(int index, int sample) { + if (index!=0) return false; + if (sample<0 || sample>255) return false; + return sampleLoaded[sample]; +} + +void DivPlatformK007232::renderSamples(int sysID) { + memset(sampleMem,0xc0,getSampleMemCapacity()); + memset(sampleOffK007232,0,256*sizeof(unsigned int)); + memset(sampleLoaded,0,256*sizeof(bool)); + + size_t memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + if (!s->renderOn[0][sysID]) { + sampleOffK007232[i]=0; + continue; + } + + const int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-1,length); + if (actualLength>0) { + if (actualLength>131072-1) { + actualLength=131072-1; + } + if ((memPos&0xfe0000)!=((memPos+actualLength+1)&0xfe0000)) { + memPos=(memPos+0x1ffff)&0xfe0000; + } + sampleOffK007232[i]=memPos; + for (int j=0; jdata8[j])^0x80; + sampleMem[memPos++]=(val>>1)&0x7f; + } + // write end of sample marker + memset(&sampleMem[memPos],0xc0,1); + memPos+=1; + } + if (actualLength +#include "../macroInt.h" +#include "vgsound_emu/src/k007232/k007232.hpp" + +class DivPlatformK007232: public DivDispatch, public k007232_intf { + struct Channel: public SharedChannel { + int prevFreq; + unsigned int audPos; + int prevBank; + int sample; + int panning, prevPan; + bool volumeChanged, setPos; + int resVol, lvol, rvol; + int macroVolMul; + Channel(): + SharedChannel(15), + prevFreq(-1), + audPos(0), + prevBank(-1), + sample(-1), + panning(255), + prevPan(-1), + volumeChanged(false), + setPos(false), + resVol(15), + lvol(15), + rvol(15), + macroVolMul(64) {} + }; + Channel chan[2]; + DivDispatchOscBuffer* oscBuf[2]; + bool isMuted[2]; + struct QueuedWrite { + unsigned short addr; + unsigned char val; + unsigned short delay; + QueuedWrite(unsigned short a, unsigned char v, unsigned short d=1): + addr(a), + val(v), + delay(d) {} + }; + std::queue writes; + unsigned int sampleOffK007232[256]; + bool sampleLoaded[256]; + + int delay; + unsigned char lastLoop, lastVolume; + bool stereo; + + unsigned char* sampleMem; + size_t sampleMemLen; + k007232_core k007232; + unsigned char regPool[20]; + friend void putDispatchChip(void*,int); + friend void putDispatchChan(void*,int,int); + + void chWrite(unsigned char ch, unsigned int addr, unsigned char val); + public: + u8 read_sample(u8 ne, u32 address); + void acquire(short* bufL, short* bufR, size_t start, 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); + bool isStereo(); + void setChipModel(int type); + void notifyInsChange(int ins); + void notifyWaveChange(int wave); + void notifyInsDeletion(void* ins); + void setFlags(const DivConfig& flags); + void poke(unsigned int addr, unsigned short val); + void poke(std::vector& wlist); + const char** getRegisterSheet(); + const void* getSampleMem(int index = 0); + size_t getSampleMemCapacity(int index = 0); + size_t getSampleMemUsage(int index = 0); + bool isSampleLoaded(int index, int sample); + void renderSamples(int chipID); + int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + void quit(); + DivPlatformK007232(): + DivDispatch(), + k007232_intf(), + k007232(*this) {} +}; + +#endif diff --git a/src/engine/song.h b/src/engine/song.h index 33e319b1d..44cdd9790 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -115,6 +115,7 @@ enum DivSystem { DIV_SYSTEM_YM2612_FRAC_EXT, DIV_SYSTEM_MSM5232, DIV_SYSTEM_T6W28, + DIV_SYSTEM_K007232, DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PONG, DIV_SYSTEM_DUMMY diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9cd0b33ff..d713a65b4 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1693,6 +1693,16 @@ void DivEngine::registerSystems() { {DIV_INS_AMIGA} ); + sysDefs[DIV_SYSTEM_K007232]=new DivSysDef( + "Konami K007232", NULL, 0xc6, 0, 2, false, true, 0, false, 1U<outStereo?colorOn:colorOff,">> OutStereo"); break; } + case DIV_SYSTEM_K007232: { + DivPlatformK007232* ch=(DivPlatformK007232*)data; + ImGui::Text("> K007232"); + COMMON_CHIP_DEBUG; + ImGui::Text("- delay: %.2x",ch->delay); + ImGui::Text("- lastLoop: %.2x",ch->lastLoop); + ImGui::Text("- lastVolume: %.2x",ch->lastVolume); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; @@ -883,6 +895,25 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos"); break; } + case DIV_SYSTEM_K007232: { + DivPlatformK007232::Channel* ch=(DivPlatformK007232::Channel*)data; + ImGui::Text("> K007232"); + COMMON_CHAN_DEBUG; + ImGui::Text("- prevFreq: %d",ch->prevFreq); + ImGui::Text("* Sample: %d",ch->sample); + ImGui::Text(" - pos: %d",ch->audPos); + ImGui::Text(" - prevBank: %d",ch->prevBank); + ImGui::Text("* panning: %d",ch->panning); + ImGui::Text(" - prev: %d",ch->prevPan); + ImGui::Text("- resVol: %.2x",ch->resVol); + ImGui::Text("- lvol: %.2x",ch->lvol); + ImGui::Text("- rvol: %.2x",ch->rvol); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + COMMON_CHAN_DEBUG_BOOL; + ImGui::TextColored(ch->volumeChanged?colorOn:colorOff,">> VolumeChanged"); + ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos"); + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 89c615645..362762da3 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1324,7 +1324,8 @@ void FurnaceGUI::doAction(int what) { i==DIV_INS_VRC6 || i==DIV_INS_SU || i==DIV_INS_SNES || - i==DIV_INS_ES5506) { + i==DIV_INS_ES5506 || + i==DIV_INS_K007232) { makeInsTypeList.push_back(i); } } diff --git a/src/gui/gui.h b/src/gui/gui.h index ec8f8b7f5..b2fe7f3e1 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -185,6 +185,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_RF5C68, GUI_COLOR_INSTR_MSM5232, GUI_COLOR_INSTR_T6W28, + GUI_COLOR_INSTR_K007232, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_BG, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index c5f86f175..ac68cb187 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -125,6 +125,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "RF5C68", "MSM5232", "T6W28", + "K007232", NULL }; @@ -808,6 +809,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.3f,0.3f,1.0f)), D(GUI_COLOR_INSTR_MSM5232,"",ImVec4(0.5f,0.9f,1.0f,1.0f)), D(GUI_COLOR_INSTR_T6W28,"",ImVec4(1.0f,0.8f,0.1f,1.0f)), + D(GUI_COLOR_INSTR_K007232,"",ImVec4(1.0f,0.8f,0.1f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), @@ -976,6 +978,7 @@ const int availableSystems[]={ DIV_SYSTEM_RF5C68, DIV_SYSTEM_SNES, DIV_SYSTEM_MSM5232, + DIV_SYSTEM_K007232, DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PONG, 0 // don't remove this last one! @@ -1075,6 +1078,7 @@ const int chipsSample[]={ DIV_SYSTEM_MSM6295, DIV_SYSTEM_RF5C68, DIV_SYSTEM_SNES, + DIV_SYSTEM_K007232, DIV_SYSTEM_PCM_DAC, 0 // don't remove this last one! }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8eb841c7f..c5b630a29 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4252,7 +4252,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_SU || ins->type==DIV_INS_SNES || - ins->type==DIV_INS_ES5506) { + ins->type==DIV_INS_ES5506 || + ins->type==DIV_INS_K007232) { if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { @@ -4994,7 +4995,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM || - ins->type==DIV_INS_FM) { + ins->type==DIV_INS_FM || ins->type==DIV_INS_K007232) { dutyMax=0; } if (ins->type==DIV_INS_VBOY) { @@ -5077,6 +5078,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_MSM6258) waveMax=0; if (ins->type==DIV_INS_MSM6295) waveMax=0; if (ins->type==DIV_INS_SEGAPCM) waveMax=0; + if (ins->type==DIV_INS_K007232) waveMax=0; if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; @@ -5166,7 +5168,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_RF5C68 || - ins->type==DIV_INS_VBOY || ins->type==DIV_INS_T6W28) { + ins->type==DIV_INS_VBOY || ins->type==DIV_INS_T6W28 || ins->type==DIV_INS_K007232) { panMax=15; } if (ins->type==DIV_INS_SEGAPCM) { @@ -5275,7 +5277,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_ES5506 || ins->type==DIV_INS_T6W28 || ins->type==DIV_INS_VBOY || - (ins->type==DIV_INS_X1_010 && ins->amiga.useSample)) { + (ins->type==DIV_INS_X1_010 && ins->amiga.useSample) || + ins->type==DIV_INS_K007232) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 186abc482..66e6c6e9a 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1153,6 +1153,11 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_SNES, 64, 0, "") } ); + ENTRY( + "Konami K007232", { + CH(DIV_SYSTEM_K007232, 64, 0, "") + } + ); ENTRY( "Generic PCM DAC", { CH(DIV_SYSTEM_PCM_DAC, 64, 0, "") @@ -1336,6 +1341,12 @@ void FurnaceGUI::initSystemPresets() { // VLM5030 exists but not used for music at all } ); + ENTRY( + "Konami MX5000", { + CH(DIV_SYSTEM_YM2151, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); ENTRY( "Konami Battlantis", { CH(DIV_SYSTEM_OPL2, 64, 0, "clockSel=3"), // 3MHz @@ -1360,6 +1371,54 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, "clockSel=3") // "" } ); + ENTRY( + "Konami Fast Lane", { + CH(DIV_SYSTEM_K007232, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); + ENTRY( + "Konami Chequered Flag", { + CH(DIV_SYSTEM_YM2151, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, "stereo=true"), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); + ENTRY( + "Konami Haunted Castle", { + CH(DIV_SYSTEM_OPL2, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_SCC, 64, 0, ""), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); + ENTRY( + "Konami Haunted Castle (drums mode)", { + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_SCC, 64, 0, ""), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); + ENTRY( + "Konami Hot Chase", { + CH(DIV_SYSTEM_K007232, 64, 0, "stereo=true"), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, "stereo=true"), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "stereo=true") // "" + } + ); + ENTRY( + "Konami S.P.Y.", { + CH(DIV_SYSTEM_OPL2, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, ""), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); + ENTRY( + "Konami S.P.Y. (drums mode)", { + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K007232, 64, 0, ""), // "" + CH(DIV_SYSTEM_K007232, 64, 0, "") // "" + } + ); ENTRY( "Konami Hexion", { CH(DIV_SYSTEM_SCC, 64, 0, "clockSel=2"), // 1.5MHz (3MHz input) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index a7476e93d..db8906209 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1787,6 +1787,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_QSOUND,"QSound"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_YMZ280B,"YMZ280B"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_RF5C68,"RF5C68"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_K007232,"K007232"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); ImGui::TreePop(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 4025682a8..6702f6cb3 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1547,6 +1547,20 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } break; } + case DIV_SYSTEM_K007232: { + bool stereo=flags.getBool("stereo",false); + + if (ImGui::Checkbox("Stereo",&stereo)) { + altered=true; + } + + if (altered) { + e->lockSave([&]() { + flags.set("stereo",stereo); + }); + } + break; + } case DIV_SYSTEM_SWAN: case DIV_SYSTEM_BUBSYS_WSG: case DIV_SYSTEM_PET: