diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b6b92df..68f42e27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -524,6 +524,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 4fbb6c91..ec6f230a 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 1ec5aa30..29c08c2e 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 00000000..92b4759c --- /dev/null +++ b/papers/doc/7-systems/k007232.md @@ -0,0 +1,9 @@ +# Konami K007232 + +a Konami's 2 channel PCM sound chip was used in their arcade boards in 1986-1990. + +Its sample format is unique; the topmost bit is the end marker, and the low 7 bits are used for generating sound (unsigned format). + +# effects + +- Nothing for now diff --git a/papers/format.md b/papers/format.md index e29b1289..492544ec 100644 --- a/papers/format.md +++ b/papers/format.md @@ -1626,6 +1626,10 @@ chips which aren't on this list don't have any flags. - bit 16-19: outDepth (int) - bit 20: stereo (bool) +## (Placeholder): Konami K007232 + +- bit 0: stereo (bool) + ## 0xe0: QSound - bit 0-11: echoDelay (int) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 25055a90..3215914a 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -70,6 +70,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" @@ -418,6 +419,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/fileOps.cpp b/src/engine/fileOps.cpp index e01a5710..32cd0dcf 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1571,6 +1571,9 @@ void DivEngine::convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivS newFlags.set("echoDelay",(int)(oldFlags&0xfff)); newFlags.set("echoFeedback",(int)((oldFlags>>12)&255)); break; + case DIV_SYSTEM_K007232: + if (oldFlags&1) newFlags.set("stereo",true); + break; default: break; } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index dc991f6a..76168173 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 829223f2..a4c1effc 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 00000000..6dee4235 --- /dev/null +++ b/src/engine/platform/k007232.cpp @@ -0,0 +1,541 @@ +/** + * 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)*((regPool[0x11]>>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 signed int out[2]={(k007232.output(0)*(regPool[0xc]&0xf)),(k007232.output(1)*((regPool[0xc]>>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) { + if (stereo) { + chan[i].lvol=isMuted[i]?0:(((chan[i].outVol&0xf)*((chan[i].panning>>0)&0xf))/15); + chan[i].rvol=isMuted[i]?0:(((chan[i].outVol&0xf)*((chan[i].panning>>4)&0xf))/15); + rWrite(0x10+i,(chan[i].lvol&0xf)|((chan[i].rvol&0xf)<<4)); + } + else { + chan[i].lvol=chan[i].rvol=isMuted[i]?0:chan[i].outVol&0xf; + rWrite(0xc,regPool[0xc]&~(0xf<<(i<<2))|((chan[i].outVol&0xf)<<(i<<2))); + } + 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; + } + } + unsigned char loopon=regPool[0xd]|(1<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)); + } + if (s->isLoopable()) { + loop=start+s->loopStart; + rWrite(0xd,loopon); + } else { + rWrite(0xd,loopoff); + } + start=MIN(start,MIN(getSampleMemCapacity(),131072)-1); + loop=MIN(loop,MIN(getSampleMemCapacity(),131072)-1); + // force keyoff first + chWrite(i,0,0); + chWrite(i,1,0); + chWrite(i,2,0xff); + chWrite(i,3,0xff); + chWrite(i,4,0x1); + chWrite(i,5,0); + // keyon + rWrite(0x12+i,bank); + chWrite(i,0,chan[i].freq&0xff); + chWrite(i,1,(chan[i].freq>>8)&0xf); + chWrite(i,2,start&0xff); + chWrite(i,3,start>>8); + chWrite(i,4,start>>16); + chWrite(i,5,0); + if (s->isLoopable()) { + 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,0,0); + chWrite(i,1,0); + chWrite(i,2,0xff); + chWrite(i,3,0xff); + chWrite(i,4,0x1); + chWrite(i,5,0); + chan[i].keyOff=false; + } + if (chan[i].freqChanged) { + chWrite(i,0,chan[i].freq&0xff); + chWrite(i,1,(chan[i].freq>>8)&0xf); + 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: { + 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() { + 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() { + memset(regPool,0,32); + k007232.reset(); + 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 32; +} + +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; + } + + 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 { + int freq, baseFreq, pitch, pitch2; + unsigned int audPos; + int sample, wave, ins; + int note; + int panning; + bool active, insChanged, volumeChanged, freqChanged, keyOn, keyOff, inPorta, setPos; + int vol, outVol, lvol, rvol; + int macroVolMul; + DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + audPos(0), + sample(-1), + ins(-1), + note(0), + panning(255), + active(false), + insChanged(true), + volumeChanged(false), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + setPos(false), + vol(15), + outVol(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; + bool stereo; + + unsigned char* sampleMem; + size_t sampleMemLen; + k007232_core k007232; + unsigned char regPool[32]; + friend void putDispatchChip(void*,int); + friend void putDispatchChan(void*,int,int); + + 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) {} + private: + void chWrite(unsigned char ch, unsigned int addr, unsigned char val); +}; + +#endif diff --git a/src/engine/song.h b/src/engine/song.h index 589a1ea5..d63ab0ed 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -116,6 +116,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 9cd0b33f..0c7d8bf4 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, 0xc1/*Placeholder*/, 0, 2, false, true, 0, false, 1U<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) { @@ -4987,7 +4988,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) { @@ -5070,6 +5071,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; @@ -5159,7 +5161,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) { @@ -5268,7 +5270,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 6072570e..84e18b3c 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1143,6 +1143,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, "") diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1c8cebb5..dc143e39 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 170e2d8b..ebfca37d 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1546,6 +1546,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: