Merge branches 'master' and 'k053260' of https://github.com/tildearrow/furnace into k053260
This commit is contained in:
commit
7b49b4b8e0
161 changed files with 1190 additions and 864 deletions
|
|
@ -284,6 +284,8 @@ struct DivRegWrite {
|
|||
* - xx is the instance ID
|
||||
* - 0xffffxx03: set sample playback direction
|
||||
* - x is the instance ID
|
||||
* - 0xffffxx04: switch sample bank
|
||||
* - for use in VGM export
|
||||
* - 0xffffffff: reset
|
||||
*/
|
||||
unsigned int addr;
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream);
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
|
|||
|
|
@ -1166,6 +1166,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define DRSLD2R(x) \
|
||||
if (chan[i].state.op[x].dr<dr) dr=chan[i].state.op[x].dr; \
|
||||
if (chan[i].state.op[x].sl<sl) sl=chan[i].state.op[x].sl; \
|
||||
if (chan[i].state.op[x].d2r<d2r) d2r=chan[i].state.op[x].d2r;
|
||||
|
||||
void DivPlatformGenesis::forceIns() {
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
|
|
@ -1190,7 +1195,29 @@ void DivPlatformGenesis::forceIns() {
|
|||
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
|
||||
if (chan[i].active) {
|
||||
if (i<5 || !chan[i].dacMode) {
|
||||
bool sustained=false;
|
||||
unsigned char dr=chan[i].state.op[3].dr;
|
||||
unsigned char sl=chan[i].state.op[3].sl;
|
||||
unsigned char d2r=chan[i].state.op[3].d2r;
|
||||
|
||||
switch (chan[i].state.alg&7) {
|
||||
case 4:
|
||||
DRSLD2R(2);
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
DRSLD2R(2);
|
||||
DRSLD2R(1);
|
||||
break;
|
||||
case 7:
|
||||
DRSLD2R(2);
|
||||
DRSLD2R(1);
|
||||
DRSLD2R(3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dr<2 || (sl<15 && d2r<2)) sustained=true;
|
||||
if ((i<5 || !chan[i].dacMode) && sustained) {
|
||||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,7 +346,11 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
rWrite(0x4012,(dpcmAddr>>6)&0xff);
|
||||
rWrite(0x4013,dpcmLen&0xff);
|
||||
rWrite(0x4015,31);
|
||||
dpcmBank=dpcmAddr>>14;
|
||||
if (dpcmBank!=(dpcmAddr>>14)) {
|
||||
dpcmBank=dpcmAddr>>14;
|
||||
logV("switching bank to %d",dpcmBank);
|
||||
if (dumpWrites) addWrite(0xffff0004,dpcmBank);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nextDPCMFreq>=0) {
|
||||
|
|
@ -425,7 +429,11 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
rWrite(0x4012,(dpcmAddr>>6)&0xff);
|
||||
rWrite(0x4013,dpcmLen&0xff);
|
||||
rWrite(0x4015,31);
|
||||
dpcmBank=dpcmAddr>>14;
|
||||
if (dpcmBank!=(dpcmAddr>>14)) {
|
||||
dpcmBank=dpcmAddr>>14;
|
||||
logV("switching bank to %d",dpcmBank);
|
||||
if (dumpWrites) addWrite(0xffff0004,dpcmBank);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -854,6 +862,7 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
|||
dpcmMem=new unsigned char[262144];
|
||||
dpcmMemLen=0;
|
||||
dpcmBank=0;
|
||||
if (dumpWrites) addWrite(0xffff0004,dpcmBank);
|
||||
|
||||
init_nla_table(500,500);
|
||||
reset();
|
||||
|
|
|
|||
|
|
@ -1691,6 +1691,10 @@ void DivEngine::runMidiTime(int totalCycles) {
|
|||
}
|
||||
|
||||
void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) {
|
||||
if (!size) {
|
||||
logW("nextBuf called with size 0!");
|
||||
return;
|
||||
}
|
||||
lastLoopPos=-1;
|
||||
|
||||
if (out!=NULL) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream) {
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream) {
|
||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||
unsigned char baseAddr2=isSecond?0x80:0;
|
||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||
|
|
@ -587,6 +587,28 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (write.addr==0xffff0004) { // switch sample bank
|
||||
switch (sys) {
|
||||
case DIV_SYSTEM_NES: {
|
||||
unsigned int bankAddr=bankOffset+(write.val<<14);
|
||||
w->writeC(0x68);
|
||||
w->writeC(0x6c);
|
||||
w->writeC(0x07|(isSecond?0x80:0x00));
|
||||
w->writeC(bankAddr&0xff);
|
||||
w->writeC((bankAddr>>8)&0xff);
|
||||
w->writeC((bankAddr>>16)&0xff);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0xc0);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0x40);
|
||||
w->writeC(0x00);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (write.addr>=0xffff0000) { // Furnace special command
|
||||
if (!directStream) {
|
||||
unsigned char streamID=streamOff+((write.addr&0xff00)>>8);
|
||||
|
|
@ -610,11 +632,14 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 1: // set sample freq
|
||||
case 1: { // set sample freq
|
||||
int realFreq=write.val;
|
||||
if (realFreq<0) realFreq=0;
|
||||
if (realFreq>44100) realFreq=44100;
|
||||
w->writeC(0x92);
|
||||
w->writeC(streamID);
|
||||
w->writeI(write.val);
|
||||
loopFreq[streamID]=write.val;
|
||||
w->writeI(realFreq);
|
||||
loopFreq[streamID]=realFreq;
|
||||
if (pendingFreq[streamID]!=-1) {
|
||||
DivSample* sample=song.sample[pendingFreq[streamID]];
|
||||
w->writeC(0x95);
|
||||
|
|
@ -629,6 +654,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
pendingFreq[streamID]=-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // stop sample
|
||||
w->writeC(0x94);
|
||||
w->writeC(streamID);
|
||||
|
|
@ -1069,6 +1095,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
bool willExport[DIV_MAX_CHIPS];
|
||||
bool isSecond[DIV_MAX_CHIPS];
|
||||
int streamIDs[DIV_MAX_CHIPS];
|
||||
size_t bankOffset[DIV_MAX_CHIPS];
|
||||
double loopTimer[DIV_MAX_CHANS];
|
||||
double loopFreq[DIV_MAX_CHANS];
|
||||
int loopSample[DIV_MAX_CHANS];
|
||||
|
|
@ -1086,6 +1113,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
bool mayWriteRate=(fmod(curSubSong->hz,1.0)<0.00001 || fmod(curSubSong->hz,1.0)>0.99999);
|
||||
int countDown=MAX(0,trailingTicks)+1;
|
||||
|
||||
memset(bankOffset,0,DIV_MAX_CHIPS*sizeof(size_t));
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
loopTimer[i]=0;
|
||||
loopFreq[i]=0;
|
||||
|
|
@ -1110,6 +1139,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
DivDispatch* writeMSM6295[2]={NULL,NULL};
|
||||
DivDispatch* writeGA20[2]={NULL,NULL};
|
||||
DivDispatch* writeK053260[2]={NULL,NULL};
|
||||
DivDispatch* writeNES[2]={NULL,NULL};
|
||||
|
||||
int writeNESIndex[2]={0,0};
|
||||
|
||||
size_t bankOffsetNESCurrent=0;
|
||||
size_t bankOffsetNES[2]={0,0};
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
willExport[i]=false;
|
||||
|
|
@ -1180,11 +1215,15 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
CHIP_VOL(20,1.7);
|
||||
willExport[i]=true;
|
||||
writeNESSamples=true;
|
||||
writeNES[0]=disCont[i].dispatch;
|
||||
writeNESIndex[0]=i;
|
||||
} else if (!(hasNES&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
CHIP_VOL_SECOND(20,1.7);
|
||||
willExport[i]=true;
|
||||
hasNES|=0x40000000;
|
||||
writeNES[1]=disCont[i].dispatch;
|
||||
writeNESIndex[1]=i;
|
||||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1865,6 +1904,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
for (unsigned int j=0; j<sample->length8; j++) {
|
||||
w->writeC(((unsigned char)sample->data8[j]+0x80)>>1);
|
||||
}
|
||||
bankOffsetNESCurrent+=sample->length8;
|
||||
}
|
||||
|
||||
if (writePCESamples && !directStream) for (int i=0; i<song.sampleLen; i++) {
|
||||
|
|
@ -2008,6 +2048,30 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
w->writeI(0);
|
||||
w->write(writeK053260[i]->getSampleMem(),writeK053260[i]->getSampleMemUsage());
|
||||
}
|
||||
if (writeNES[i]!=NULL && writeNES[i]->getSampleMemUsage()>0) {
|
||||
size_t howMuchWillBeWritten=writeNES[i]->getSampleMemUsage();
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(7);
|
||||
w->writeI(howMuchWillBeWritten);
|
||||
w->write(writeNES[i]->getSampleMem(),howMuchWillBeWritten);
|
||||
bankOffsetNES[i]=bankOffsetNESCurrent;
|
||||
bankOffset[writeNESIndex[i]]=bankOffsetNES[i];
|
||||
bankOffsetNESCurrent+=howMuchWillBeWritten;
|
||||
// force the first bank
|
||||
w->writeC(0x68);
|
||||
w->writeC(0x6c);
|
||||
w->writeC(0x07|(i?0x80:0x00));
|
||||
w->writeC(bankOffsetNES[i]&0xff);
|
||||
w->writeC((bankOffsetNES[i]>>8)&0xff);
|
||||
w->writeC((bankOffsetNES[i]>>16)&0xff);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0xc0);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0x00);
|
||||
w->writeC(0x40);
|
||||
w->writeC(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
|
@ -2217,7 +2281,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
for (int i=0; i<song.systemLen; i++) {
|
||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||
for (DivRegWrite& j: writes) {
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,directStream);
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,bankOffset[i],directStream);
|
||||
writeCount++;
|
||||
}
|
||||
writes.clear();
|
||||
|
|
@ -2257,7 +2321,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
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],pendingFreq,playingSample,directStream);
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,bankOffset[i.first],directStream);
|
||||
// handle global Furnace commands
|
||||
|
||||
writeCount++;
|
||||
}
|
||||
sortedWrites.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue