more playback work
This commit is contained in:
parent
5b002ca1d5
commit
775b88dae2
|
@ -25,6 +25,7 @@ set(ENGINE_SOURCES
|
||||||
src/log.cpp
|
src/log.cpp
|
||||||
|
|
||||||
extern/Nuked-OPN2/ym3438.c
|
extern/Nuked-OPN2/ym3438.c
|
||||||
|
src/engine/platform/sound/sn76496.cpp
|
||||||
|
|
||||||
src/engine/blip_buf.c
|
src/engine/blip_buf.c
|
||||||
src/engine/safeReader.cpp
|
src/engine/safeReader.cpp
|
||||||
|
|
|
@ -6,9 +6,8 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_NOTE_OFF,
|
DIV_CMD_NOTE_OFF,
|
||||||
DIV_CMD_INSTRUMENT,
|
DIV_CMD_INSTRUMENT,
|
||||||
DIV_CMD_VOLUME,
|
DIV_CMD_VOLUME,
|
||||||
DIV_CMD_PITCH_UP,
|
DIV_CMD_NOTE_PORTA,
|
||||||
DIV_CMD_PITCH_DOWN,
|
DIV_CMD_PITCH,
|
||||||
DIV_CMD_PITCH_TO,
|
|
||||||
DIV_CMD_PANNING,
|
DIV_CMD_PANNING,
|
||||||
|
|
||||||
DIV_CMD_SAMPLE_MODE
|
DIV_CMD_SAMPLE_MODE
|
||||||
|
|
|
@ -7,10 +7,22 @@
|
||||||
|
|
||||||
struct DivChannelState {
|
struct DivChannelState {
|
||||||
std::vector<DivDelayedCommand> delayed;
|
std::vector<DivDelayedCommand> delayed;
|
||||||
int rampSpeed, portaSpeed, portaNote;
|
int note, pitch, portaSpeed, portaNote;
|
||||||
int volSpeed;
|
int volume, volSpeed;
|
||||||
int vibratoDepth, vibratoRate;
|
int vibratoDepth, vibratoRate;
|
||||||
int tremoloDepth, tremoloRate;
|
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 {
|
class DivEngine {
|
||||||
|
@ -22,7 +34,7 @@ class DivEngine {
|
||||||
bool speedAB;
|
bool speedAB;
|
||||||
int ticks, cycles, curRow, curOrder;
|
int ticks, cycles, curRow, curOrder;
|
||||||
int changeOrd, changePos;
|
int changeOrd, changePos;
|
||||||
std::vector<DivChannelState> chan;
|
DivChannelState chan[17];
|
||||||
|
|
||||||
blip_buffer_t* bb[2];
|
blip_buffer_t* bb[2];
|
||||||
short temp[2], prevSample[2];
|
short temp[2], prevSample[2];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
struct DivPattern {
|
struct DivPattern {
|
||||||
unsigned char data[256][16];
|
short data[256][16];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivChannelData {
|
struct DivChannelData {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "genesis.h"
|
#include "genesis.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
// TODO fix all the writes.
|
// TODO fix all the writes.
|
||||||
// i think there is no wait for data writes, just for ON/OFF 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]={
|
static unsigned char konOffs[6]={
|
||||||
0, 1, 2, 4, 5, 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]={
|
static bool isOutput[8][4]={
|
||||||
// 1 3 2 4
|
// 1 3 2 4
|
||||||
{false,false,false,true},
|
{false,false,false,true},
|
||||||
|
@ -87,9 +85,36 @@ void DivPlatformGenesis::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<6; i++) {
|
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]+0xa4,chan[i].freqH);
|
||||||
writes.emplace(chanOffs[i]+0xa0,chan[i].freqL);
|
writes.emplace(chanOffs[i]+0xa0,chan[i].freqL);
|
||||||
|
}
|
||||||
|
if (chan[i].keyOn) {
|
||||||
writes.emplace(0x28,0xf0|konOffs[i]);
|
writes.emplace(0x28,0xf0|konOffs[i]);
|
||||||
chan[i].keyOn=false;
|
chan[i].keyOn=false;
|
||||||
}
|
}
|
||||||
|
@ -99,6 +124,7 @@ void DivPlatformGenesis::tick() {
|
||||||
#define rWrite(a,v) pendingWrites[a]=v;
|
#define rWrite(a,v) pendingWrites[a]=v;
|
||||||
|
|
||||||
int DivPlatformGenesis::dispatch(DivCommand c) {
|
int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
|
if (c.chan>5) return 0;
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
if (c.chan==5 && dacMode) {
|
if (c.chan==5 && dacMode) {
|
||||||
|
@ -112,8 +138,6 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
dacRate=dacRates[parent->song.sample[dacSample]->rate];
|
dacRate=dacRates[parent->song.sample[dacSample]->rate];
|
||||||
break;
|
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];
|
DivInstrument* ins=parent->song.ins[chan[c.chan].ins];
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
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]+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));
|
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].freq=644.0f*pow(2.0f,((float)c.value/12.0f));
|
||||||
chan[c.chan].freqL=notes[c.value%12];
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].keyOn=true;
|
chan[c.chan].keyOn=true;
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
class DivPlatformGenesis: public DivDispatch {
|
class DivPlatformGenesis: public DivDispatch {
|
||||||
struct Channel {
|
struct Channel {
|
||||||
unsigned char freqH, freqL;
|
unsigned char freqH, freqL;
|
||||||
|
int freq;
|
||||||
unsigned char ins;
|
unsigned char ins;
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, keyOn, keyOff;
|
bool active, insChanged, freqChanged, keyOn, keyOff;
|
||||||
signed char vol;
|
signed char vol;
|
||||||
unsigned char pan;
|
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];
|
Channel chan[10];
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
|
|
|
@ -65,26 +65,26 @@ void DivEngine::nextRow() {
|
||||||
snprintf(pb2,4095,"\x1b[37m %s",
|
snprintf(pb2,4095,"\x1b[37m %s",
|
||||||
formatNote(pat->data[curRow][0],pat->data[curRow][1]));
|
formatNote(pat->data[curRow][0],pat->data[curRow][1]));
|
||||||
strcat(pb3,pb2);
|
strcat(pb3,pb2);
|
||||||
if (pat->data[curRow][3]==255) {
|
if (pat->data[curRow][3]==-1) {
|
||||||
strcat(pb3,"\x1b[m--");
|
strcat(pb3,"\x1b[m--");
|
||||||
} else {
|
} else {
|
||||||
snprintf(pb2,4095,"\x1b[1;32m%.2x",pat->data[curRow][3]);
|
snprintf(pb2,4095,"\x1b[1;32m%.2x",pat->data[curRow][3]);
|
||||||
strcat(pb3,pb2);
|
strcat(pb3,pb2);
|
||||||
}
|
}
|
||||||
if (pat->data[curRow][2]==255) {
|
if (pat->data[curRow][2]==-1) {
|
||||||
strcat(pb3,"\x1b[m--");
|
strcat(pb3,"\x1b[m--");
|
||||||
} else {
|
} else {
|
||||||
snprintf(pb2,4095,"\x1b[0;36m%.2x",pat->data[curRow][2]);
|
snprintf(pb2,4095,"\x1b[0;36m%.2x",pat->data[curRow][2]);
|
||||||
strcat(pb3,pb2);
|
strcat(pb3,pb2);
|
||||||
}
|
}
|
||||||
for (int j=0; j<song.pat[i]->effectRows; j++) {
|
for (int j=0; j<song.pat[i]->effectRows; j++) {
|
||||||
if (pat->data[curRow][4+(j<<1)]==255) {
|
if (pat->data[curRow][4+(j<<1)]==-1) {
|
||||||
strcat(pb3,"\x1b[m--");
|
strcat(pb3,"\x1b[m--");
|
||||||
} else {
|
} else {
|
||||||
snprintf(pb2,4095,"\x1b[1;31m%.2x",pat->data[curRow][4+(j<<1)]);
|
snprintf(pb2,4095,"\x1b[1;31m%.2x",pat->data[curRow][4+(j<<1)]);
|
||||||
strcat(pb3,pb2);
|
strcat(pb3,pb2);
|
||||||
}
|
}
|
||||||
if (pat->data[curRow][5+(j<<1)]==255) {
|
if (pat->data[curRow][5+(j<<1)]==-1) {
|
||||||
strcat(pb3,"\x1b[m--");
|
strcat(pb3,"\x1b[m--");
|
||||||
} else {
|
} else {
|
||||||
snprintf(pb2,4095,"\x1b[1;37m%.2x",pat->data[curRow][5+(j<<1)]);
|
snprintf(pb2,4095,"\x1b[1;37m%.2x",pat->data[curRow][5+(j<<1)]);
|
||||||
|
@ -96,11 +96,33 @@ void DivEngine::nextRow() {
|
||||||
|
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
DivPattern* pat=song.pat[i]->data[curOrder];
|
DivPattern* pat=song.pat[i]->data[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
|
// effects
|
||||||
for (int j=0; j<song.pat[i]->effectRows; j++) {
|
for (int j=0; j<song.pat[i]->effectRows; j++) {
|
||||||
unsigned char effect=pat->data[curRow][4+(j<<1)];
|
unsigned char effect=pat->data[curRow][4+(j<<1)];
|
||||||
unsigned char effectVal=pat->data[curRow][5+(j<<1)];
|
unsigned char effectVal=pat->data[curRow][5+(j<<1)];
|
||||||
|
|
||||||
|
if (effectVal==-1) effectVal=0;
|
||||||
|
|
||||||
// per-system effect
|
// per-system effect
|
||||||
if (!perSystemEffect(i,effect,effectVal)) switch (effect) {
|
if (!perSystemEffect(i,effect,effectVal)) switch (effect) {
|
||||||
case 0x09: // speed 1
|
case 0x09: // speed 1
|
||||||
|
@ -120,26 +142,62 @@ void DivEngine::nextRow() {
|
||||||
case 0x08: // panning
|
case 0x08: // panning
|
||||||
dispatch->dispatch(DivCommand(DIV_CMD_PANNING,i,effectVal));
|
dispatch->dispatch(DivCommand(DIV_CMD_PANNING,i,effectVal));
|
||||||
break;
|
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;
|
speedAB=!speedAB;
|
||||||
}
|
}
|
||||||
|
// process stuff
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
if (chan[i].volSpeed!=0) {
|
||||||
|
chan[i].volume+=chan[i].volSpeed;
|
||||||
|
if (chan[i].volume>0x7f00) 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();
|
dispatch->tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue