VGM export: kind of implement sample loop

for PCE, NES and Genesis
kinda glitchy
This commit is contained in:
tildearrow 2022-01-25 03:12:53 -05:00
parent b6c536c907
commit 0c8ec07633
3 changed files with 59 additions and 10 deletions

View file

@ -1909,24 +1909,33 @@ SafeWriter* DivEngine::saveDMF() {
return w; return w;
} }
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff) { void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample) {
if (write.addr>=0xffff0000) { // Furnace special command if (write.addr>=0xffff0000) { // Furnace special command
unsigned char streamID=streamOff+((write.addr&0xff00)>>8); unsigned char streamID=streamOff+((write.addr&0xff00)>>8);
switch (write.addr&0xff) { switch (write.addr&0xff) {
case 0: // play sample case 0: // play sample
w->writeC(0x95); if (write.val<song.sampleLen) {
w->writeC(streamID); DivSample* sample=song.sample[write.val];
w->writeS(write.val); // sample number w->writeC(0x95);
w->writeC(0); // flags w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->loopStart==0)); // flags
if (sample->loopStart>0) {
loopTimer[streamID]=sample->rendLength;
loopSample[streamID]=write.val;
}
}
break; break;
case 1: // set sample freq case 1: // set sample freq
w->writeC(0x92); w->writeC(0x92);
w->writeC(streamID); w->writeC(streamID);
w->writeI(write.val); w->writeI(write.val);
loopFreq[streamID]=write.val;
break; break;
case 2: // stop sample case 2: // stop sample
w->writeC(0x94); w->writeC(0x94);
w->writeC(streamID); w->writeC(streamID);
loopSample[streamID]=-1;
break; break;
} }
return; return;
@ -2082,6 +2091,15 @@ SafeWriter* DivEngine::saveVGM() {
bool willExport[32]; bool willExport[32];
int streamIDs[32]; int streamIDs[32];
double loopTimer[DIV_MAX_CHANS];
double loopFreq[DIV_MAX_CHANS];
int loopSample[DIV_MAX_CHANS];
for (int i=0; i<DIV_MAX_CHANS; i++) {
loopTimer[i]=0;
loopFreq[i]=0;
loopSample[i]=-1;
}
bool writeDACSamples=false; bool writeDACSamples=false;
bool writeNESSamples=false; bool writeNESSamples=false;
@ -2260,6 +2278,14 @@ SafeWriter* DivEngine::saveVGM() {
} }
// write samples // write samples
unsigned int sampleSeek=0;
for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i];
logI("setting seek to %d\n",sampleSeek);
sample->rendOffContiguous=sampleSeek;
sampleSeek+=sample->rendLength;
}
if (writeDACSamples) for (int i=0; i<song.sampleLen; i++) { if (writeDACSamples) for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i]; DivSample* sample=song.sample[i];
w->writeC(0x67); w->writeC(0x67);
@ -2460,14 +2486,36 @@ SafeWriter* DivEngine::saveVGM() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites(); std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
for (DivRegWrite& j: writes) { for (DivRegWrite& j: writes) {
performVGMWrite(w,song.system[i],j,streamIDs[i]); performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample);
} }
writes.clear(); writes.clear();
} }
// check whether we need to loop
int totalWait=cycles>>MASTER_CLOCK_PREC;
for (int i=0; i<streamID; i++) {
if (loopSample[i]>=0) {
loopTimer[i]-=(loopFreq[i]/44100.0)*(double)totalWait;
if (loopTimer[i]<0) {
if (loopSample[i]<song.sampleLen) {
DivSample* sample=song.sample[loopSample[i]];
// insert loop
if (sample->loopStart<(int)sample->rendLength) {
//logW("inserting LOOP: %d\n",sample->rendOffContiguous);
w->writeC(0x93);
w->writeC(i);
w->writeI(sample->rendOffContiguous+sample->loopStart);
w->writeC(0x81);
w->writeI(sample->rendLength-sample->loopStart);
}
}
loopSample[i]=-1;
}
}
}
// write wait // write wait
w->writeC(0x61); w->writeC(0x61);
w->writeS(cycles>>MASTER_CLOCK_PREC); w->writeS(totalWait);
tickCount+=cycles>>MASTER_CLOCK_PREC; tickCount+=totalWait;
} }
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {

View file

@ -188,7 +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); void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample);
// 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);

View file

@ -6,7 +6,7 @@ struct DivSample {
signed char vol, pitch; signed char vol, pitch;
unsigned char depth; unsigned char depth;
short* data; short* data;
unsigned int rendLength, adpcmRendLength, rendOff, rendOffP; unsigned int rendLength, adpcmRendLength, rendOff, rendOffP, rendOffContiguous;
short* rendData; short* rendData;
unsigned char* adpcmRendData; unsigned char* adpcmRendData;
@ -25,6 +25,7 @@ struct DivSample {
adpcmRendLength(0), adpcmRendLength(0),
rendOff(0), rendOff(0),
rendOffP(0), rendOffP(0),
rendOffContiguous(0),
rendData(NULL), rendData(NULL),
adpcmRendData(NULL) {} adpcmRendData(NULL) {}
~DivSample(); ~DivSample();