VGM: experimental direct stream mode for YM2612

This commit is contained in:
tildearrow 2022-10-17 14:25:30 -05:00
parent 684b5a928b
commit 4723ed3972
5 changed files with 71 additions and 11 deletions

View File

@ -264,6 +264,9 @@ struct DivRegWrite {
struct DivDelayedWrite { struct DivDelayedWrite {
int time; int time;
DivRegWrite write; DivRegWrite write;
DivDelayedWrite(int t, unsigned int a, unsigned short v):
time(t),
write(a,v) {}
}; };
struct DivDispatchOscBuffer { struct DivDispatchOscBuffer {

View File

@ -27,11 +27,11 @@
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
void DivPlatformGenesis::processDAC() { void DivPlatformGenesis::processDAC(int iRate) {
if (softPCM) { if (softPCM) {
softPCMTimer+=chipClock/576; softPCMTimer+=chipClock/576;
if (softPCMTimer>rate) { if (softPCMTimer>iRate) {
softPCMTimer-=rate; softPCMTimer-=iRate;
int sample=0; int sample=0;
for (int i=5; i<7; i++) { for (int i=5; i<7; i++) {
@ -75,14 +75,14 @@ void DivPlatformGenesis::processDAC() {
} else { } else {
if (!chan[5].dacReady) { if (!chan[5].dacReady) {
chan[5].dacDelay+=32000; chan[5].dacDelay+=32000;
if (chan[5].dacDelay>=rate) { if (chan[5].dacDelay>=iRate) {
chan[5].dacDelay-=rate; chan[5].dacDelay-=iRate;
chan[5].dacReady=true; chan[5].dacReady=true;
} }
} }
if (chan[5].dacMode && chan[5].dacSample!=-1) { if (chan[5].dacMode && chan[5].dacSample!=-1) {
chan[5].dacPeriod+=chan[5].dacRate; chan[5].dacPeriod+=chan[5].dacRate;
if (chan[5].dacPeriod>=rate) { if (chan[5].dacPeriod>=iRate) {
DivSample* s=parent->getSample(chan[5].dacSample); DivSample* s=parent->getSample(chan[5].dacSample);
if (s->samples>0) { if (s->samples>0) {
if (!isMuted[5]) { if (!isMuted[5]) {
@ -106,7 +106,7 @@ void DivPlatformGenesis::processDAC() {
rWrite(0x2b,0); rWrite(0x2b,0);
} }
} }
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate; while (chan[5].dacPeriod>=iRate) chan[5].dacPeriod-=iRate;
} else { } else {
chan[5].dacSample=-1; chan[5].dacSample=-1;
} }
@ -120,7 +120,7 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
static int os[2]; static int os[2];
for (size_t h=start; h<start+len; h++) { for (size_t h=start; h<start+len; h++) {
processDAC(); processDAC(rate);
os[0]=0; os[1]=0; os[0]=0; os[1]=0;
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
@ -180,7 +180,7 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine(); ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine();
for (size_t h=start; h<start+len; h++) { for (size_t h=start; h<start+len; h++) {
processDAC(); processDAC(rate);
os[0]=0; os[1]=0; os[0]=0; os[1]=0;
if (!writes.empty()) { if (!writes.empty()) {
@ -237,6 +237,20 @@ void DivPlatformGenesis::acquire(short* bufL, short* bufR, size_t start, size_t
} }
} }
void DivPlatformGenesis::fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len) {
while (!writes.empty()) writes.pop_front();
for (size_t i=0; i<len; i++) {
processDAC(sRate);
while (!writes.empty()) {
QueuedWrite& w=writes.front();
stream.push_back(DivDelayedWrite(i,w.addr,w.val));
writes.pop_front();
}
}
regWrites.clear();
}
void DivPlatformGenesis::tick(bool sysTick) { void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<(softPCM?7:6); i++) { for (int i=0; i<(softPCM?7:6); i++) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;

View File

@ -119,12 +119,13 @@ class DivPlatformGenesis: public DivPlatformOPN {
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
inline void processDAC(); inline void processDAC(int iRate);
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len); void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
public: public:
void acquire(short* bufL, short* bufR, size_t start, size_t len); void acquire(short* bufL, short* bufR, size_t start, size_t len);
void fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len);
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);

View File

@ -948,6 +948,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
bool sampleDir[DIV_MAX_CHANS]; bool sampleDir[DIV_MAX_CHANS];
std::vector<unsigned int> chipVol; std::vector<unsigned int> chipVol;
std::vector<DivDelayedWrite> delayedWrites[32]; std::vector<DivDelayedWrite> delayedWrites[32];
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
for (int i=0; i<DIV_MAX_CHANS; i++) { for (int i=0; i<DIV_MAX_CHANS; i++) {
loopTimer[i]=0; loopTimer[i]=0;
@ -1942,8 +1943,42 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
// check whether we need to loop // check whether we need to loop
int totalWait=cycles>>MASTER_CLOCK_PREC; int totalWait=cycles>>MASTER_CLOCK_PREC;
if (directStream) { if (directStream) {
// render stream of all chips
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->fillStream(delayedWrites[i],44100,totalWait); disCont[i].dispatch->fillStream(delayedWrites[i],44100,totalWait);
for (DivDelayedWrite& j: delayedWrites[i]) {
sortedWrites.push_back(std::pair<int,DivDelayedWrite>(i,j));
}
delayedWrites[i].clear();
}
if (!sortedWrites.empty()) {
// sort if more than one chip
if (song.systemLen>1) {
std::sort(sortedWrites.begin(),sortedWrites.end(),[](const std::pair<int,DivDelayedWrite>& a, const std::pair<int,DivDelayedWrite>& b) -> bool {
return a.second.time<b.second.time;
});
}
// write it out
int lastOne=0;
for (std::pair<int,DivDelayedWrite>& i: sortedWrites) {
if (i.second.time>lastOne) {
// write delay
int delay=i.second.time-lastOne;
if (delay>16) {
w->writeC(0x61);
w->writeS(totalWait);
} else if (delay>0) {
w->writeC(0x70+delay-1);
}
lastOne=i.second.time;
}
// write write
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],directStream);
}
sortedWrites.clear();
totalWait-=lastOne;
} }
} else { } else {
for (int i=0; i<streamID; i++) { for (int i=0; i<streamID; i++) {

View File

@ -66,6 +66,7 @@ bool consoleMode=true;
bool displayEngineFailError=false; bool displayEngineFailError=false;
bool cmdOutBinary=false; bool cmdOutBinary=false;
bool vgmOutDirect=false;
std::vector<TAParam> params; std::vector<TAParam> params;
@ -122,6 +123,11 @@ TAParamResult pBinary(String val) {
return TA_PARAM_SUCCESS; return TA_PARAM_SUCCESS;
} }
TAParamResult pDirect(String val) {
vgmOutDirect=true;
return TA_PARAM_SUCCESS;
}
TAParamResult pLogLevel(String val) { TAParamResult pLogLevel(String val) {
if (val=="trace") { if (val=="trace") {
logLevel=LOGLEVEL_TRACE; logLevel=LOGLEVEL_TRACE;
@ -289,6 +295,7 @@ void initParams() {
params.push_back(TAParam("a","audio",true,pAudio,"jack|sdl","set audio engine (SDL by default)")); params.push_back(TAParam("a","audio",true,pAudio,"jack|sdl","set audio engine (SDL by default)"));
params.push_back(TAParam("o","output",true,pOutput,"<filename>","output audio to file")); params.push_back(TAParam("o","output",true,pOutput,"<filename>","output audio to file"));
params.push_back(TAParam("O","vgmout",true,pVGMOut,"<filename>","output .vgm data")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"<filename>","output .vgm data"));
params.push_back(TAParam("D","direct",false,pDirect,"","set VGM export direct stream mode"));
params.push_back(TAParam("Z","zsmout",true,pZSMOut,"<filename>","output .zsm data for Commander X16 Zsound")); params.push_back(TAParam("Z","zsmout",true,pZSMOut,"<filename>","output .zsm data for Commander X16 Zsound"));
params.push_back(TAParam("C","cmdout",true,pCmdOut,"<filename>","output command stream")); params.push_back(TAParam("C","cmdout",true,pCmdOut,"<filename>","output command stream"));
params.push_back(TAParam("b","binary",false,pBinary,"","set command stream output format to binary")); params.push_back(TAParam("b","binary",false,pBinary,"","set command stream output format to binary"));
@ -490,7 +497,7 @@ int main(int argc, char** argv) {
} }
} }
if (vgmOutName!="") { if (vgmOutName!="") {
SafeWriter* w=e.saveVGM(); SafeWriter* w=e.saveVGM(NULL,true,0x171,false,vgmOutDirect);
if (w!=NULL) { if (w!=NULL) {
FILE* f=fopen(vgmOutName.c_str(),"wb"); FILE* f=fopen(vgmOutName.c_str(),"wb");
if (f!=NULL) { if (f!=NULL) {