mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-02 02:52:40 +00:00
VGM: experimental direct stream mode for YM2612
This commit is contained in:
parent
684b5a928b
commit
4723ed3972
5 changed files with 71 additions and 11 deletions
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue