From 775b88dae2896d89e50aa9f5d930e360dfb9be02 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 14 May 2021 03:23:40 -0500 Subject: [PATCH] more playback work --- CMakeLists.txt | 1 + src/engine/dispatch.h | 5 +- src/engine/engine.h | 18 ++++- src/engine/pattern.h | 2 +- src/engine/platform/genesis.cpp | 40 ++++++++--- src/engine/platform/genesis.h | 5 +- src/engine/playback.cpp | 113 +++++++++++++++++++++++++------- 7 files changed, 145 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf6125bac..bb7105023 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ set(ENGINE_SOURCES src/log.cpp extern/Nuked-OPN2/ym3438.c +src/engine/platform/sound/sn76496.cpp src/engine/blip_buf.c src/engine/safeReader.cpp diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 0cb0154b1..f9815449b 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -6,9 +6,8 @@ enum DivDispatchCmds { DIV_CMD_NOTE_OFF, DIV_CMD_INSTRUMENT, DIV_CMD_VOLUME, - DIV_CMD_PITCH_UP, - DIV_CMD_PITCH_DOWN, - DIV_CMD_PITCH_TO, + DIV_CMD_NOTE_PORTA, + DIV_CMD_PITCH, DIV_CMD_PANNING, DIV_CMD_SAMPLE_MODE diff --git a/src/engine/engine.h b/src/engine/engine.h index a2c6630c6..b72ca532b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -7,10 +7,22 @@ struct DivChannelState { std::vector delayed; - int rampSpeed, portaSpeed, portaNote; - int volSpeed; + int note, pitch, portaSpeed, portaNote; + int volume, volSpeed; int vibratoDepth, vibratoRate; int tremoloDepth, tremoloRate; + + DivChannelState(): + note(-1), + pitch(0), + portaSpeed(-1), + portaNote(-1), + volume(0x7f00), + volSpeed(0), + vibratoDepth(0), + vibratoRate(0), + tremoloDepth(0), + tremoloRate(0) {} }; class DivEngine { @@ -22,7 +34,7 @@ class DivEngine { bool speedAB; int ticks, cycles, curRow, curOrder; int changeOrd, changePos; - std::vector chan; + DivChannelState chan[17]; blip_buffer_t* bb[2]; short temp[2], prevSample[2]; diff --git a/src/engine/pattern.h b/src/engine/pattern.h index 5eb09024f..421870cc6 100644 --- a/src/engine/pattern.h +++ b/src/engine/pattern.h @@ -1,5 +1,5 @@ struct DivPattern { - unsigned char data[256][16]; + short data[256][16]; }; struct DivChannelData { diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 2d8debbe2..3ed84d5d7 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -1,6 +1,7 @@ #include "genesis.h" #include "../engine.h" #include +#include // TODO fix all the writes. // i think there is no wait for data writes, just for ON/OFF writes @@ -50,9 +51,6 @@ static unsigned short opOffs[4]={ 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 -}; static bool isOutput[8][4]={ // 1 3 2 4 {false,false,false,true}, @@ -87,9 +85,36 @@ void DivPlatformGenesis::tick() { } for (int i=0; i<6; i++) { - if (chan[i].keyOn) { + if (chan[i].freqChanged) { + if (chan[i].freq>=131072) { + chan[i].freqH=((chan[i].freq>>15)&7)|0x38; + chan[i].freqL=(chan[i].freq>>7)&0xff; + } else if (chan[i].freq>=65536) { + chan[i].freqH=((chan[i].freq>>14)&7)|0x30; + chan[i].freqL=(chan[i].freq>>6)&0xff; + } else if (chan[i].freq>=32768) { + chan[i].freqH=((chan[i].freq>>13)&7)|0x28; + chan[i].freqL=(chan[i].freq>>5)&0xff; + } else if (chan[i].freq>=16384) { + chan[i].freqH=((chan[i].freq>>12)&7)|0x20; + chan[i].freqL=(chan[i].freq>>4)&0xff; + } else if (chan[i].freq>=8192) { + chan[i].freqH=((chan[i].freq>>11)&7)|0x18; + chan[i].freqL=(chan[i].freq>>3)&0xff; + } else if (chan[i].freq>=4096) { + chan[i].freqH=((chan[i].freq>>10)&7)|0x10; + chan[i].freqL=(chan[i].freq>>2)&0xff; + } else if (chan[i].freq>=2048) { + chan[i].freqH=((chan[i].freq>>9)&7)|0x08; + chan[i].freqL=(chan[i].freq>>1)&0xff; + } else { + chan[i].freqH=(chan[i].freq>>8)&7; + chan[i].freqL=chan[i].freq&0xff; + } writes.emplace(chanOffs[i]+0xa4,chan[i].freqH); writes.emplace(chanOffs[i]+0xa0,chan[i].freqL); + } + if (chan[i].keyOn) { writes.emplace(0x28,0xf0|konOffs[i]); chan[i].keyOn=false; } @@ -99,6 +124,7 @@ void DivPlatformGenesis::tick() { #define rWrite(a,v) pendingWrites[a]=v; int DivPlatformGenesis::dispatch(DivCommand c) { + if (c.chan>5) return 0; switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan==5 && dacMode) { @@ -112,8 +138,6 @@ int DivPlatformGenesis::dispatch(DivCommand c) { dacRate=dacRates[parent->song.sample[dacSample]->rate]; break; } - 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]; if (chan[c.chan].insChanged) { @@ -136,8 +160,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) { rWrite(chanOffs[c.chan]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); rWrite(chanOffs[c.chan]+0xb4,(chan[c.chan].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } - chan[c.chan].freqH=((c.value/12)<<3)|(notes[c.value%12]>>8); - chan[c.chan].freqL=notes[c.value%12]; + chan[c.chan].freq=644.0f*pow(2.0f,((float)c.value/12.0f)); + chan[c.chan].freqChanged=true; chan[c.chan].keyOn=true; chan[c.chan].active=true; break; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index c088eb44e..c932f9243 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -5,12 +5,13 @@ class DivPlatformGenesis: public DivDispatch { struct Channel { unsigned char freqH, freqL; + int freq; unsigned char ins; signed char konCycles; - bool active, insChanged, keyOn, keyOff; + bool active, insChanged, freqChanged, keyOn, keyOff; signed char vol; unsigned char pan; - Channel(): freqH(0), freqL(0), ins(0), active(false), insChanged(true), keyOn(false), keyOff(false), vol(0), pan(3) {} + Channel(): freqH(0), freqL(0), freq(0), ins(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), vol(0), pan(3) {} }; Channel chan[10]; struct QueuedWrite { diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index e7ba441b2..685dd90ec 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -65,26 +65,26 @@ void DivEngine::nextRow() { snprintf(pb2,4095,"\x1b[37m %s", formatNote(pat->data[curRow][0],pat->data[curRow][1])); strcat(pb3,pb2); - if (pat->data[curRow][3]==255) { + if (pat->data[curRow][3]==-1) { strcat(pb3,"\x1b[m--"); } else { snprintf(pb2,4095,"\x1b[1;32m%.2x",pat->data[curRow][3]); strcat(pb3,pb2); } - if (pat->data[curRow][2]==255) { + if (pat->data[curRow][2]==-1) { strcat(pb3,"\x1b[m--"); } else { snprintf(pb2,4095,"\x1b[0;36m%.2x",pat->data[curRow][2]); strcat(pb3,pb2); } for (int j=0; jeffectRows; j++) { - if (pat->data[curRow][4+(j<<1)]==255) { + if (pat->data[curRow][4+(j<<1)]==-1) { strcat(pb3,"\x1b[m--"); } else { snprintf(pb2,4095,"\x1b[1;31m%.2x",pat->data[curRow][4+(j<<1)]); strcat(pb3,pb2); } - if (pat->data[curRow][5+(j<<1)]==255) { + if (pat->data[curRow][5+(j<<1)]==-1) { strcat(pb3,"\x1b[m--"); } else { snprintf(pb2,4095,"\x1b[1;37m%.2x",pat->data[curRow][5+(j<<1)]); @@ -96,11 +96,33 @@ void DivEngine::nextRow() { for (int i=0; idata[curOrder]; + + // instrument + if (pat->data[curRow][2]!=-1) { + dispatch->dispatch(DivCommand(DIV_CMD_INSTRUMENT,i,pat->data[curRow][2])); + } + // note + if (pat->data[curRow][0]==100) { + chan[i].note=-1; + dispatch->dispatch(DivCommand(DIV_CMD_NOTE_OFF,i)); + } else if (!(pat->data[curRow][0]==0 && pat->data[curRow][1]==0)) { + chan[i].note=pat->data[curRow][0]+pat->data[curRow][1]*12; + dispatch->dispatch(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note)); + } + + // volume + if (pat->data[curRow][3]!=-1) { + chan[i].volume=pat->data[curRow][3]<<8; + dispatch->dispatch(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + } + // effects for (int j=0; jeffectRows; j++) { unsigned char effect=pat->data[curRow][4+(j<<1)]; unsigned char effectVal=pat->data[curRow][5+(j<<1)]; + if (effectVal==-1) effectVal=0; + // per-system effect if (!perSystemEffect(i,effect,effectVal)) switch (effect) { case 0x09: // speed 1 @@ -120,26 +142,62 @@ void DivEngine::nextRow() { case 0x08: // panning dispatch->dispatch(DivCommand(DIV_CMD_PANNING,i,effectVal)); break; + case 0x01: // ramp up + if (effectVal==0) { + chan[i].portaNote=-1; + chan[i].portaSpeed=-1; + } else { + chan[i].portaNote=0x7f; + chan[i].portaSpeed=effectVal; + } + break; + case 0x02: // ramp down + if (effectVal==0) { + chan[i].portaNote=-1; + chan[i].portaSpeed=-1; + } else { + chan[i].portaNote=0x00; + chan[i].portaSpeed=effectVal; + } + break; + case 0x03: // portamento + if (effectVal==0) { + chan[i].portaNote=-1; + chan[i].portaSpeed=-1; + } else { + chan[i].portaNote=chan[i].note; + chan[i].portaSpeed=effectVal; + } + break; + case 0x04: // vibrato + chan[i].vibratoDepth=effectVal&15; + chan[i].vibratoRate=effectVal>>4; + break; + case 0x0a: // volume ramp + if (effectVal!=0) { + if ((effectVal&15)!=0) { + chan[i].volSpeed=-(effectVal&15)*64; + } else { + chan[i].volSpeed=(effectVal>>4)*64; + } + } else { + chan[i].volSpeed=0; + } + break; + + case 0xe1: // portamento up + chan[i].portaNote=chan[i].note+(effectVal&15); + chan[i].portaSpeed=effectVal>>4; + break; + case 0xe2: // portamento down + chan[i].portaNote=chan[i].note-(effectVal&15); + chan[i].portaSpeed=effectVal>>4; + break; + case 0xe5: // pitch + chan[i].pitch=effectVal-0x80; + break; } } - - // 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)); - } else if (!(pat->data[curRow][0]==0 && pat->data[curRow][1]==0)) { - 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])); - } - - } } @@ -162,6 +220,17 @@ void DivEngine::nextTick() { } speedAB=!speedAB; } + // process stuff + for (int i=0; i0x7f00) chan[i].volume=0x7f00; + if (chan[i].volume<0) chan[i].volume=0; + dispatch->dispatch(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); + } + } + + // system tick dispatch->tick(); }