From 3172fd37edb0e9be1b31ff9077c4093bb37c06bd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 15 May 2021 16:42:48 -0500 Subject: [PATCH] more SMS work it is able to play some modules... the next step is to bind this to the Genesis platform --- CMakeLists.txt | 1 + src/engine/engine.cpp | 4 ++ src/engine/instrument.h | 5 ++- src/engine/macroInt.cpp | 88 +++++++++++++++++++++++++++++++++++++ src/engine/macroInt.h | 31 +++++++++++++ src/engine/platform/sms.cpp | 18 +++++++- src/engine/platform/sms.h | 2 + 7 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/engine/macroInt.cpp create mode 100644 src/engine/macroInt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d90ccdfc..cfab8cf38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ src/engine/platform/sound/sn76496.cpp src/engine/blip_buf.c src/engine/safeReader.cpp src/engine/engine.cpp +src/engine/macroInt.cpp src/engine/playback.cpp src/engine/platform/abstract.cpp src/engine/platform/genesis.cpp diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index ef8e80f5b..e7ab2165f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -529,6 +529,10 @@ bool DivEngine::load(void* f, size_t slen) { pat->data[k][0]=reader.readS(); // octave pat->data[k][1]=reader.readS(); + if (ds.system==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { + // apparently it was up one octave before + pat->data[k][1]--; + } // volume pat->data[k][3]=reader.readS(); for (int l=0; leffectRows; l++) { diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 37a501eb7..fd0c1b403 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -1,3 +1,5 @@ +#ifndef _INSTRUMENT_H +#define _INSTRUMENT_H #include "../ta-utils.h" enum DivInstrumentType { @@ -22,7 +24,7 @@ struct DivInstrumentSTD { int waveMacro[256]; bool arpMacroMode; unsigned char volMacroLen, arpMacroLen, dutyMacroLen, waveMacroLen; - unsigned char volMacroLoop, arpMacroLoop, dutyMacroLoop, waveMacroLoop; + signed char volMacroLoop, arpMacroLoop, dutyMacroLoop, waveMacroLoop; }; struct DivInstrumentGB { @@ -48,3 +50,4 @@ struct DivInstrument { DivInstrumentGB gb; DivInstrumentC64 c64; }; +#endif diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp new file mode 100644 index 000000000..342ba030c --- /dev/null +++ b/src/engine/macroInt.cpp @@ -0,0 +1,88 @@ +#include "macroInt.h" + +void DivMacroInt::next() { + if (ins==NULL) return; + + hadVol=hasVol; + if (hasVol) { + vol=ins->std.volMacro[volPos++]; + if (volPos>=ins->std.volMacroLen) { + if (ins->std.volMacroLoop>=0) { + volPos=ins->std.volMacroLoop; + } else { + hasVol=false; + } + } + } + + hadArp=hasArp; + if (hasArp) { + arp=ins->std.arpMacro[arpPos++]; + if (arpPos>=ins->std.arpMacroLen) { + if (ins->std.arpMacroLoop>=0) { + arpPos=ins->std.arpMacroLoop; + } else { + hasArp=false; + } + } + } + + hadDuty=hasDuty; + if (hasDuty) { + duty=ins->std.dutyMacro[dutyPos++]; + if (dutyPos>=ins->std.dutyMacroLen) { + if (ins->std.dutyMacroLoop>=0) { + dutyPos=ins->std.dutyMacroLoop; + } else { + hasDuty=false; + } + } + } + + hadWave=hasWave; + if (hasWave) { + wave=ins->std.waveMacro[wavePos++]; + if (wavePos>=ins->std.waveMacroLen) { + if (ins->std.waveMacroLoop>=0) { + wavePos=ins->std.waveMacroLoop; + } else { + hasWave=false; + } + } + } +} + +void DivMacroInt::init(DivInstrument* which) { + ins=which; + volPos=0; + arpPos=0; + dutyPos=0; + wavePos=0; + hasVol=false; + hasArp=false; + hasDuty=false; + hasWave=false; + hadVol=false; + hadArp=false; + hadDuty=false; + hadWave=false; + + if (ins==NULL) return; + + if (ins->std.volMacroLen>0) { + hadVol=true; + hasVol=true; + } + if (ins->std.arpMacroLen>0) { + hadArp=true; + hasArp=true; + } + if (ins->std.dutyMacroLen>0) { + hadDuty=true; + hasDuty=true; + } + if (ins->std.waveMacroLen>0) { + hadWave=true; + hasWave=true; + } +} diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h new file mode 100644 index 000000000..48cc7b616 --- /dev/null +++ b/src/engine/macroInt.h @@ -0,0 +1,31 @@ +#ifndef _MACROINT_H +#define _MACROINT_H + +#include "instrument.h" + +class DivMacroInt { + DivInstrument* ins; + int volPos, arpPos, dutyPos, wavePos; + public: + unsigned char vol, arp, duty, wave; + bool hasVol, hasArp, hasDuty, hasWave; + bool hadVol, hadArp, hadDuty, hadWave; + void next(); + void init(DivInstrument* which); + DivMacroInt(): + ins(NULL), + vol(0), + arp(0), + duty(0), + wave(0), + hasVol(false), + hasArp(false), + hasDuty(false), + hasWave(false), + hadVol(false), + hadArp(false), + hadDuty(false), + hadWave(false) {} +}; + +#endif diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index ea486c36c..0570c291e 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -1,4 +1,5 @@ #include "sms.h" +#include "../engine.h" #include void DivPlatformSMS::acquire(short& l, short& r) { @@ -9,8 +10,13 @@ void DivPlatformSMS::acquire(short& l, short& r) { } void DivPlatformSMS::tick() { + for (int i=0; i<4; i++) { + chan[i].std.next(); + if (chan[i].std.hadVol) sn->write(0x90|(i<<5)|(15-((chan[i].vol*chan[i].std.vol)>>4))); + } for (int i=0; i<3; i++) { if (chan[i].freqChanged) { + chan[i].freq=(chan[i].baseFreq*(2048-chan[i].pitch))>>11; sn->write(0x80|i<<5|(chan[i].freq&15)); sn->write(chan[i].freq>>4); chan[i].freqChanged=false; @@ -18,6 +24,7 @@ void DivPlatformSMS::tick() { } if (chan[3].freqChanged || updateSNMode) { updateSNMode=false; + chan[3].freq=(chan[3].baseFreq*(2048-chan[3].pitch))>>11; chan[3].freqChanged=false; if (snNoiseMode&2) { // take period from channel 3 if (snNoiseMode&1) { @@ -40,19 +47,28 @@ void DivPlatformSMS::tick() { int DivPlatformSMS::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: - chan[c.chan].freq=3430/pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].baseFreq=1712/pow(2.0f,((float)c.value/12.0f)); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; chan[c.chan].active=true; sn->write(0x90|c.chan<<5|(15-chan[c.chan].vol)); + chan[c.chan].std.init(parent->song.ins[chan[c.chan].ins]); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; break; + case DIV_CMD_INSTRUMENT: + chan[c.chan].ins=c.value; + chan[c.chan].std.init(parent->song.ins[chan[c.chan].ins]); + break; case DIV_CMD_VOLUME: chan[c.chan].vol=c.value; sn->write(0x90|c.chan<<5|(15-chan[c.chan].vol)); break; + case DIV_CMD_PITCH: + chan[c.chan].pitch=c.value; + chan[c.chan].freqChanged=true; + break; case DIV_CMD_STD_NOISE_MODE: snNoiseMode=(c.value&1)|((c.value&16)>>3); updateSNMode=true; diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index a8ef61d5e..c190fe67a 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -1,4 +1,5 @@ #include "../dispatch.h" +#include "../macroInt.h" #include "sound/sn76496.h" class DivPlatformSMS: public DivDispatch { @@ -7,6 +8,7 @@ class DivPlatformSMS: public DivDispatch { unsigned char ins, note; bool active, insChanged, freqChanged, keyOn, keyOff; signed char vol; + DivMacroInt std; Channel(): freq(0), baseFreq(0), pitch(0), ins(0), note(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), vol(15) {} }; Channel chan[4];