earliest VGM export!
only supports single-chip Genesis for now the other systems will be added shortly
This commit is contained in:
parent
35ee06d6cf
commit
858d5343b8
|
@ -110,14 +110,21 @@ struct DivDelayedCommand {
|
||||||
|
|
||||||
struct DivRegWrite {
|
struct DivRegWrite {
|
||||||
/**
|
/**
|
||||||
* an address of 0xffffff00 indicates a Furnace specific command.
|
* an address of 0xffffxx00 indicates a Furnace specific command.
|
||||||
* the following addresses are available:
|
* the following addresses are available:
|
||||||
* - 0xffffff00: start sample playback
|
* - 0xffffxx00: start sample playback
|
||||||
|
* - xx is the instance ID
|
||||||
* - data is the sample number
|
* - data is the sample number
|
||||||
|
* - 0xffffxx01: set sample rate
|
||||||
|
* - xx is the instance ID
|
||||||
|
* - data is the sample rate
|
||||||
|
* - 0xffffxx02: stop sample playback
|
||||||
|
* - xx is the instance ID
|
||||||
|
* - 0xffffffff: reset
|
||||||
*/
|
*/
|
||||||
unsigned int addr;
|
unsigned int addr;
|
||||||
unsigned char val;
|
unsigned short val;
|
||||||
DivRegWrite(unsigned int a, unsigned char v):
|
DivRegWrite(unsigned int a, unsigned short v):
|
||||||
addr(a), val(v) {}
|
addr(a), val(v) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,7 +259,7 @@ class DivDispatch {
|
||||||
/**
|
/**
|
||||||
* enable register dumping.
|
* enable register dumping.
|
||||||
*/
|
*/
|
||||||
void toggleRegisterDump(bool enable);
|
virtual void toggleRegisterDump(bool enable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get register writes.
|
* get register writes.
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
#include <fmt/printf.h>
|
#include <fmt/printf.h>
|
||||||
|
|
||||||
|
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||||
|
|
||||||
void process(void* u, float** in, float** out, int inChans, int outChans, unsigned int size) {
|
void process(void* u, float** in, float** out, int inChans, int outChans, unsigned int size) {
|
||||||
((DivEngine*)u)->nextBuf(in,out,inChans,outChans,size);
|
((DivEngine*)u)->nextBuf(in,out,inChans,outChans,size);
|
||||||
}
|
}
|
||||||
|
@ -1907,6 +1909,54 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff) {
|
||||||
|
if (write.addr>=0xffff0000) { // Furnace special command
|
||||||
|
unsigned char streamID=streamOff+((write.addr&0xff00)>>8);
|
||||||
|
switch (write.addr&0xff) {
|
||||||
|
case 0: // play sample
|
||||||
|
w->writeC(0x95);
|
||||||
|
w->writeC(streamID);
|
||||||
|
w->writeS(write.val); // sample number
|
||||||
|
w->writeC(0); // flags
|
||||||
|
break;
|
||||||
|
case 1: // set sample freq
|
||||||
|
w->writeC(0x92);
|
||||||
|
w->writeC(streamID);
|
||||||
|
w->writeI(write.val);
|
||||||
|
break;
|
||||||
|
case 2: // stop sample
|
||||||
|
w->writeC(0x94);
|
||||||
|
w->writeC(streamID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (sys) {
|
||||||
|
case DIV_SYSTEM_GENESIS:
|
||||||
|
case DIV_SYSTEM_GENESIS_EXT:
|
||||||
|
switch (write.addr>>8) {
|
||||||
|
case 0: // port 0
|
||||||
|
w->writeC(0x52);
|
||||||
|
w->writeC(write.addr&0xff);
|
||||||
|
w->writeC(write.val);
|
||||||
|
break;
|
||||||
|
case 1: // port 1
|
||||||
|
w->writeC(0x53);
|
||||||
|
w->writeC(write.addr&0xff);
|
||||||
|
w->writeC(write.val);
|
||||||
|
break;
|
||||||
|
case 2: // PSG
|
||||||
|
w->writeC(0x50);
|
||||||
|
w->writeC(write.val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logW("write not handled!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SafeWriter* DivEngine::saveVGM() {
|
SafeWriter* DivEngine::saveVGM() {
|
||||||
stop();
|
stop();
|
||||||
setOrder(0);
|
setOrder(0);
|
||||||
|
@ -1916,44 +1966,52 @@ SafeWriter* DivEngine::saveVGM() {
|
||||||
bool done=false;
|
bool done=false;
|
||||||
|
|
||||||
int hasSN=0;
|
int hasSN=0;
|
||||||
//int hasOPLL=0;
|
int snNoiseConfig=9;
|
||||||
|
int snNoiseSize=16;
|
||||||
|
int snFlags=0;
|
||||||
|
int hasOPLL=0;
|
||||||
int hasOPN2=0;
|
int hasOPN2=0;
|
||||||
int hasOPM=0;
|
int hasOPM=0;
|
||||||
int hasSegaPCM=0;
|
int hasSegaPCM=0;
|
||||||
//int hasRFC=0;
|
int segaPCMOffset=0x2000;
|
||||||
//int hasOPN=0;
|
int hasRFC=0;
|
||||||
//int hasOPNA=0;
|
int hasOPN=0;
|
||||||
|
int hasOPNA=0;
|
||||||
int hasOPNB=0;
|
int hasOPNB=0;
|
||||||
//int hasOPL2=0;
|
int hasOPL2=0;
|
||||||
//int hasOPL=0;
|
int hasOPL=0;
|
||||||
//int hasY8950=0;
|
int hasY8950=0;
|
||||||
//int hasOPL3=0;
|
int hasOPL3=0;
|
||||||
//int hasZ280=0;
|
int hasOPL4=0;
|
||||||
//int hasRFC1=0;
|
int hasOPX=0;
|
||||||
//int hasPWM=0;
|
int hasZ280=0;
|
||||||
|
int hasRFC1=0;
|
||||||
|
int hasPWM=0;
|
||||||
int hasAY=0;
|
int hasAY=0;
|
||||||
|
int ayConfig=0;
|
||||||
|
int ayFlags=0;
|
||||||
int hasGB=0;
|
int hasGB=0;
|
||||||
int hasNES=0;
|
int hasNES=0;
|
||||||
//int hasMultiPCM=0;
|
int hasMultiPCM=0;
|
||||||
//int hasuPD7759=0;
|
int hasuPD7759=0;
|
||||||
//int hasOKIM6258=0;
|
int hasOKIM6258=0;
|
||||||
//int hasK054539=0;
|
int hasK054539=0;
|
||||||
//int hasOKIM6295=0;
|
int hasOKIM6295=0;
|
||||||
//int hasK051649=0;
|
int hasK051649=0;
|
||||||
//int hasK054539=0;
|
|
||||||
int hasPCE=0;
|
int hasPCE=0;
|
||||||
//int hasNamco=0;
|
int hasNamco=0;
|
||||||
//int hasK053260=0;
|
int hasK053260=0;
|
||||||
//int hasPOKEY=0;
|
int hasPOKEY=0;
|
||||||
//int hasQSound=0;
|
int hasQSound=0;
|
||||||
//int hasSCSP=0;
|
int hasSCSP=0;
|
||||||
//int hasSwan=0;
|
int hasSwan=0;
|
||||||
//int hasVSU=0;
|
int hasVSU=0;
|
||||||
int hasSAA=0;
|
int hasSAA=0;
|
||||||
//int hasES5503=0;
|
int hasES5503=0;
|
||||||
//int hasX1=0;
|
int hasES5505=0;
|
||||||
//int hasC352=0;
|
int hasX1=0;
|
||||||
//int hasGA20=0;
|
int hasC352=0;
|
||||||
|
int hasGA20=0;
|
||||||
|
|
||||||
SafeWriter* w=new SafeWriter;
|
SafeWriter* w=new SafeWriter;
|
||||||
w->init();
|
w->init();
|
||||||
|
@ -1963,108 +2021,254 @@ SafeWriter* DivEngine::saveVGM() {
|
||||||
w->writeI(0); // will be written later
|
w->writeI(0); // will be written later
|
||||||
w->writeI(0x171); // VGM 1.71
|
w->writeI(0x171); // VGM 1.71
|
||||||
|
|
||||||
|
bool willExport[32];
|
||||||
|
int streamIDs[32];
|
||||||
|
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
bool willExport=false;
|
willExport[i]=false;
|
||||||
|
streamIDs[i]=0;
|
||||||
switch (song.system[i]) {
|
switch (song.system[i]) {
|
||||||
case DIV_SYSTEM_GENESIS:
|
case DIV_SYSTEM_GENESIS:
|
||||||
case DIV_SYSTEM_GENESIS_EXT:
|
case DIV_SYSTEM_GENESIS_EXT:
|
||||||
if (!hasOPN2) {
|
if (!hasOPN2) {
|
||||||
hasOPN2=7670454;
|
hasOPN2=7670454;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
if (!hasSN) {
|
if (!hasSN) {
|
||||||
hasSN=3579545;
|
hasSN=3579545;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_SMS:
|
case DIV_SYSTEM_SMS:
|
||||||
if (!hasSN) {
|
if (!hasSN) {
|
||||||
hasSN=3579545;
|
hasSN=3579545;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_GB:
|
case DIV_SYSTEM_GB:
|
||||||
if (!hasGB) {
|
if (!hasGB) {
|
||||||
hasGB=4194304;
|
hasGB=4194304;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_PCE:
|
case DIV_SYSTEM_PCE:
|
||||||
if (!hasPCE) {
|
if (!hasPCE) {
|
||||||
hasPCE=3579545;
|
hasPCE=3579545;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_NES:
|
case DIV_SYSTEM_NES:
|
||||||
if (!hasNES) {
|
if (!hasNES) {
|
||||||
hasNES=1789773;
|
hasNES=1789773;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_ARCADE:
|
case DIV_SYSTEM_ARCADE:
|
||||||
if (!hasOPM) {
|
if (!hasOPM) {
|
||||||
hasOPM=3579545;
|
hasOPM=3579545;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
if (!hasSegaPCM) {
|
if (!hasSegaPCM) {
|
||||||
hasSegaPCM=4000000;
|
hasSegaPCM=4000000;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_YM2610:
|
case DIV_SYSTEM_YM2610:
|
||||||
case DIV_SYSTEM_YM2610_EXT:
|
case DIV_SYSTEM_YM2610_EXT:
|
||||||
if (!hasOPNB) {
|
if (!hasOPNB) {
|
||||||
hasOPNB=8000000;
|
hasOPNB=8000000;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_AY8910:
|
case DIV_SYSTEM_AY8910:
|
||||||
case DIV_SYSTEM_AY8930:
|
case DIV_SYSTEM_AY8930:
|
||||||
if (!hasAY) {
|
if (!hasAY) {
|
||||||
hasAY=1789773;
|
hasAY=1789773;
|
||||||
willExport=true;
|
ayConfig=(song.system[i]==DIV_SYSTEM_AY8930)?3:0;
|
||||||
|
ayFlags=1;
|
||||||
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_SAA1099:
|
case DIV_SYSTEM_SAA1099:
|
||||||
if (!hasSAA) {
|
if (!hasSAA) {
|
||||||
hasSAA=8000000;
|
hasSAA=8000000;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_YM2612:
|
case DIV_SYSTEM_YM2612:
|
||||||
if (!hasOPN2) {
|
if (!hasOPN2) {
|
||||||
hasOPN2=7670454;
|
hasOPN2=7670454;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_YM2151:
|
case DIV_SYSTEM_YM2151:
|
||||||
if (!hasOPM) {
|
if (!hasOPM) {
|
||||||
hasOPM=3579545;
|
hasOPM=3579545;
|
||||||
willExport=true;
|
willExport[i]=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (willExport) {
|
if (willExport[i]) {
|
||||||
disCont[i].dispatch->toggleRegisterDump(true);
|
disCont[i].dispatch->toggleRegisterDump(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write chips and stuff
|
||||||
|
w->writeI(hasSN);
|
||||||
|
w->writeI(hasOPLL);
|
||||||
|
w->writeI(0);
|
||||||
|
w->writeI(0); // length. will be written later
|
||||||
|
w->writeI(0); // loop. will be written later
|
||||||
|
w->writeI(0); // loop length. why is this necessary?
|
||||||
|
w->writeI(0); // tick rate
|
||||||
|
w->writeS(snNoiseConfig);
|
||||||
|
w->writeC(snNoiseSize);
|
||||||
|
w->writeC(snFlags);
|
||||||
|
w->writeI(hasOPN2);
|
||||||
|
w->writeI(hasOPM);
|
||||||
|
w->writeI(0x100-w->tell()); // data pointer
|
||||||
|
w->writeI(hasSegaPCM);
|
||||||
|
w->writeI(segaPCMOffset);
|
||||||
|
w->writeI(hasRFC);
|
||||||
|
w->writeI(hasOPN);
|
||||||
|
w->writeI(hasOPNA);
|
||||||
|
w->writeI(hasOPNB);
|
||||||
|
w->writeI(hasOPL2);
|
||||||
|
w->writeI(hasOPL);
|
||||||
|
w->writeI(hasY8950);
|
||||||
|
w->writeI(hasOPL3);
|
||||||
|
w->writeI(hasOPL4);
|
||||||
|
w->writeI(hasOPX);
|
||||||
|
w->writeI(hasZ280);
|
||||||
|
w->writeI(hasRFC1);
|
||||||
|
w->writeI(hasPWM);
|
||||||
|
w->writeI(hasAY);
|
||||||
|
w->writeC(ayConfig);
|
||||||
|
w->writeC(ayFlags);
|
||||||
|
w->writeC(ayFlags); // OPN
|
||||||
|
w->writeC(ayFlags); // OPNA
|
||||||
|
w->writeC(0); // volume
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeC(0); // loop count
|
||||||
|
w->writeC(0); // loop modifier
|
||||||
|
w->writeI(hasGB);
|
||||||
|
w->writeI(hasNES);
|
||||||
|
w->writeI(hasMultiPCM);
|
||||||
|
w->writeI(hasuPD7759);
|
||||||
|
w->writeI(hasOKIM6258);
|
||||||
|
w->writeC(0); // flags
|
||||||
|
w->writeC(0); // K flags
|
||||||
|
w->writeC(0); // C140 chip type
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeI(hasOKIM6295);
|
||||||
|
w->writeI(hasK051649);
|
||||||
|
w->writeI(hasK054539);
|
||||||
|
w->writeI(hasPCE);
|
||||||
|
w->writeI(hasNamco);
|
||||||
|
w->writeI(hasK053260);
|
||||||
|
w->writeI(hasPOKEY);
|
||||||
|
w->writeI(hasQSound);
|
||||||
|
w->writeI(hasSCSP);
|
||||||
|
w->writeI(0); // extra header. currently not written to
|
||||||
|
w->writeI(hasSwan);
|
||||||
|
w->writeI(hasVSU);
|
||||||
|
w->writeI(hasSAA);
|
||||||
|
w->writeI(hasES5503);
|
||||||
|
w->writeI(hasES5505);
|
||||||
|
w->writeC(0); // 5503 chans
|
||||||
|
w->writeC(0); // 5505 chans
|
||||||
|
w->writeC(0); // C352 clock divider
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeI(hasX1);
|
||||||
|
w->writeI(hasC352);
|
||||||
|
w->writeI(hasGA20);
|
||||||
|
for (int i=0; i<7; i++) { // reserved
|
||||||
|
w->writeI(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write samples
|
||||||
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
DivSample* sample=song.sample[i];
|
||||||
|
w->writeC(0x67);
|
||||||
|
w->writeC(0x66);
|
||||||
|
w->writeC(0); // for now!
|
||||||
|
w->writeI(sample->rendLength);
|
||||||
|
if (sample->depth==8) {
|
||||||
|
for (unsigned int j=0; j<sample->rendLength; j++) {
|
||||||
|
w->writeC((unsigned char)sample->rendData[j]+0x80);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int j=0; j<sample->rendLength; j++) {
|
||||||
|
w->writeC(((unsigned short)sample->rendData[j]+0x8000)>>8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize streams
|
||||||
|
int streamID=0;
|
||||||
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
|
if (!willExport[i]) continue;
|
||||||
|
streamIDs[i]=streamID;
|
||||||
|
switch (song.system[i]) {
|
||||||
|
case DIV_SYSTEM_GENESIS:
|
||||||
|
case DIV_SYSTEM_GENESIS_EXT:
|
||||||
|
w->writeC(0x90);
|
||||||
|
w->writeC(streamID);
|
||||||
|
w->writeC(0x02);
|
||||||
|
w->writeC(0); // port
|
||||||
|
w->writeC(0x2a); // DAC
|
||||||
|
|
||||||
|
w->writeC(0x91);
|
||||||
|
w->writeC(streamID);
|
||||||
|
w->writeC(0);
|
||||||
|
w->writeC(1);
|
||||||
|
w->writeC(0);
|
||||||
|
|
||||||
|
w->writeC(0x92);
|
||||||
|
w->writeC(streamID);
|
||||||
|
w->writeI(32000); // default
|
||||||
|
streamID++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logE("what? trying to play sample on unsupported system\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write song data
|
||||||
|
size_t tickCount=0;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
if (nextTick()) done=true;
|
if (nextTick()) done=true;
|
||||||
// get register dumps
|
// get register dumps
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
for (DivRegWrite& j: disCont[i].dispatch->getRegisterWrites()) {
|
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||||
printf("- (%d) %.2x = %.2x\n",i,j.addr,j.val);
|
for (DivRegWrite& j: writes) {
|
||||||
|
performVGMWrite(w,song.system[i],j,streamIDs[i]);
|
||||||
}
|
}
|
||||||
|
writes.clear();
|
||||||
}
|
}
|
||||||
|
// write wait
|
||||||
|
w->writeC(0x61);
|
||||||
|
w->writeS(cycles>>MASTER_CLOCK_PREC);
|
||||||
|
tickCount+=cycles>>MASTER_CLOCK_PREC;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
disCont[i].dispatch->toggleRegisterDump(false);
|
disCont[i].dispatch->toggleRegisterDump(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// finish file
|
||||||
|
size_t len=w->size()-4;
|
||||||
|
w->seek(4,SEEK_SET);
|
||||||
|
w->writeI(len);
|
||||||
|
w->seek(0x18,SEEK_SET);
|
||||||
|
w->writeI(tickCount);
|
||||||
|
// loop not handled for now
|
||||||
|
w->writeI(0);
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
isBusy.unlock();
|
isBusy.unlock();
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,6 +188,7 @@ class DivEngine {
|
||||||
void processRow(int i, bool afterDelay);
|
void processRow(int i, bool afterDelay);
|
||||||
void nextOrder();
|
void nextOrder();
|
||||||
void nextRow();
|
void nextRow();
|
||||||
|
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff);
|
||||||
// returns true if end of song.
|
// returns true if end of song.
|
||||||
bool nextTick(bool noAccum=false);
|
bool nextTick(bool noAccum=false);
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
|
|
|
@ -192,6 +192,7 @@ void DivPlatformGenesis::tick() {
|
||||||
immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
|
immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
|
||||||
if (chan[i].furnaceDac) {
|
if (chan[i].furnaceDac) {
|
||||||
dacRate=(1280000*1.25)/chan[i].baseFreq;
|
dacRate=(1280000*1.25)/chan[i].baseFreq;
|
||||||
|
if (dumpWrites) addWrite(0xffff0001,chan[i].baseFreq);
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
|
@ -202,6 +203,11 @@ void DivPlatformGenesis::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
psg.tick();
|
psg.tick();
|
||||||
|
|
||||||
|
for (DivRegWrite& i: psg.getRegisterWrites()) {
|
||||||
|
if (dumpWrites) addWrite(i.addr,i.val);
|
||||||
|
}
|
||||||
|
psg.getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformGenesis::octave(int freq) {
|
int DivPlatformGenesis::octave(int freq) {
|
||||||
|
@ -277,7 +283,10 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
dacSample=ins->amiga.initSample;
|
dacSample=ins->amiga.initSample;
|
||||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
||||||
}
|
}
|
||||||
dacPos=0;
|
dacPos=0;
|
||||||
dacPeriod=0;
|
dacPeriod=0;
|
||||||
|
@ -288,11 +297,15 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
dacSample=12*sampleBank+c.value%12;
|
dacSample=12*sampleBank+c.value%12;
|
||||||
if (dacSample>=parent->song.sampleLen) {
|
if (dacSample>=parent->song.sampleLen) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
||||||
}
|
}
|
||||||
dacPos=0;
|
dacPos=0;
|
||||||
dacPeriod=0;
|
dacPeriod=0;
|
||||||
dacRate=1280000/parent->song.sample[dacSample]->rate;
|
dacRate=1280000/parent->song.sample[dacSample]->rate;
|
||||||
|
if (dumpWrites) addWrite(0xffff0001,parent->song.sample[dacSample]->rate);
|
||||||
chan[c.chan].furnaceDac=false;
|
chan[c.chan].furnaceDac=false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -342,6 +355,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_OFF:
|
case DIV_CMD_NOTE_OFF:
|
||||||
if (c.chan==5) {
|
if (c.chan==5) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
}
|
}
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
|
@ -522,6 +536,11 @@ void DivPlatformGenesis::forceIns() {
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
|
||||||
|
DivDispatch::toggleRegisterDump(enable);
|
||||||
|
psg.toggleRegisterDump(enable);
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::reset() {
|
void DivPlatformGenesis::reset() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
OPN2_Reset(&fm);
|
OPN2_Reset(&fm);
|
||||||
|
|
|
@ -78,6 +78,7 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
bool isStereo();
|
bool isStereo();
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
bool keyOffAffectsPorta(int ch);
|
bool keyOffAffectsPorta(int ch);
|
||||||
|
void toggleRegisterDump(bool enable);
|
||||||
void setPAL(bool pal);
|
void setPAL(bool pal);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#define FREQ_BASE 1712.0f
|
#define FREQ_BASE 1712.0f
|
||||||
|
|
||||||
#define rWrite(v) {sn->write(v); if (dumpWrites) {addWrite(0,v);} }
|
#define rWrite(v) {sn->write(v); if (dumpWrites) {addWrite(0x200,v);} }
|
||||||
|
|
||||||
void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
sn->sound_stream_update(bufL+start,len);
|
sn->sound_stream_update(bufL+start,len);
|
||||||
|
|
Loading…
Reference in New Issue