From 062a9837c0e2725b0340be568ed1f888585c6134 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 12 May 2021 17:19:18 -0500 Subject: [PATCH] G E N E S I S without SN --- .gitmodules | 3 ++ CMakeLists.txt | 4 ++ extern/Nuked-OPN2 | 1 + src/engine/engine.cpp | 10 +++- src/engine/engine.h | 2 +- src/engine/instrument.h | 4 +- src/engine/platform/dummy.cpp | 10 ++-- src/engine/platform/genesis.cpp | 88 +++++++++++++++++++++++++++++++++ src/engine/platform/genesis.h | 28 +++++++++++ src/engine/playback.cpp | 9 ++++ src/engine/song.h | 5 +- 11 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 .gitmodules create mode 160000 extern/Nuked-OPN2 create mode 100644 src/engine/platform/genesis.cpp create mode 100644 src/engine/platform/genesis.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..dfa03f46 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extern/Nuked-OPN2"] + path = extern/Nuked-OPN2 + url = https://github.com/nukeykt/Nuked-OPN2 diff --git a/CMakeLists.txt b/CMakeLists.txt index b3e557e1..9eb20c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,11 +23,15 @@ endif() set(ENGINE_SOURCES src/log.cpp + +extern/Nuked-OPN2/ym3438.c + src/engine/blip_buf.c src/engine/safeReader.cpp src/engine/engine.cpp src/engine/playback.cpp src/engine/platform/abstract.cpp +src/engine/platform/genesis.cpp src/engine/platform/dummy.cpp) #imgui/imgui.cpp diff --git a/extern/Nuked-OPN2 b/extern/Nuked-OPN2 new file mode 160000 index 00000000..64704a44 --- /dev/null +++ b/extern/Nuked-OPN2 @@ -0,0 +1 @@ +Subproject commit 64704a443f8f6c1906ba26297092ea70fa1d45d7 diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index df301b0e..8c98026f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2,6 +2,7 @@ #include "safeReader.h" #include "../ta-log.h" #include "../audio/sdl.h" +#include "platform/genesis.h" #include "platform/dummy.h" #include @@ -636,7 +637,14 @@ bool DivEngine::init() { bbOut[0]=new short[got.bufsize]; bbOut[1]=new short[got.bufsize]; - dispatch=new DivPlatformDummy; + switch (song.system) { + case DIV_SYSTEM_GENESIS: + dispatch=new DivPlatformGenesis; + break; + default: + dispatch=new DivPlatformDummy; + break; + } dispatch->init(this,getChannelCount(song.system),got.rate); blip_set_rates(bb[0],dispatch->rate,got.rate); diff --git a/src/engine/engine.h b/src/engine/engine.h index d06e38f4..9fa834da 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -14,7 +14,6 @@ struct DivChannelState { }; class DivEngine { - DivSong song; DivDispatch* dispatch; TAAudio* output; TAAudioDesc want, got; @@ -34,6 +33,7 @@ class DivEngine { void nextTick(); public: + DivSong song; void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); // load a .dmf. bool load(void* f, size_t length); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index a048960d..37a501eb 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -1,3 +1,5 @@ +#include "../ta-utils.h" + enum DivInstrumentType { DIV_INS_FM, DIV_INS_STD, @@ -7,7 +9,7 @@ enum DivInstrumentType { struct DivInstrumentFM { unsigned char alg, fb, fms, ams, ops; - struct { + struct Operator { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759 } op[4]; diff --git a/src/engine/platform/dummy.cpp b/src/engine/platform/dummy.cpp index f4a2ebf1..13506dcd 100644 --- a/src/engine/platform/dummy.cpp +++ b/src/engine/platform/dummy.cpp @@ -13,21 +13,20 @@ void DivPlatformDummy::acquire(short& l, short& r) { } void DivPlatformDummy::tick() { - for (unsigned char i=0; i>3); - } } int DivPlatformDummy::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: - chan[c.chan].vol=0x7f; chan[c.chan].freq=16.4f*pow(2.0f,((float)c.value/12.0f)); chan[c.chan].active=true; break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; break; + case DIV_CMD_VOLUME: + chan[c.chan].vol=c.value; + break; default: break; } @@ -38,5 +37,8 @@ int DivPlatformDummy::init(DivEngine* p, int channels, int sugRate) { parent=p; rate=65536; chans=channels; + for (int i=0; i + +// TODO fix all the writes. +// i think there is no wait for data writes, just for ON/OFF writes +void DivPlatformGenesis::acquire(short& l, short& r) { + short o[2]; + if (!writes.empty() && --delay<0) { + QueuedWrite w=writes.front(); + //printf("write: %x = %.2x\n",w.addr,w.val); + OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr); + OPN2_Clock(&fm,o); + OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val); + writes.pop(); + delay=24; + } + OPN2_Clock(&fm,o); + //OPN2_Write(&fm,0,0); + l=o[0]<<7; + r=o[1]<<7; +} + +void DivPlatformGenesis::tick() { +} + +static unsigned short chanOffs[6]={ + 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 +}; +static unsigned short opOffs[4]={ + 0x00, 0x04, 0x08, 0x0c +}; +static unsigned char konOffs[6]={ + 0, 1, 2, 4, 5, 6 +}; +static unsigned short notes[12]={ + 644,681,722,765,810,858,910,964,1021,1081,1146,1214 +}; + +int DivPlatformGenesis::dispatch(DivCommand c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: { + if (c.chan>5) break; + //chan[c.chan].freq=16.4f*pow(2.0f,((float)c.value/12.0f)); + DivInstrument* ins=parent->song.ins[chan[c.chan].ins]; + writes.emplace(0x28,0x00|konOffs[c.chan]); + for (int i=0; i<4; i++) { + unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; + DivInstrumentFM::Operator op=ins->fm.op[i]; + writes.emplace(baseAddr+0x30,op.mult&15|(op.dt<<4)); + writes.emplace(baseAddr+0x40,op.tl); + writes.emplace(baseAddr+0x50,op.ar&31|(op.rs<<6)); + writes.emplace(baseAddr+0x60,op.dr&31|(op.am<<7)); + writes.emplace(baseAddr+0x70,op.d2r&31); + writes.emplace(baseAddr+0x80,op.rr&15|(op.sl<<4)); + } + writes.emplace(chanOffs[c.chan]+0xa4,((c.value/12)<<3)|(notes[c.value%12]>>8)); + writes.emplace(chanOffs[c.chan]+0xa0,notes[c.value%12]); + writes.emplace(chanOffs[c.chan]+0xb0,ins->fm.alg&7|(ins->fm.fb<<3)); + writes.emplace(chanOffs[c.chan]+0xb4,0xc0|ins->fm.fms&7|((ins->fm.ams&3)<<4)); + writes.emplace(0x28,0xf0|konOffs[c.chan]); + chan[c.chan].active=true; + break; + } + case DIV_CMD_NOTE_OFF: + writes.emplace(0x28,0x00|konOffs[c.chan]); + chan[c.chan].active=false; + break; + case DIV_CMD_VOLUME: + chan[c.chan].vol=c.value; + break; + case DIV_CMD_INSTRUMENT: + chan[c.chan].ins=c.value; + break; + default: + break; + } + return 1; +} + +int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate) { + parent=p; + rate=1278409; + OPN2_Reset(&fm); + + delay=100; + return 10; +} diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h new file mode 100644 index 00000000..0f64d934 --- /dev/null +++ b/src/engine/platform/genesis.h @@ -0,0 +1,28 @@ +#include "../dispatch.h" +#include +#include "../../../extern/Nuked-OPN2/ym3438.h" + +class DivPlatformGenesis: public DivDispatch { + struct Channel { + unsigned short freq; + unsigned char ins; + bool active; + signed char vol; + Channel(): freq(0), ins(0), active(false), vol(0) {} + }; + Channel chan[10]; + struct QueuedWrite { + unsigned short addr; + unsigned char val; + QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {} + }; + std::queue writes; + ym3438_t fm; + int psg; + int delay; + public: + void acquire(short& l, short& r); + int dispatch(DivCommand c); + void tick(); + int init(DivEngine* parent, int channels, int sugRate); +}; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 472db966..6b50a5af 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -79,6 +79,10 @@ void DivEngine::nextRow() { for (int i=0; idata[curOrder]; + // instrument + if (pat->data[curRow][2]!=255) { + dispatch->dispatch(DivCommand(DIV_CMD_INSTRUMENT,i,pat->data[curRow][2])); + } // note if (pat->data[curRow][0]==100) { dispatch->dispatch(DivCommand(DIV_CMD_NOTE_OFF,i)); @@ -86,6 +90,11 @@ void DivEngine::nextRow() { dispatch->dispatch(DivCommand(DIV_CMD_NOTE_ON,i,pat->data[curRow][0]+pat->data[curRow][1]*12)); } + // volume + if (pat->data[curRow][3]!=255) { + dispatch->dispatch(DivCommand(DIV_CMD_VOLUME,i,pat->data[curRow][3])); + } + // effects for (int j=0; jeffectRows; j++) { unsigned char effect=pat->data[curRow][4+(j<<1)]; diff --git a/src/engine/song.h b/src/engine/song.h index e94d5171..15a08d5d 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -63,8 +63,9 @@ struct DivSong { // - introduces Genesis system // - introduces system number // - 7: ??? - // - 5: ??? - // - 3: BETA 3 (?) + // - 5: BETA 3 (?) + // - adds arpeggio tick + // - 3: BETA 2 // - possibly the first version that could save // - basic format, no system number, 16 instruments, one speed, YMU759-only // - if somebody manages to find a version 2 or even 1 module, please tell me as it will be worth more than a luxury vehicle