From d7984896d8cd1a38c3809f7babff802ba0171966 Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Fri, 28 Mar 2025 05:43:20 +0700 Subject: [PATCH] Add Kurumitsu-8L support No sample playback yet --- CMakeLists.txt | 1 + src/engine/dispatchContainer.cpp | 4 + src/engine/instrument.h | 1 + src/engine/platform/kurumitsu8l.cpp | 496 ++++++++++++++++++++++++++++ src/engine/platform/kurumitsu8l.h | 78 +++++ src/engine/song.h | 1 + src/engine/sysDef.cpp | 15 + src/gui/gui.h | 1 + src/gui/guiConst.cpp | 4 + src/gui/insEdit.cpp | 14 +- src/gui/presets.cpp | 5 + src/gui/sysConf.cpp | 1 + 12 files changed, 620 insertions(+), 1 deletion(-) create mode 100644 src/engine/platform/kurumitsu8l.cpp create mode 100644 src/engine/platform/kurumitsu8l.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 179b27c11..a5ee7cc9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -814,6 +814,7 @@ src/engine/platform/nds.cpp src/engine/platform/bifurcator.cpp src/engine/platform/sid2.cpp src/engine/platform/sid3.cpp +src/engine/platform/kurumitsu8l.cpp src/engine/platform/pcmdac.cpp src/engine/platform/dummy.cpp diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 23cbde76b..cf3feea0d 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -93,6 +93,7 @@ #include "platform/bifurcator.h" #include "platform/sid2.h" #include "platform/sid3.h" +#include "platform/kurumitsu8l.h" #include "platform/dummy.h" #include "../ta-log.h" #include "song.h" @@ -787,6 +788,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do ((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl4Core",0)); } break; + case DIV_SYSTEM_KURUMITSU_8L: + dispatch=new DivPlatformKurumitsu8L; + break; case DIV_SYSTEM_DUMMY: dispatch=new DivPlatformDummy; break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 2c7d91be7..125a7f15d 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -99,6 +99,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_SUPERVISION=64, DIV_INS_UPD1771C=65, DIV_INS_SID3=66, + DIV_INS_KURUMITSU_8L=67, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/kurumitsu8l.cpp b/src/engine/platform/kurumitsu8l.cpp new file mode 100644 index 000000000..c13b27338 --- /dev/null +++ b/src/engine/platform/kurumitsu8l.cpp @@ -0,0 +1,496 @@ +/** + * 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 "kurumitsu8l.h" +#include "../engine.h" +#include + +#define chRead(c,a) regPool[(c)*16+(a)] +#define chWrite(c,a,v) if (!skipRegisterWrites) {regPool[(c)*16+(a)]=v; if (dumpWrites) {addWrite(a,v);} } + +#define CHIP_FREQBASE 67108864 + +const char* regCheatSheetKurumitsu8L[]={ + "CHxAtt", "00+x*10", + "CHxPanL", "01+x*10", + "CHxPanR", "02+x*10", + "CHxMod", "03+x*10", + "CHxFreq", "04+x*10", + "CHxAcc", "08+x*10", + "CHxLoopS", "0C+x*10", + "CHxLoopE", "0E+x*10", + NULL +}; + +const char** DivPlatformKurumitsu8L::getRegisterSheet() { + return regCheatSheetKurumitsu8L; +} + +void DivPlatformKurumitsu8L::acquire(short** buf, size_t len) { + const int volTab[32]={ + 32767, 32064, 31377, 30705, 30047, 29403, 28773, 28156, 27553, 26963, 26385, 25820, 25266, 24725, 24195, 23677, 23169, 22673, 22187, 21712, 21246, 20791, 20345, 19910, 19483, 19065, 18657, 18257, 17866, 17483, 17108, 16742 + }; + + for (int i=0; i<8; i++) { + oscBuf[i]->begin(len); + } + + for (size_t h=0; h>4)&0xf; + unsigned freq=chRead(i,4)|((unsigned)chRead(i,5)<<8)|((unsigned)chRead(i,6)<<16)|((unsigned)chRead(i,7)<<24); + unsigned phase=chRead(i,8)|((unsigned)chRead(i,9)<<8)|((unsigned)chRead(i,10)<<16)|((unsigned)chRead(i,11)<<24); + int fbData=chRead(i,13)|((unsigned)chRead(i,14)<<8); + if (fbData>=0x8000) fbData-=0x10000; + + unsigned phase_modded=phase; + phase_modded+=(fbData<<8)>>fb; + phase_modded+=(modData<<8)>>mod; + phase+=freq; + + unsigned char data=wtMem[i][(phase_modded>>16)&255]; + int out=(data>>1)+vol; + out=volTab[out&0x1f]>>(out>>5); + if (data&1) out=-out; + fbData=out; + modData=out; + outAL+=out*panL; + outAR+=out*panR; + oscBuf[i]->putSample(h,(out*((int)panL+panR))>>9); + + chWrite(i,8,phase&0xff); + chWrite(i,9,(phase>>8)&0xff); + chWrite(i,10,(phase>>16)&0xff); + chWrite(i,11,(phase>>24)&0xff); + chWrite(i,13,fbData&0xff); + chWrite(i,14,(fbData>>8)&0xff); + chWrite(i,15,(fbData>>16)&0xff); + } + buf[0][h]=outAL>>11; + buf[1][h]=outAR>>11; + } + + for (int i=0; i<8; i++) { + oscBuf[i]->end(len); + } +} + +void DivPlatformKurumitsu8L::updateWave(int ch) { + for (int i=0; i<256; i++) { + int data=chan[ch].ws.output[i]-128; + unsigned char val=0; + if (data<0) { + val|=1; + data=-data; + } + // convert to log attenuation format + if (data>0) { + val|=((unsigned char)MIN(roundf((7.f-log2f(data))*32.f),127.f))<<1; + } else { + val|=0xfe; + } + wtMem[ch][i]=val; + } +} + +void DivPlatformKurumitsu8L::tick(bool sysTick) { + for (int i=0; i<8; i++) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,chan[i].std.vol.val,255); + if (!isMuted[i] && chan[i].active) { + chWrite(i,0,~chan[i].outVol&255); + } + } + if (NEW_ARP_STRAT) { + chan[i].handleArp(); + } else if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val)); + } + chan[i].freqChanged=true; + } + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; + chan[i].ws.changeWave1(chan[i].wave); + if (!chan[i].keyOff) chan[i].keyOn=true; + } + } + if (chan[i].std.panL.had) { + chan[i].panL=chan[i].std.panL.val; + if (!isMuted[i] && chan[i].active) { + chWrite(i,1,chan[i].panL); + } + } + if (chan[i].std.panR.had) { + chan[i].panR=chan[i].std.panR.val; + if (!isMuted[i] && chan[i].active) { + chWrite(i,2,chan[i].panR); + } + } + 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,-1048575,1048575); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1) { + chWrite(i,8,0); + chWrite(i,9,0); + chWrite(i,10,0); + chWrite(i,11,0); + } + } + if (chan[i].std.ex1.had) { + unsigned char val=chRead(i,3)&0xf0; + chWrite(i,3,val|(~chan[i].std.ex1.val&0xf)); + } + if (chan[i].std.ex2.had) { + unsigned char val=chRead(i,3)&0x0f; + chWrite(i,3,val|((~chan[i].std.ex2.val&0xf)<<4)); + } + if (chan[i].active) { + if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) { + updateWave(i); + } + } + if (chan[i].freqChanged) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); + if (chan[i].freq<0) chan[i].freq=0; + if (chan[i].freq>8388608) chan[i].freq=8388608; + chWrite(i,4,chan[i].freq&0xff); + chWrite(i,5,(chan[i].freq>>8)&0xff); + chWrite(i,6,(chan[i].freq>>16)&0xff); + chWrite(i,7,(chan[i].freq>>24)&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].keyOff) { + if (!chan[i].std.vol.had) { + chan[i].outVol=chan[i].vol; + } + if (!isMuted[i] && chan[i].active) { + chWrite(i,0,~chan[i].outVol&255); + chWrite(i,1,chan[i].panL); + chWrite(i,2,chan[i].panR); + } else { + chWrite(i,0,255); + chWrite(i,1,0); + chWrite(i,2,0); + } + if (chan[i].keyOn) chan[i].keyOn=false; + if (chan[i].keyOff) chan[i].keyOff=false; + } + } +} + +int DivPlatformKurumitsu8L::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + 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].active) { + chWrite(c.chan,0,~chan[c.chan].outVol&255); + } + } + if (chan[c.chan].wave<0) { + chan[c.chan].wave=0; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); + } + chan[c.chan].ws.init(ins,256,255,chan[c.chan].insChanged); + chan[c.chan].insChanged=false; + break; + } + case DIV_CMD_NOTE_OFF: + 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 (!isMuted[c.chan] && chan[c.chan].active) { + chWrite(c.chan,0,~chan[c.chan].outVol&255); + } + } + } + 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_WAVE: + chan[c.chan].wave=c.value; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); + chan[c.chan].keyOn=true; + break; + case DIV_CMD_NOTE_PORTA: { + int destFreq=NOTE_FREQUENCY(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:8); + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:8); + 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_PANNING: { + chan[c.chan].panL=c.value; + chan[c.chan].panR=c.value2; + if (!isMuted[c.chan] && chan[c.chan].active) { + chWrite(c.chan,1,chan[c.chan].panL); + chWrite(c.chan,2,chan[c.chan].panR); + } + break; + } + case DIV_CMD_LEGATO: + chan[c.chan].baseFreq=NOTE_FREQUENCY(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_PCE)); + } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); + chan[c.chan].inPorta=c.value; + break; + case DIV_CMD_FM_FB: { + unsigned char val=chRead(c.chan,3)&0xf0; + chWrite(c.chan,3,val|(~c.value&0xf)); + break; + } + case DIV_CMD_FM_PM_DEPTH: { + unsigned char val=chRead(c.chan,3)&0x0f; + chWrite(c.chan,3,val|((~c.value&0xf)<<4)); + break; + } + case DIV_CMD_GET_VOLMAX: + return 255; + break; + case DIV_CMD_MACRO_OFF: + chan[c.chan].std.mask(c.value,true); + break; + case DIV_CMD_MACRO_ON: + chan[c.chan].std.mask(c.value,false); + break; + case DIV_CMD_MACRO_RESTART: + chan[c.chan].std.restart(c.value); + break; + default: + break; + } + return 1; +} + +void DivPlatformKurumitsu8L::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + if (!mute && chan[ch].active) { + chWrite(ch,0,~chan[ch].outVol&255); + chWrite(ch,1,chan[ch].panL); + chWrite(ch,2,chan[ch].panR); + } else { + chWrite(ch,0,255); + chWrite(ch,1,0); + chWrite(ch,2,0); + } +} + +void DivPlatformKurumitsu8L::forceIns() { + for (int i=0; i<8; i++) { + chan[i].insChanged=true; + chan[i].freqChanged=true; + updateWave(i); + } +} + +void* DivPlatformKurumitsu8L::getChanState(int ch) { + return &chan[ch]; +} + +DivMacroInt* DivPlatformKurumitsu8L::getChanMacroInt(int ch) { + return &chan[ch].std; +} + +unsigned short DivPlatformKurumitsu8L::getPan(int ch) { + return (chRead(ch,1)<<8)|chRead(ch,2); +} + +void DivPlatformKurumitsu8L::getPaired(int ch, std::vector& ret) { + unsigned char mod=~(chRead(ch,3)>>4)&0xf; + if (mod>0) { + sprintf(modLabel[ch],"%d",mod); + if (ch==0){ + ret.push_back(DivChannelPair(modLabel[ch],7)); + } else { + ret.push_back(DivChannelPair(modLabel[ch],ch-1)); + } + } +} + +DivDispatchOscBuffer* DivPlatformKurumitsu8L::getOscBuffer(int ch) { + return oscBuf[ch]; +} + +unsigned char* DivPlatformKurumitsu8L::getRegisterPool() { + return regPool; +} + +int DivPlatformKurumitsu8L::getRegisterPoolSize() { + return 16*8; +} + +void DivPlatformKurumitsu8L::reset() { + memset(regPool,0,sizeof(regPool)); + memset(wtMem,0xff,sizeof(wtMem)); + for (int i=0; i<8; i++) { + chan[i]=DivPlatformKurumitsu8L::Channel(); + chan[i].std.setEngine(parent); + chan[i].ws.setEngine(parent); + chan[i].ws.init(NULL,256,255,false); + chWrite(i,3,0xff); // set mod to min + } + modData=0; + if (dumpWrites) { + addWrite(0xffffffff,0); + } +} + +int DivPlatformKurumitsu8L::getOutputCount() { + return 2; +} + +bool DivPlatformKurumitsu8L::keyOffAffectsArp(int ch) { + return true; +} + +void DivPlatformKurumitsu8L::notifyWaveChange(int wave) { + for (int i=0; i<8; i++) { + if (chan[i].wave==wave) { + chan[i].ws.changeWave1(wave); + updateWave(i); + } + } +} + +void DivPlatformKurumitsu8L::notifyInsDeletion(void* ins) { + for (int i=0; i<8; i++) { + chan[i].std.notifyInsDeletion((DivInstrument*)ins); + } +} + +int DivPlatformKurumitsu8L::mapVelocity(int ch, float vel) { + // -0.19dB per step + if (vel==0) return 0; + if (vel>=1.0) return 255; + return CLAMP(roundf(256.f-(32.f-log2f(vel)*32.f)),0,255); +} + +void DivPlatformKurumitsu8L::setFlags(const DivConfig& flags) { + chipClock=6144000; + CHECK_CUSTOM_CLOCK; + rate=chipClock/64; + for (int i=0; i<8; i++) { + oscBuf[i]->setRate(rate); + } +} + +void DivPlatformKurumitsu8L::poke(unsigned int addr, unsigned short val) { + chWrite((addr>>4)&7,addr&0xf,val); +} + +void DivPlatformKurumitsu8L::poke(std::vector& wlist) { + for (DivRegWrite& i: wlist) chWrite((i.addr>>4)&7,i.addr&0xf,i.val); +} + +int DivPlatformKurumitsu8L::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + memset(modLabel,0,sizeof(modLabel)); + for (int i=0; i<8; i++) { + isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; + } + setFlags(flags); + reset(); + return 8; +} + +void DivPlatformKurumitsu8L::quit() { + for (int i=0; i<8; i++) { + delete oscBuf[i]; + } +} + +DivPlatformKurumitsu8L::~DivPlatformKurumitsu8L() { +} diff --git a/src/engine/platform/kurumitsu8l.h b/src/engine/platform/kurumitsu8l.h new file mode 100644 index 000000000..52eb7c16a --- /dev/null +++ b/src/engine/platform/kurumitsu8l.h @@ -0,0 +1,78 @@ +/** + * 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 _KURUMITSU_8L_H +#define _KURUMITSU_8L_H + +#include "../dispatch.h" +#include "../../fixedQueue.h" +#include "../waveSynth.h" + +class DivPlatformKurumitsu8L: public DivDispatch { + struct Channel: public SharedChannel { + unsigned char panL; + unsigned char panR; + signed short wave; + DivWaveSynth ws; + Channel(): + SharedChannel(255), + panL(255), + panR(255), + wave(-1) {} + }; + Channel chan[8]; + DivDispatchOscBuffer* oscBuf[8]; + bool isMuted[8]; + + unsigned char regPool[8*16]; + unsigned char wtMem[8][256]; + char modLabel[8][4]; + int modData; + void updateWave(int ch); + 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); + unsigned short getPan(int chan); + void getPaired(int ch, std::vector& ret); + 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 notifyWaveChange(int wave); + void notifyInsDeletion(void* ins); + int mapVelocity(int ch, float vel); + 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(); + ~DivPlatformKurumitsu8L(); +}; + +#endif diff --git a/src/engine/song.h b/src/engine/song.h index e13d8b101..03d0e27f5 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_KURUMITSU_8L, DIV_SYSTEM_MAX }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index e3971a2c6..73607ac7a 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -2342,6 +2342,21 @@ void DivEngine::registerSystems() { {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD} ); + sysDefs[DIV_SYSTEM_KURUMITSU_8L]=new DivSysDef( + _("Kurumitsu-8L"), NULL, 0xfe, 0, 8, false, true, 0, false, 1U<id!=0) { diff --git a/src/gui/gui.h b/src/gui/gui.h index a50b21c92..08729cb3c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -363,6 +363,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SUPERVISION, GUI_COLOR_INSTR_UPD1771C, GUI_COLOR_INSTR_SID3, + GUI_COLOR_INSTR_KURUMITSU_8L, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_BG, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 40938b42d..825db3c63 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -187,6 +187,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={ {"Watara Supervision",ICON_FA_GAMEPAD,ICON_FUR_INS_SUPERVISION}, {"NEC μPD1771C",ICON_FA_BAR_CHART,ICON_FUR_INS_UPD1771C}, {"SID3",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID3}, + {"Kurumitsu-8L",ICON_FA_CALCULATOR,ICON_FA_QUESTION}, {NULL,ICON_FA_QUESTION,ICON_FA_QUESTION} }; @@ -1063,6 +1064,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SUPERVISION,"",ImVec4(0.52f,1.0f,0.6f,1.0f)), D(GUI_COLOR_INSTR_UPD1771C,"",ImVec4(0.94f,0.52f,0.6f,1.0f)), D(GUI_COLOR_INSTR_SID3,"",ImVec4(0.6f,0.75f,0.6f,1.0f)), + D(GUI_COLOR_INSTR_KURUMITSU_8L,"",ImVec4(0.9f,0.3f,0.3f,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)), @@ -1321,6 +1323,7 @@ const int availableSystems[]={ DIV_SYSTEM_SUPERVISION, DIV_SYSTEM_UPD1771C, DIV_SYSTEM_SID3, + DIV_SYSTEM_KURUMITSU_8L, 0 // don't remove this last one! }; @@ -1394,6 +1397,7 @@ const int chipsWave[]={ DIV_SYSTEM_NAMCO, DIV_SYSTEM_NAMCO_15XX, DIV_SYSTEM_NAMCO_CUS30, + DIV_SYSTEM_KURUMITSU_8L, 0 // don't remove this last one! }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index e2ff1867a..64064e86b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -8000,7 +8000,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SNES || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_SM8521 || - (ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave)) + (ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave) || + ins->type==DIV_INS_KURUMITSU_8L) { insTabWavetable(ins); } @@ -8685,6 +8686,17 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(_("Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); } break; + case DIV_INS_KURUMITSU_8L: + macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME])); + macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); + macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); + macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL)); + macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(_("Feedback"),&ins->std.ex1Macro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,NULL)); + macroList.push_back(FurnaceGUIMacroDesc(_("Modulation"),&ins->std.ex2Macro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,NULL)); + break; case DIV_INS_MAX: case DIV_INS_NULL: break; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 4e0d11d93..3937ad4bb 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -3611,6 +3611,11 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_X1_010, 1.0f, 0, "") } ); + ENTRY( + _("Kurumitsu-8L"), { + CH(DIV_SYSTEM_KURUMITSU_8L, 1.0f, 0, "") + } + ); CATEGORY_END; CATEGORY_BEGIN(_("Specialized"),_("chips/systems with unique sound synthesis methods.")); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b36e5f32a..ba64cf487 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2722,6 +2722,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_KURUMITSU_8L: break; case DIV_SYSTEM_YMU759: case DIV_SYSTEM_ESFM: