Merge branch 'master' of https://github.com/tildearrow/furnace into k053260

This commit is contained in:
cam900 2023-07-10 19:56:29 +09:00
commit 7aaa52297e
36 changed files with 783 additions and 141 deletions

View file

@ -288,6 +288,9 @@ struct DivRegWrite {
* - x is the instance ID
* - 0xffffxx04: switch sample bank
* - for use in VGM export
* - 0xffffxx05: set sample position
* - xx is the instance ID
* - data is the sample position
* - 0xffffffff: reset
*/
unsigned int addr;

View file

@ -54,8 +54,10 @@
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
#define DIV_VERSION "0.6pre6"
#define DIV_ENGINE_VERSION 161
#define DIV_UNSTABLE
#define DIV_VERSION "dev163"
#define DIV_ENGINE_VERSION 163
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -489,7 +491,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, size_t bankOffset, 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, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, 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);

View file

@ -63,7 +63,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
for (int i=5; i<7; i++) {
if (chan[i].dacSample!=-1) {
DivSample* s=parent->getSample(chan[i].dacSample);
if (!isMuted[i] && s->samples>0) {
if (!isMuted[i] && s->samples>0 && chan[i].dacPos<s->samples) {
if (parent->song.noOPN2Vol) {
chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
} else {
@ -110,7 +110,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
chan[5].dacPeriod+=chan[5].dacRate;
if (chan[5].dacPeriod>=iRate) {
DivSample* s=parent->getSample(chan[5].dacSample);
if (s->samples>0) {
if (s->samples>0 && chan[5].dacPos<s->samples) {
if (!isMuted[5]) {
if (chan[5].dacReady && writes.size()<16) {
int sample;
@ -122,10 +122,6 @@ void DivPlatformGenesis::processDAC(int iRate) {
urgentWrite(0x2a,(unsigned char)sample+0x80);
chan[5].dacReady=false;
}
} else {
if (chan[5].dacReady && writes.size()<16) {
urgentWrite(0x2a,0x80);
}
}
chan[5].dacPos++;
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {
@ -597,6 +593,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (ch>6) return;
if (ch<6) {
if (ch==5) immWrite(0x2a,0x80);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
@ -704,7 +701,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
addWrite(0xffff0003,chan[c.chan].dacDirection);
}
}
chan[c.chan].dacPos=0;
if (chan[c.chan].setPos) {
chan[c.chan].setPos=false;
} else {
chan[c.chan].dacPos=0;
}
chan[c.chan].dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
@ -927,6 +928,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
if (dumpWrites) addWrite(0xffff0003,chan[c.chan].dacDirection);
break;
}
case DIV_CMD_SAMPLE_POS:
if (c.chan<5) c.chan=5;
chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true;
if (dumpWrites) addWrite(0xffff0005,chan[c.chan].dacPos);
break;
case DIV_CMD_LEGATO: {
if (c.chan==csmChan) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);

View file

@ -57,6 +57,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
int dacDelay;
bool dacReady;
bool dacDirection;
bool setPos;
unsigned char sampleBank;
signed char dacOutput;
Channel():
@ -70,6 +71,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
dacDelay(0),
dacReady(true),
dacDirection(false),
setPos(false),
sampleBank(0),
dacOutput(0) {}
};

View file

@ -42,7 +42,7 @@ void DivPlatformPV1000::acquire(short** buf, size_t len) {
short samp=d65010g031_sound_tick(&d65010g031,1);
buf[0][h]=samp;
for (int i=0; i<3; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=d65010g031.out[i]<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=MAX(d65010g031.out[i]<<2,0);
}
}
}

View file

@ -141,6 +141,7 @@ template<bool IsOpnA>
bool opn_registers_base<IsOpnA>::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask)
{
assert(index < REGISTERS);
if (index >= REGISTERS) return false;
// writes in the 0xa0-af/0x1a0-af region are handled as latched pairs
// borrow unused registers 0xb8-bf/0x1b8-bf as temporary holding locations

View file

@ -236,9 +236,12 @@ void DivPlatformVERA::tick(bool sysTick) {
if (s->samples>0) {
if (s->isLoopable()) {
// Inform the export process of the loop point for this sample
addWrite(67,s->loopStart&0xff);
addWrite(67,(s->loopStart>>8)&0xff);
addWrite(67,(s->loopStart>>16)&0xff);
int tmp_ls=(s->loopStart<<1); // for stereo
if (chan[16].pcm.depth16)
tmp_ls<<=1; // for 16 bit
addWrite(67,tmp_ls&0xff);
addWrite(67,(tmp_ls>>8)&0xff);
addWrite(67,(tmp_ls>>16)&0xff);
}
while (true) {
short tmp_l=0;

View file

@ -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, size_t bankOffset, 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, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream) {
unsigned char baseAddr1=isSecond?0xa0:0x50;
unsigned char baseAddr2=isSecond?0x80:0;
unsigned short baseAddr2S=isSecond?0x8000:0;
@ -620,15 +620,35 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
pendingFreq[streamID]=write.val;
} else {
DivSample* sample=song.sample[write.val];
w->writeC(0x95);
w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
int pos=sampleOff8[write.val&0xff]+setPos[streamID];
int len=(int)sampleLen8[write.val&0xff]-setPos[streamID];
if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8;
loopTimer[streamID]=len;
loopSample[streamID]=write.val;
}
playingSample[streamID]=write.val;
setPos[streamID]=0;
}
}
break;
@ -642,16 +662,36 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
loopFreq[streamID]=realFreq;
if (pendingFreq[streamID]!=-1) {
DivSample* sample=song.sample[pendingFreq[streamID]];
w->writeC(0x95);
w->writeC(streamID);
w->writeS(pendingFreq[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
int pos=sampleOff8[pendingFreq[streamID]&0xff]+setPos[streamID];
int len=(int)sampleLen8[pendingFreq[streamID]&0xff]-setPos[streamID];
if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(pendingFreq[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8;
loopTimer[streamID]=len;
loopSample[streamID]=pendingFreq[streamID];
}
playingSample[streamID]=pendingFreq[streamID];
pendingFreq[streamID]=-1;
setPos[streamID]=0;
}
break;
}
@ -665,6 +705,41 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
case 3: // set sample direction
sampleDir[streamID]=write.val;
break;
case 5: // set sample pos
setPos[streamID]=write.val;
if (playingSample[streamID]!=-1 && pendingFreq[streamID]==-1) {
// play the sample again
DivSample* sample=song.sample[playingSample[streamID]];
int pos=sampleOff8[playingSample[streamID]&0xff]+setPos[streamID];
int len=(int)sampleLen8[playingSample[streamID]&0xff]-setPos[streamID];
if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(playingSample[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=len;
loopSample[streamID]=playingSample[streamID];
}
}
break;
}
}
return;
@ -1082,6 +1157,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
int songTick=0;
unsigned int sampleOff8[256];
unsigned int sampleLen8[256];
unsigned int sampleOffSegaPCM[256];
SafeWriter* w=new SafeWriter;
@ -1102,6 +1178,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
bool sampleDir[DIV_MAX_CHANS];
int pendingFreq[DIV_MAX_CHANS];
int playingSample[DIV_MAX_CHANS];
int setPos[DIV_MAX_CHANS];
std::vector<unsigned int> chipVol;
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
@ -1121,6 +1198,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
loopSample[i]=-1;
pendingFreq[i]=-1;
playingSample[i]=-1;
setPos[i]=0;
sampleDir[i]=false;
}
@ -1379,7 +1457,6 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
willExport[i]=true;
CHIP_VOL(6,1.0);
CHIP_VOL(0x86,1.7);
writeDACSamples=true;
} else if (!(hasOPN&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
@ -1873,6 +1950,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
// initialize sample offsets
memset(sampleOff8,0,256*sizeof(unsigned int));
memset(sampleLen8,0,256*sizeof(unsigned int));
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
// write samples
@ -1881,6 +1959,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
DivSample* sample=song.sample[i];
logI("setting seek to %d",sampleSeek);
sampleOff8[i]=sampleSeek;
sampleLen8[i]=sample->length8;
sampleSeek+=sample->length8;
}
@ -2016,9 +2095,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
w->writeC(0x67);
w->writeC(0x66);
w->writeC(0xc0+i);
w->writeI(writeRF5C68[i]->getSampleMemUsage()+8);
w->writeI(writeRF5C68[i]->getSampleMemCapacity());
w->writeI(0);
w->writeI(writeRF5C68[i]->getSampleMemUsage()+2);
w->writeS(0);
w->write(writeRF5C68[i]->getSampleMem(),writeRF5C68[i]->getSampleMemUsage());
}
if (writeMSM6295[i]!=NULL && writeMSM6295[i]->getSampleMemUsage()>0) {
@ -2281,7 +2359,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,bankOffset[i],directStream);
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i],directStream);
writeCount++;
}
writes.clear();
@ -2321,7 +2399,7 @@ 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,bankOffset[i.first],directStream);
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream);
// handle global Furnace commands
writeCount++;

View file

@ -318,6 +318,7 @@ void DivZSM::flushWrites() {
}
pcmCache.resize(pcmCache.size()>>1);
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
pcmLoopPointCache>>=1; // halve the loop point
}
}
} else { // 8-bit
@ -334,6 +335,7 @@ void DivZSM::flushWrites() {
}
pcmCache.resize(pcmCache.size()>>1);
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
pcmLoopPointCache>>=1; // halve the loop point
}
}
}
@ -365,9 +367,9 @@ void DivZSM::flushWrites() {
inst.loopPoint=pcmLoopPointCache;
inst.isLooped=pcmIsLooped;
pcmInsts.push_back(inst);
pcmIsLooped=false;
pcmLoopPointCache=0;
}
pcmIsLooped=false;
pcmLoopPointCache=0;
}
if (extCmd0Len>63) { // this would be bad, but will almost certainly never happen
logE("ZSM: extCmd 0 exceeded maximum length of 63: %d",extCmd0Len);