diff --git a/CMakeLists.txt b/CMakeLists.txt index 78a68aa8..7105990b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -551,6 +551,7 @@ src/engine/platform/k007232.cpp src/engine/platform/ga20.cpp src/engine/platform/sm8521.cpp src/engine/platform/pv1000.cpp +src/engine/platform/k053260.cpp src/engine/platform/pcmdac.cpp src/engine/platform/dummy.cpp diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp index bf056b81..2ee4efac 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.cpp @@ -8,18 +8,19 @@ #include "k053260.hpp" -void k053260_core::tick() +void k053260_core::tick(u32 cycle) { m_out[0] = m_out[1] = 0; if (m_ctrl.sound_en()) { for (int i = 0; i < 4; i++) { - m_voice[i].tick(); + m_voice[i].tick(cycle); m_out[0] += m_voice[i].out(0); m_out[1] += m_voice[i].out(1); } } + /* // dac clock (YM3012 format) u8 dac_clock = m_dac.clock(); if (bitfield(++dac_clock, 0, 4) == 0) @@ -34,62 +35,59 @@ void k053260_core::tick() m_dac.set_state(bitfield(dac_state, 0, 2)); } m_dac.set_clock(bitfield(dac_clock, 0, 4)); + */ } -void k053260_core::voice_t::tick() +void k053260_core::voice_t::tick(u32 cycle) { if (m_enable && m_busy) { bool update = false; // update counter - if (bitfield(++m_counter, 0, 12) == 0) + m_counter += cycle; + if (m_counter >= 0x1000) { if (m_bitpos < 8) { m_bitpos += 8; m_addr = bitfield(m_addr + 1, 0, 21); m_remain--; + if (m_remain < 0) // check end flag + { + if (m_loop) + { + m_addr = m_start; + m_remain = m_length; + m_output = 0; + } + else + { + m_busy = false; + } + } } + m_data = m_host.m_intf.read_sample(bitfield(m_addr, 0, 21)); // fetch ROM if (m_adpcm) { - m_bitpos -= 4; - update = true; + m_bitpos -= 4; + const u8 nibble = bitfield(m_data, m_bitpos & 4, 4); // get nibble from ROM + if (nibble) + { + m_output += m_host.adpcm_lut(nibble); + } } else { m_bitpos -= 8; } - m_counter = bitfield(m_pitch, 0, 12); - } - m_data = m_host.m_intf.read_sample(bitfield(m_addr, 0, 21)); // fetch ROM - if (update) - { - const u8 nibble = bitfield(m_data, m_bitpos & 4, 4); // get nibble from ROM - if (nibble) - { - m_adpcm_buf += bitfield(nibble, 3) ? s8(0x80 >> bitfield(nibble, 0, 3)) - : (1 << bitfield(nibble - 1, 0, 3)); - } + m_counter = 0x1000 - bitfield(m_pitch, 0, 12); } - if (m_remain < 0) // check end flag - { - if (m_loop) - { - m_addr = m_start; - m_remain = m_length; - m_adpcm_buf = 0; - } - else - { - m_busy = false; - } - } // calculate output - s32 output = m_adpcm ? m_adpcm_buf : sign_ext(m_data, 8) * s32(m_volume); + s32 output = (m_adpcm ? m_output : sign_ext(m_data, 8)) * s32(m_volume); // use math for now; actually fomula unknown - m_out[0] = (m_pan >= 0) ? s32(output * cos(f64(m_pan) * PI / 180)) : 0; - m_out[1] = (m_pan >= 0) ? s32(output * sin(f64(m_pan) * PI / 180)) : 0; + m_out[0] = (output * m_host.pan_lut(m_pan, 0)) >> 7; + m_out[1] = (output * m_host.pan_lut(m_pan, 1)) >> 7; } else { @@ -244,7 +242,8 @@ void k053260_core::voice_t::keyon() m_addr = m_start; m_remain = m_length; m_bitpos = 4; - m_adpcm_buf = 0; + m_data = 0; + m_output = 0; std::fill(m_out.begin(), m_out.end(), 0); } @@ -259,12 +258,12 @@ void k053260_core::reset() elem.reset(); } - m_intf.write_int(0); + //m_intf.write_int(0); std::fill(m_host2snd.begin(), m_host2snd.end(), 0); std::fill(m_snd2host.begin(), m_snd2host.end(), 0); m_ctrl.reset(); - m_dac.reset(); + //m_dac.reset(); std::fill(m_reg.begin(), m_reg.end(), 0); std::fill(m_out.begin(), m_out.end(), 0); @@ -273,20 +272,20 @@ void k053260_core::reset() // reset voice void k053260_core::voice_t::reset() { - m_enable = 0; - m_busy = 0; - m_loop = 0; - m_adpcm = 0; - m_pitch = 0; - m_start = 0; - m_length = 0; - m_volume = 0; - m_pan = -1; - m_counter = 0; - m_addr = 0; - m_remain = 0; - m_bitpos = 4; - m_data = 0; - m_adpcm_buf = 0; + m_enable = 0; + m_busy = 0; + m_loop = 0; + m_adpcm = 0; + m_pitch = 0; + m_start = 0; + m_length = 0; + m_volume = 0; + m_pan = 4; + m_counter = 0; + m_addr = 0; + m_remain = 0; + m_bitpos = 4; + m_data = 0; + m_output = 0; m_out[0] = m_out[1] = 0; } diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp index a8668a0d..feaffeac 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/k053260/k053260.hpp @@ -25,7 +25,7 @@ class k053260_intf : public vgsound_emu_core virtual u8 read_sample(u32 address) { return 0; } // sample fetch - virtual void write_int(u8 out) {} // timer interrupt + //virtual void write_int(u8 out) {} // timer interrupt }; class k053260_core : public vgsound_emu_core @@ -33,7 +33,19 @@ class k053260_core : public vgsound_emu_core friend class k053260_intf; // k053260 specific interface private: - const int pan_dir[8] = {-1, 0, 24, 35, 45, 55, 66, 90}; // pan direction + const s32 m_pan_lut[8][2] = { + {0x00, 0x00}, + {0x7f, 0x00}, + {0x74, 0x34}, + {0x68, 0x49}, + {0x5a, 0x5a}, + {0x49, 0x68}, + {0x34, 0x74}, + {0x00, 0x7f} + }; // pan LUT + + const s8 m_adpcm_lut[16] = + {0, 1, 2, 4, 8, 16, 32, 64, -128, -64, -32, -16, -8, -4, -2, -1}; // ADPCM LUT class voice_t : public vgsound_emu_core { @@ -50,20 +62,20 @@ class k053260_core : public vgsound_emu_core , m_start(0) , m_length(0) , m_volume(0) - , m_pan(-1) + , m_pan(4) , m_counter(0) , m_addr(0) , m_remain(0) , m_bitpos(4) , m_data(0) - , m_adpcm_buf(0) + , m_output(0) { m_out.fill(0); } // internal state void reset(); - void tick(); + void tick(u32 cycle); // accessors void write(u8 address, u8 data); @@ -81,7 +93,7 @@ class k053260_core : public vgsound_emu_core inline void length_inc() { m_length = (m_length + 1) & 0xffff; } - inline void set_pan(u8 pan) { m_pan = m_host.pan_dir[pan & 7]; } + inline void set_pan(u8 pan) { m_pan = pan & 7; } // getters inline bool enable() { return m_enable; } @@ -97,21 +109,21 @@ class k053260_core : public vgsound_emu_core private: // registers k053260_core &m_host; - u16 m_enable : 1; // enable flag - u16 m_busy : 1; // busy status - u16 m_loop : 1; // loop flag - u16 m_adpcm : 1; // ADPCM flag - u16 m_pitch : 12; // pitch - u32 m_start = 0; // start position - u16 m_length = 0; // source length - u8 m_volume = 0; // master volume - int m_pan = -1; // master pan - u16 m_counter = 0; // frequency counter - u32 m_addr = 0; // current address - s32 m_remain = 0; // remain for end sample - u8 m_bitpos = 4; // bit position for ADPCM decoding - u8 m_data = 0; // current data - s8 m_adpcm_buf = 0; // ADPCM buffer + u16 m_enable : 1; // enable flag + u16 m_busy : 1; // busy status + u16 m_loop : 1; // loop flag + u16 m_adpcm : 1; // ADPCM flag + u16 m_pitch : 12; // pitch + u32 m_start = 0; // start position + u16 m_length = 0; // source length + u8 m_volume = 0; // master volume + int m_pan = -1; // master pan + u16 m_counter = 0; // frequency counter + u32 m_addr = 0; // current address + s32 m_remain = 0; // remain for end sample + u8 m_bitpos = 4; // bit position for ADPCM decoding + u8 m_data = 0; // current data + s8 m_output = 0; // ADPCM buffer std::array m_out; // current output }; @@ -152,6 +164,7 @@ class k053260_core : public vgsound_emu_core u8 m_input_en : 2; // Input enable }; + /* class ym3012_t { public: @@ -177,7 +190,9 @@ class k053260_core : public vgsound_emu_core std::array m_in; std::array m_out; }; + */ + /* class dac_t { public: @@ -205,6 +220,7 @@ class k053260_core : public vgsound_emu_core u8 m_clock : 4; // DAC clock (16 clock) u8 m_state : 2; // DAC state (4 state - SAM1, SAM2) }; + */ public: // constructor @@ -213,8 +229,8 @@ class k053260_core : public vgsound_emu_core , m_voice{*this, *this, *this, *this} , m_intf(intf) , m_ctrl(ctrl_t()) - , m_ym3012(ym3012_t()) - , m_dac(dac_t()) + //, m_ym3012(ym3012_t()) + //, m_dac(dac_t()) { m_host2snd.fill(0); m_snd2host.fill(0); @@ -233,7 +249,7 @@ class k053260_core : public vgsound_emu_core // internal state void reset(); - void tick(); + void tick(u32 cycle); // getters for debug, trackers, etc inline s32 output(u8 ch) { return m_out[ch & 1]; } // output for each channels @@ -245,6 +261,11 @@ class k053260_core : public vgsound_emu_core return (voice < 4) ? m_voice[voice].out(ch & 1) : 0; } + protected: + inline s32 pan_lut(const u8 pan, const u8 out) { return m_pan_lut[pan][out]; } + + inline s32 adpcm_lut(const u8 nibble) { return m_adpcm_lut[nibble]; } + private: std::array m_voice; k053260_intf &m_intf; // common memory interface @@ -254,8 +275,8 @@ class k053260_core : public vgsound_emu_core ctrl_t m_ctrl; // chip control - ym3012_t m_ym3012; // YM3012 output - dac_t m_dac; // YM3012 interface + //ym3012_t m_ym3012; // YM3012 output + //dac_t m_dac; // YM3012 interface std::array m_reg; // register pool std::array m_out; // stereo output diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index c30d7f23..319630d6 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -78,6 +78,7 @@ #include "platform/ga20.h" #include "platform/sm8521.h" #include "platform/pv1000.h" +#include "platform/k053260.h" #include "platform/pcmdac.h" #include "platform/dummy.h" #include "../ta-log.h" @@ -501,6 +502,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do case DIV_SYSTEM_PV1000: dispatch=new DivPlatformPV1000; break; + case DIV_SYSTEM_K053260: + dispatch=new DivPlatformK053260; + break; case DIV_SYSTEM_PCM_DAC: dispatch=new DivPlatformPCMDAC; break; diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index faa9f86c..c51805ab 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -930,6 +930,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { break; case DIV_INS_PV1000: break; + case DIV_INS_K053260: + featureSM=true; + featureSL=true; + break; case DIV_INS_MAX: break; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c53688ec..932d44ff 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -80,6 +80,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_POKEMINI=47, DIV_INS_SM8521=48, DIV_INS_PV1000=49, + DIV_INS_K053260=50, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/k053260.cpp b/src/engine/platform/k053260.cpp new file mode 100644 index 00000000..47e7636d --- /dev/null +++ b/src/engine/platform/k053260.cpp @@ -0,0 +1,475 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 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 "k053260.h" +#include "../engine.h" +#include "../../ta-log.h" +#include + +#define rWrite(a,v) {if(!skipRegisterWrites) {k053260.write(a,v); regPool[a]=v; if(dumpWrites) addWrite(a,v);}} + +#define CHIP_DIVIDER 64 +#define TICK_DIVIDER 4 + +const char* regCheatSheetK053260[]={ + "FreqL", "0", + "FreqH", "1", + "LengthL", "2", + "LengthH", "3", + "StartL", "4", + "StartM", "5", + "StartH", "6", + "Volume", "7", + NULL +}; + +const char** DivPlatformK053260::getRegisterSheet() { + return regCheatSheetK053260; +} + +inline void DivPlatformK053260::chWrite(unsigned char ch, unsigned int addr, unsigned char val) { + if (!skipRegisterWrites) { + rWrite(8+((ch<<3)|(addr&7)),val); + } +} + +// TODO: this code is weird +// make sure newDispatch didn't break it up +void DivPlatformK053260::acquire(short** buf, size_t len) { + for (int i=0; i32767) lout=32767; + if (lout<-32768) lout=-32768; + if (rout>32767) rout=32767; + if (rout<-32768) rout=-32768; + buf[0][i]=lout; + buf[1][i]=rout; + + for (int i=0; i<4; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(k053260.voice_out(i,0)+k053260.voice_out(i,1))>>1; + } + } +} + +void DivPlatformK053260::tick(bool sysTick) { + unsigned char panMask=0; + for (int i=0; i<4; i++) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&0x7f)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; + chWrite(i,7,chan[i].outVol); + } + if (NEW_ARP_STRAT) { + chan[i].handleArp(); + } else if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(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; + } + if (chan[i].std.panL.had) { // panning + chan[i].panning=4+chan[i].std.panL.val; + if (!isMuted[i]) { + panMask|=1<=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,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,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 start=0; + unsigned int length=0; + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + start=sampleOffK053260[chan[i].sample]; + length=start+s->length8; + } + if (chan[i].audPos>0) { + start=start+MIN(chan[i].audPos,s->length8); + } + start=MIN(start,getSampleMemCapacity()-31); + length=MIN(length,getSampleMemCapacity()-31); + rWrite(0x28,keyoff); // force keyoff first + rWrite(0x2a,loopoff); + chWrite(i,2,length&0xff); + chWrite(i,3,length>>8); + chWrite(i,4,start&0xff); + chWrite(i,5,start>>8); + chWrite(i,6,start>>16); + if (!chan[i].std.vol.had) { + chan[i].outVol=chan[i].vol; + chWrite(i,7,chan[i].outVol); + } + rWrite(0x28,keyon); + if (s->isLoopable()) { + rWrite(0x2a,loopon); + } + chan[i].keyOn=false; + } + if (chan[i].keyOff) { + rWrite(0x28,keyoff); + rWrite(0x2a,loopoff); + chan[i].keyOff=false; + } + if (chan[i].freqChanged) { + chWrite(i,0,chan[i].freq&0xff); + chWrite(i,1,chan[i].freq>>8); + chan[i].freqChanged=false; + } + } + } + if (panMask) { + updatePanning(panMask); + } +} + +void DivPlatformK053260::updatePanning(unsigned char mask) { + if (mask&3) { + rWrite(0x2c, + (isMuted[0]?0:chan[0].panning)| + (isMuted[1]?0:chan[1].panning<<3)); + } + if (mask&0xc) { + rWrite(0x2d, + (isMuted[2]?0:chan[2].panning)| + (isMuted[3]?0:chan[3].panning<<3)); + } +} + +int DivPlatformK053260::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:127; + if (c.value!=DIV_NOTE_NULL) 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; + } + 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; + chWrite(c.chan,7,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_PANNING: + chan[c.chan].panning=MIN(parent->convertPanSplitToLinearLR(c.value,c.value2,7)+1,7); + if (!isMuted[c.chan]) { + updatePanning(1<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+((HACKY_LEGATO_MESS)?(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 && !NEW_ARP_STRAT) 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 127; + 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_ALWAYS_SET_VOLUME: + return 1; + break; + default: + break; + } + return 1; +} + +void DivPlatformK053260::muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + updatePanning(1<rate=rate; + } +} + +void DivPlatformK053260::poke(unsigned int addr, unsigned short val) { + rWrite(addr&0x0f,val); +} + +void DivPlatformK053260::poke(std::vector& wlist) { + for (DivRegWrite& i: wlist) rWrite(i.addr&0x0f,i.val); +} + +unsigned char* DivPlatformK053260::getRegisterPool() { + return regPool; +} + +int DivPlatformK053260::getRegisterPoolSize() { + return 48; +} + +const void* DivPlatformK053260::getSampleMem(int index) { + return index == 0 ? sampleMem : NULL; +} + +size_t DivPlatformK053260::getSampleMemCapacity(int index) { + return index == 0 ? 2097152 : 0; +} + +size_t DivPlatformK053260::getSampleMemUsage(int index) { + return index == 0 ? sampleMemLen : 0; +} + +bool DivPlatformK053260::isSampleLoaded(int index, int sample) { + if (index!=0) return false; + if (sample<0 || sample>255) return false; + return sampleLoaded[sample]; +} + +void DivPlatformK053260::renderSamples(int sysID) { + memset(sampleMem,0,getSampleMemCapacity()); + memset(sampleOffK053260,0,256*sizeof(unsigned int)); + memset(sampleLoaded,0,256*sizeof(bool)); + + size_t memPos=1; // for avoid silence + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + if (!s->renderOn[0][sysID]) { + sampleOffK053260[i]=0; + continue; + } + + int length=MIN(65535,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length); + if (actualLength>0) { + sampleOffK053260[i]=memPos-1; + for (int j=0; jdata8[j]; + } + } + if (actualLength +#include "vgsound_emu/src/k053260/k053260.hpp" + +class DivPlatformK053260: public DivDispatch, public k053260_intf { + struct Channel: public SharedChannel { + unsigned int audPos; + int sample, wave; + int panning; + bool setPos; + int macroVolMul; + Channel(): + SharedChannel(127), + audPos(0), + sample(-1), + wave(-1), + panning(4), + setPos(false), + macroVolMul(64) {} + }; + Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; + bool isMuted[4]; + int chipType; + unsigned char curChan; + unsigned int sampleOffK053260[256]; + bool sampleLoaded[256]; + + unsigned char* sampleMem; + size_t sampleMemLen; + k053260_core k053260; + unsigned char regPool[48]; + void updatePanning(unsigned char mask); + + 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(); + 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(); + DivPlatformK053260(): + DivDispatch(), + k053260_intf(), + k053260(*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 8b6da13b..bc2dc750 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -127,7 +127,8 @@ enum DivSystem { DIV_SYSTEM_YM2203_CSM, DIV_SYSTEM_YM2608_CSM, DIV_SYSTEM_SM8521, - DIV_SYSTEM_PV1000 + DIV_SYSTEM_PV1000, + DIV_SYSTEM_K053260 }; struct DivGroovePattern { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index fbb718cb..f236fcd2 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1855,6 +1855,16 @@ void DivEngine::registerSystems() { } ); + sysDefs[DIV_SYSTEM_K053260]=new DivSysDef( + "Konami K053260", NULL, 0xfe/*placeholder*/, 0, 4, false, true, 0x161, false, 1U<writeC(0xff); break; case DIV_SYSTEM_GA20: - for (int i=0; i<3; i++) { + for (int i=0; i<4; i++) { w->writeC(0xbf); // mute w->writeC((baseAddr2|5)+(i*8)); w->writeC(0); @@ -573,6 +573,16 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(0); } break; + case DIV_SYSTEM_K053260: + for (int i=0; i<4; i++) { + w->writeC(0xba); // mute + w->writeC(baseAddr2|0x2f); + w->writeC(0); + w->writeC(0xba); // keyoff + w->writeC(baseAddr2|0x28); + w->writeC(0); + } + break; default: break; } @@ -928,6 +938,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(baseAddr2|(write.addr&0x7f)); w->writeC(write.val); break; + case DIV_SYSTEM_K053260: + w->writeC(0xba); + w->writeC(baseAddr2|(write.addr&0x3f)); + w->writeC(write.val&0xff); + break; default: logW("write not handled!"); break; @@ -1093,6 +1108,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p DivDispatch* writeRF5C68[2]={NULL,NULL}; DivDispatch* writeMSM6295[2]={NULL,NULL}; DivDispatch* writeGA20[2]={NULL,NULL}; + DivDispatch* writeK053260[2]={NULL,NULL}; for (int i=0; ichipClock; + CHIP_VOL(40,0.4); + willExport[i]=true; + writeK053260[0]=disCont[i].dispatch; + } else if (!(hasK053260&0x40000000)) { + isSecond[i]=true; + CHIP_VOL_SECOND(40,0.4); + willExport[i]=true; + writeK053260[1]=disCont[i].dispatch; + hasK053260|=0x40000000; + howManyChips++; + } + break; case DIV_SYSTEM_T6W28: if (!hasSN) { hasSN=0xc0000000|disCont[i].dispatch->chipClock; @@ -1964,6 +1995,15 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p w->writeI(0); w->write(writeGA20[i]->getSampleMem(),writeGA20[i]->getSampleMemUsage()); } + if (writeK053260[i]!=NULL && writeK053260[i]->getSampleMemUsage()>0) { + w->writeC(0x67); + w->writeC(0x66); + w->writeC(0x8e); + w->writeI((writeK053260[i]->getSampleMemUsage()+8)|(i*0x80000000)); + w->writeI(writeK053260[i]->getSampleMemCapacity()); + w->writeI(0); + w->write(writeK053260[i]->getSampleMem(),writeK053260[i]->getSampleMemUsage()); + } } // TODO diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 2a37c7e8..859a0d0d 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -438,6 +438,10 @@ void FurnaceGUI::drawInsList(bool asChild) { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_PV1000]); name=fmt::sprintf(ICON_FA_GAMEPAD "##_INS%d",i); break; + case DIV_INS_K053260: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_K053260]); + name=fmt::sprintf(ICON_FA_BAR_CHART "##_INS%d",i); + break; default: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); name=fmt::sprintf(ICON_FA_QUESTION "##_INS%d",i); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 49d568b3..7a01edf8 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -53,6 +53,7 @@ #include "../engine/platform/ga20.h" #include "../engine/platform/sm8521.h" #include "../engine/platform/pv1000.h" +#include "../engine/platform/k053260.h" #include "../engine/platform/dummy.h" #define COMMON_CHIP_DEBUG \ @@ -545,6 +546,13 @@ void putDispatchChip(void* data, int type) { COMMON_CHIP_DEBUG_BOOL; break; } + case DIV_SYSTEM_K053260: { + DivPlatformK053260* ch=(DivPlatformK053260*)data; + ImGui::Text("> K053260"); + COMMON_CHIP_DEBUG; + COMMON_CHIP_DEBUG_BOOL; + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; @@ -1083,6 +1091,18 @@ void putDispatchChan(void* data, int chanNum, int type) { COMMON_CHAN_DEBUG_BOOL; break; } + case DIV_SYSTEM_K053260: { + DivPlatformK053260::Channel* ch=(DivPlatformK053260::Channel*)data; + ImGui::Text("> K053260"); + COMMON_CHAN_DEBUG; + ImGui::Text("* Sample: %d",ch->sample); + ImGui::Text(" - pos: %d",ch->audPos); + ImGui::Text("- panning: %d",ch->panning); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + COMMON_CHAN_DEBUG_BOOL; + 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 4e6cdec5..47579864 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1344,7 +1344,8 @@ void FurnaceGUI::doAction(int what) { i==DIV_INS_SNES || i==DIV_INS_ES5506 || i==DIV_INS_K007232 || - i==DIV_INS_GA20) { + i==DIV_INS_GA20 || + i==DIV_INS_K053260) { makeInsTypeList.push_back(i); } } diff --git a/src/gui/gui.h b/src/gui/gui.h index 7dddb53e..9fcabf6c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -193,6 +193,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_POKEMINI, GUI_COLOR_INSTR_SM8521, GUI_COLOR_INSTR_PV1000, + GUI_COLOR_INSTR_K053260, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_BG, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 214eb468..15b4e8c7 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -131,6 +131,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "Pokémon Mini/QuadTone", "SM8521", "PV-1000", + "K053260", NULL }; @@ -822,6 +823,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_POKEMINI,"",ImVec4(1.0f,1.0f,0.3f,1.0f)), D(GUI_COLOR_INSTR_SM8521,"",ImVec4(0.5f,0.55f,0.6f,1.0f)), D(GUI_COLOR_INSTR_PV1000,"",ImVec4(0.4f,0.6f,0.7f,1.0f)), + D(GUI_COLOR_INSTR_K053260,"",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)), @@ -1005,6 +1007,7 @@ const int availableSystems[]={ DIV_SYSTEM_GA20, DIV_SYSTEM_SM8521, DIV_SYSTEM_PV1000, + DIV_SYSTEM_K053260, DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PONG, 0 // don't remove this last one! @@ -1113,6 +1116,7 @@ const int chipsSample[]={ DIV_SYSTEM_GA20, DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_ES5506, + DIV_SYSTEM_K053260, 0 // don't remove this last one! }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index abac70c1..92692ce5 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4338,7 +4338,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SNES || ins->type==DIV_INS_ES5506 || ins->type==DIV_INS_K007232 || - ins->type==DIV_INS_GA20) { + ins->type==DIV_INS_GA20 || + ins->type==DIV_INS_K053260) { if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { String sName; if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { @@ -5078,7 +5079,8 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ || - ins->type==DIV_INS_OPM || ins->type==DIV_INS_SNES || ins->type==DIV_INS_MSM5232) { + ins->type==DIV_INS_OPM || ins->type==DIV_INS_SNES || ins->type==DIV_INS_MSM5232 || + ins->type==DIV_INS_K053260) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -5167,7 +5169,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_SEGAPCM || ins->type==DIV_INS_FM || ins->type==DIV_INS_K007232 || ins->type==DIV_INS_GA20 || - ins->type==DIV_INS_SM8521 || ins->type==DIV_INS_PV1000) { + ins->type==DIV_INS_SM8521 || ins->type==DIV_INS_PV1000 || ins->type==DIV_INS_K053260) { dutyMax=0; } if (ins->type==DIV_INS_VBOY) { @@ -5267,6 +5269,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SEGAPCM) waveMax=0; if (ins->type==DIV_INS_K007232) waveMax=0; if (ins->type==DIV_INS_GA20) waveMax=0; + if (ins->type==DIV_INS_K053260) waveMax=0; if (ins->type==DIV_INS_POKEMINI) waveMax=0; if (ins->type==DIV_INS_SU || ins->type==DIV_INS_POKEY) waveMax=7; if (ins->type==DIV_INS_PET) { @@ -5385,6 +5388,11 @@ void FurnaceGUI::drawInsEdit() { panMax=7; panSingleNoBit=true; } + if (ins->type==DIV_INS_K053260) { + panMin=-3; + panMax=3; + panSingleNoBit=true; + } if (ins->type==DIV_INS_SU) { panMin=-127; panMax=127; @@ -5475,7 +5483,8 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_VBOY || (ins->type==DIV_INS_X1_010 && ins->amiga.useSample) || ins->type==DIV_INS_K007232 || - ins->type==DIV_INS_GA20) { + ins->type==DIV_INS_GA20 || + ins->type==DIV_INS_K053260) { 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 3354914c..33924b84 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1245,6 +1245,42 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_K007232, 1.0f, 0, "") // "" } ); + ENTRY( + "Konami Rollergames", { + CH(DIV_SYSTEM_OPL2, 1.0f, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // "" + } + ); + ENTRY( + "Konami Rollergames (drums mode)", { + CH(DIV_SYSTEM_OPL2_DRUMS, 1.0f, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // "" + } + ); + ENTRY( + "Konami Golfing Greats", { + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // 3.58MHz + } + ); + ENTRY( + "Konami Lightning Fighters", { + CH(DIV_SYSTEM_YM2151, 1.0f, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // "" + } + ); + ENTRY( + "Konami Over Drive", { + CH(DIV_SYSTEM_YM2151, 1.0f, 0, ""), // 3.58MHz + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // "" + CH(DIV_SYSTEM_K053260, 1.0f, 0, ""), // "" + } + ); + ENTRY( + "Konami Asterix", { + CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2"), // 4MHz + CH(DIV_SYSTEM_K053260, 1.0f, 0, "clockSel=1"), // "" + } + ); ENTRY( "Konami Hexion", { CH(DIV_SYSTEM_SCC, 1.0f, 0, "clockSel=2"), // 1.5MHz (3MHz input) @@ -2449,6 +2485,11 @@ void FurnaceGUI::initSystemPresets() { CH(DIV_SYSTEM_ES5506, 1.0f, 0, "channels=31") } ); + ENTRY( + "Konami K053260", { + CH(DIV_SYSTEM_K053260, 1.0f, 0, "") + } + ); CATEGORY_END; CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound."); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 207c8838..7edaeb0f 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1954,6 +1954,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEMINI,"Pokémon Mini"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SM8521,"SM8521"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_PV1000,"PV-1000"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_K053260,"K053260"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); ImGui::TreePop(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 77bc6c72..31f66e0a 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1784,6 +1784,26 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } break; }*/ + case DIV_SYSTEM_K053260: { + int clockSel=flags.getInt("clockSel",0); + + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) { + clockSel=0; + altered=true; + } + if (ImGui::RadioButton("4MHz",clockSel==1)) { + clockSel=1; + altered=true; + } + + if (altered) { + e->lockSave([&]() { + flags.set("clockSel",clockSel); + }); + } + break; + } case DIV_SYSTEM_SWAN: case DIV_SYSTEM_BUBSYS_WSG: case DIV_SYSTEM_PET: