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 {
int time;
DivRegWrite write;
DivDelayedWrite(int t, unsigned int a, unsigned short v):
time(t),
write(a,v) {}
};
struct DivDispatchOscBuffer {

View file

@ -27,11 +27,11 @@
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
void DivPlatformGenesis::processDAC() {
void DivPlatformGenesis::processDAC(int iRate) {
if (softPCM) {
softPCMTimer+=chipClock/576;
if (softPCMTimer>rate) {
softPCMTimer-=rate;
if (softPCMTimer>iRate) {
softPCMTimer-=iRate;
int sample=0;
for (int i=5; i<7; i++) {
@ -75,14 +75,14 @@ void DivPlatformGenesis::processDAC() {
} else {
if (!chan[5].dacReady) {
chan[5].dacDelay+=32000;
if (chan[5].dacDelay>=rate) {
chan[5].dacDelay-=rate;
if (chan[5].dacDelay>=iRate) {
chan[5].dacDelay-=iRate;
chan[5].dacReady=true;
}
}
if (chan[5].dacMode && chan[5].dacSample!=-1) {
chan[5].dacPeriod+=chan[5].dacRate;
if (chan[5].dacPeriod>=rate) {
if (chan[5].dacPeriod>=iRate) {
DivSample* s=parent->getSample(chan[5].dacSample);
if (s->samples>0) {
if (!isMuted[5]) {
@ -106,7 +106,7 @@ void DivPlatformGenesis::processDAC() {
rWrite(0x2b,0);
}
}
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate;
while (chan[5].dacPeriod>=iRate) chan[5].dacPeriod-=iRate;
} else {
chan[5].dacSample=-1;
}
@ -120,7 +120,7 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
static int os[2];
for (size_t h=start; h<start+len; h++) {
processDAC();
processDAC(rate);
os[0]=0; os[1]=0;
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();
for (size_t h=start; h<start+len; h++) {
processDAC();
processDAC(rate);
os[0]=0; os[1]=0;
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) {
for (int i=0; i<(softPCM?7:6); i++) {
if (i==2 && extMode) continue;

View file

@ -119,12 +119,13 @@ class DivPlatformGenesis: public DivPlatformOPN {
friend void putDispatchChip(void*,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_ymfm(short* bufL, short* bufR, size_t start, size_t len);
public:
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);
void* getChanState(int chan);
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];
std::vector<unsigned int> chipVol;
std::vector<DivDelayedWrite> delayedWrites[32];
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
for (int i=0; i<DIV_MAX_CHANS; i++) {
loopTimer[i]=0;
@ -1942,8 +1943,42 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
// check whether we need to loop
int totalWait=cycles>>MASTER_CLOCK_PREC;
if (directStream) {
// render stream of all chips
for (int i=0; i<song.systemLen; i++) {
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 {
for (int i=0; i<streamID; i++) {

View file

@ -66,6 +66,7 @@ bool consoleMode=true;
bool displayEngineFailError=false;
bool cmdOutBinary=false;
bool vgmOutDirect=false;
std::vector<TAParam> params;
@ -122,6 +123,11 @@ TAParamResult pBinary(String val) {
return TA_PARAM_SUCCESS;
}
TAParamResult pDirect(String val) {
vgmOutDirect=true;
return TA_PARAM_SUCCESS;
}
TAParamResult pLogLevel(String val) {
if (val=="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("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("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("C","cmdout",true,pCmdOut,"<filename>","output command stream"));
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!="") {
SafeWriter* w=e.saveVGM();
SafeWriter* w=e.saveVGM(NULL,true,0x171,false,vgmOutDirect);
if (w!=NULL) {
FILE* f=fopen(vgmOutName.c_str(),"wb");
if (f!=NULL) {