Merge branch 'master' into ZSMv1

This commit is contained in:
ZeroByteOrg 2022-07-11 12:59:59 -05:00
commit 850508e1b8
70 changed files with 342 additions and 65 deletions

View file

@ -45,8 +45,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "0.6pre1"
#define DIV_ENGINE_VERSION 100
#define DIV_VERSION "0.6pre1 (dev101)"
#define DIV_ENGINE_VERSION 101
// for imports
#define DIV_VERSION_MOD 0xff01

View file

@ -172,6 +172,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.volMacroLinger=false;
ds.brokenOutVol=true; // ???
ds.e1e2StopOnSameNote=true;
ds.brokenPortaArp=false;
// 1.1 compat flags
if (ds.version>24) {
@ -1047,6 +1048,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<100) {
ds.e1e2StopOnSameNote=false;
}
if (ds.version<101) {
ds.brokenPortaArp=true;
}
ds.isDMF=false;
reader.readS(); // reserved
@ -1448,7 +1452,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} else {
reader.readC();
}
for (int i=0; i<8; i++) {
if (ds.version>=101) {
ds.brokenPortaArp=reader.readC();
} else {
reader.readC();
}
for (int i=0; i<7; i++) {
reader.readC();
}
}
@ -2922,7 +2931,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeC(song.volMacroLinger);
w->writeC(song.brokenOutVol);
w->writeC(song.e1e2StopOnSameNote);
for (int i=0; i<8; i++) {
w->writeC(song.brokenPortaArp);
for (int i=0; i<7; i++) {
w->writeC(0);
}

View file

@ -355,6 +355,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -827,6 +827,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -471,9 +471,12 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
return 15;
break;
case DIV_CMD_PRE_PORTA:
// TODO: FIX wtr_envelope.dmf
// the brokenPortaArp update broke it
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -506,6 +506,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -250,6 +250,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -369,6 +369,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -406,6 +406,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -393,6 +393,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GB_SWEEP_DIR:

View file

@ -387,6 +387,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -324,6 +324,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -121,6 +121,7 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
chan[c.chan].outVol=chan[c.chan].vol;
}
sample=ins->amiga.getSample(c.value);
samplePos=0;
if (sample>=0 && sample<parent->song.sampleLen) {
//DivSample* s=parent->getSample(chan[c.chan].sample);
if (c.value!=DIV_NOTE_NULL) {
@ -144,8 +145,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
sample=12*sampleBank+c.value%12;
samplePos=0;
msm->ctrl_w(1);
msm->ctrl_w(2);
rWrite(0,1);
rWrite(0,2);
}
break;
}

View file

@ -562,6 +562,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -442,6 +442,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -573,6 +573,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -1434,6 +1434,9 @@ int DivPlatformOPL::dispatch(DivCommand c) {
return 63;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) {
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(chan[c.chan].note)):(NOTE_FREQUENCY(chan[c.chan].note));
}
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:
@ -1539,7 +1542,7 @@ void DivPlatformOPL::reset() {
}
*/
if (downsample) {
const unsigned int downsampledRate=(unsigned int)(49716.0*(double(rate)/chipRateBase));
const unsigned int downsampledRate=(unsigned int)((double)rate*rate/chipRateBase);
OPL3_Reset(&fm,downsampledRate);
} else {
OPL3_Reset(&fm,rate);
@ -1669,7 +1672,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
slots=drums?slotsDrums:slotsNonDrums;
chanMap=drums?chanMapOPL2Drums:chanMapOPL2;
outChanMap=outChanMapOPL2;
chipFreqBase=9440540*0.25;
chipFreqBase=32768*72;
chans=9;
melodicChans=drums?6:9;
totalChans=drums?11:9;
@ -1683,7 +1686,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
slots=drums?slotsDrums:slotsNonDrums;
chanMap=drums?chanMapOPL3Drums:chanMapOPL3;
outChanMap=outChanMapOPL3;
chipFreqBase=9440540;
chipFreqBase=32768*288;
chans=18;
melodicChans=drums?15:18;
totalChans=drums?20:18;
@ -1735,9 +1738,6 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
default:
case 1: case 2: case 8950:
switch (flags&0xff) {
case 0x00:
chipClock=COLOR_NTSC;
break;
case 0x01:
chipClock=COLOR_PAL*4.0/5.0;
break;
@ -1753,15 +1753,15 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
case 0x05:
chipClock=3500000.0;
break;
default:
chipClock=COLOR_NTSC;
break;
}
rate=chipClock/72;
chipRateBase=double(rate);
chipRateBase=rate;
break;
case 3:
switch (flags&0xff) {
case 0x00:
chipClock=COLOR_NTSC*4.0;
break;
case 0x01:
chipClock=COLOR_PAL*16.0/5.0;
break;
@ -1774,28 +1774,31 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
case 0x04:
chipClock=15000000.0;
break;
default:
chipClock=COLOR_NTSC*4.0;
break;
}
rate=chipClock/288;
chipRateBase=double(rate);
chipRateBase=rate;
break;
case 4:
switch (flags&0xff) {
case 0x02:
chipClock=33868800.0;
break;
case 0x00:
chipClock=COLOR_NTSC*8.0;
break;
case 0x01:
chipClock=COLOR_PAL*32.0/5.0;
break;
case 0x02:
chipClock=33868800.0;
break;
default:
chipClock=COLOR_NTSC*8.0;
break;
}
chipRateBase=double(chipClock)/684.0;
rate=chipClock/768;
chipRateBase=chipClock/684;
break;
case 759:
rate=48000;
chipRateBase=double(rate);
chipRateBase=rate;
chipClock=rate*288;
break;
}

View file

@ -95,7 +95,7 @@ class DivPlatformOPL: public DivDispatch {
const unsigned char** slots;
const unsigned short* chanMap;
const unsigned char* outChanMap;
double chipFreqBase, chipRateBase;
int chipFreqBase, chipRateBase;
int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank;
unsigned char lastBusy;
unsigned char drumState;

View file

@ -831,6 +831,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (c.chan>=9 && !properDrums) return 0;
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -445,6 +445,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -471,6 +471,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -239,6 +239,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
if (chan.active && c.value2) {
if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_PET));
}
if (!chan.inPorta && c.value && !parent->song.brokenPortaArp && chan.std.arp.will) chan.baseFreq=NOTE_PERIODIC(chan.note);
chan.inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -496,6 +496,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -265,6 +265,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -335,6 +335,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -267,6 +267,7 @@ int DivPlatformSCC::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -365,6 +365,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<6);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -133,7 +133,7 @@ void DivPlatformSMS::tick(bool sysTick) {
if (i==3) CHIP_DIVIDER=noiseDivider;
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,15);
if (chan[i].outVol<0) chan[i].outVol=0;
// old formula
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
@ -353,9 +353,8 @@ int DivPlatformSMS::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
// TODO: pre porta cancel arp compat flag
//if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
break;
case DIV_CMD_GET_VOLMAX:
return 15;

View file

@ -454,6 +454,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -431,6 +431,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -259,6 +259,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<8);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -933,6 +933,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
return 127;
break;
case DIV_CMD_PRE_PORTA:
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_PRE_NOTE:

View file

@ -361,6 +361,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=calcNoteFreq(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_STD_NOISE_MODE:

View file

@ -243,6 +243,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -399,6 +399,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -732,6 +732,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_FREQ:

View file

@ -293,6 +293,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS:

View file

@ -224,6 +224,7 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:

View file

@ -334,6 +334,11 @@ void DivEngine::processRow(int i, bool afterDelay) {
if (chan[i].lastIns!=pat->data[whatRow][2]) {
chan[i].lastIns=pat->data[whatRow][2];
insChanged=true;
if (song.legacyVolumeSlides && chan[i].volume==chan[i].volMax+1) {
logV("forcing volume");
chan[i].volume=chan[i].volMax;
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
}
}
}
// note

View file

@ -114,6 +114,8 @@ enum DivSystem {
DIV_SYSTEM_YM2612_FRAC,
DIV_SYSTEM_YM2612_FRAC_EXT,
DIV_SYSTEM_RESERVED_8,
DIV_SYSTEM_T6W28,
DIV_SYSTEM_PCM_DAC,
DIV_SYSTEM_DUMMY
};
@ -351,7 +353,7 @@ struct DivSong {
// - 1: stereo
// - YM2203:
// - bit 0-4: clock rate
// - 0: 3.58MHz (MTSC)
// - 0: 3.58MHz (NTSC)
// - 1: 3.55MHz (PAL)
// - 2: 4MHz
// - 3: 3MHz
@ -371,7 +373,7 @@ struct DivSong {
// - 2: FM: clock / 48, SSG: clock / 8
// - YM3526, YM3812, Y8950:
// - bit 0-7: clock rate
// - 0: 3.58MHz (MTSC)
// - 0: 3.58MHz (NTSC)
// - 1: 3.55MHz (PAL)
// - 2: 4MHz
// - 3: 3MHz
@ -379,7 +381,7 @@ struct DivSong {
// - 5: 3.5MHz
// - YMF262:
// - bit 0-7: clock rate
// - 0: 14.32MHz (MTSC)
// - 0: 14.32MHz (NTSC)
// - 1: 14.19MHz (PAL)
// - 2: 14MHz
// - 3: 16MHz
@ -387,7 +389,7 @@ struct DivSong {
// - YMF289B: (TODO)
// - bit 0-7: clock rate
// - 0: 33.8688MHz
// - 1: 28.64MHz (MTSC)
// - 1: 28.64MHz (NTSC)
// - 2: 28.38MHz (PAL)
// - MSM6295:
// - bit 0-6: clock rate
@ -418,7 +420,7 @@ struct DivSong {
// - YMZ280B:
// - bit 0-7: clock rate
// - 0: 16.9344MHz
// - 1: 14.32MHz (MTSC)
// - 1: 14.32MHz (NTSC)
// - 2: 14.19MHz (PAL)
// - 3: 16MHz
// - 4: 16.67MHz
@ -495,6 +497,7 @@ struct DivSong {
bool volMacroLinger;
bool brokenOutVol;
bool e1e2StopOnSameNote;
bool brokenPortaArp;
std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave;
@ -593,7 +596,8 @@ struct DivSong {
newVolumeScaling(true),
volMacroLinger(true),
brokenOutVol(false),
e1e2StopOnSameNote(false) {
e1e2StopOnSameNote(false),
brokenPortaArp(false) {
for (int i=0; i<32; i++) {
system[i]=DIV_SYSTEM_NULL;
systemVol[i]=64;

View file

@ -165,25 +165,25 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) {
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC6) {
return "NES + Konami VRC6";
return "Famicom + Konami VRC6";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) {
return "NES + Konami VRC7";
return "Famicom + Konami VRC7";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_OPLL) {
return "NES + Yamaha OPLL";
return "Family Noraebang";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) {
return "Famicom Disk System";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) {
return "NES + Namco C163";
return "Famicom + Namco C163";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) {
return "NES + MMC5";
return "Famicom + MMC5";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_AY8910) {
return "NES + Sunsoft 5B";
return "Famicom + Sunsoft 5B";
}
if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910) {
@ -2082,6 +2082,35 @@ void DivEngine::registerSystems() {
fmPostEffectHandler
);
sysDefs[DIV_SYSTEM_T6W28]=new DivSysDef(
"T6W28", NULL, 0xbf, 0, 4, false, true, 0, false,
"an SN76489 derivative used in Neo Geo Pocket, has independent stereo volume and noise channel frequency.",
{"Square 1", "Square 2", "Square 3", "Noise"},
{"S1", "S2", "S3", "NO"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE},
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD},
{},
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
switch (effect) {
case 0x20: // SN noise mode
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
break;
default:
return false;
}
return true;
}
);
sysDefs[DIV_SYSTEM_PCM_DAC]=new DivSysDef(
"Generic PCM DAC", NULL, 0xc0, 0, 1, false, true, 0, false,
"as generic sample playback as it gets.",
{"Sample"},
{"PCM"},
{DIV_CH_PCM},
{DIV_INS_AMIGA}
);
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
"this is a system designed for testing purposes.",

View file

@ -207,31 +207,35 @@ void FurnaceGUI::drawCompatFlags() {
}
ImGui::Checkbox("Stop portamento on note off",&e->song.stopPortaOnNoteOff);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("Allow instrument change during slides",&e->song.newInsTriggersInPorta);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("Reset note to base on arpeggio stop",&e->song.arp0Reset);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("ExtCh channel status is shared among operators",&e->song.sharedExtStat);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("New SegaPCM features (macros and better panning)",&e->song.newSegaPCM);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("Old FM octave boundary behavior",&e->song.oldOctaveBoundary);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("No OPN2 DAC volume control",&e->song.noOPN2Vol);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
ImGui::SetTooltip("behavior changed in 0.6pre1");
}
ImGui::Checkbox("Broken initial position of portamento after arpeggio",&e->song.brokenPortaArp);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6pre1.5");
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;

View file

@ -447,7 +447,6 @@ void FurnaceGUI::doReplace() {
}
if (!us.pat.empty()) {
printf("pusher\n");
undoHist.push_back(us);
redoHist.clear();
if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front();
@ -997,16 +996,16 @@ void FurnaceGUI::drawFindReplace() {
ImGui::TableNextColumn();
ImGui::BeginDisabled(!queryReplaceEffectValDo[i]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::Combo("##ERMode",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX);
ImGui::Combo("##ERModeV",&queryReplaceEffectValMode[i],queryReplaceModes,GUI_QUERY_REPLACE_MAX);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_SET) {
if (ImGui::InputScalar("##ERValueH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) {
if (ImGui::InputScalar("##ERValueVH",ImGuiDataType_S32,&queryReplaceEffectVal[i],&_ONE,&_SIXTEEN,"%.2X",ImGuiInputTextFlags_CharsHexadecimal)) {
if (queryReplaceEffectVal[i]<0) queryReplaceEffectVal[i]=0;
if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255;
}
} else if (queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD || queryReplaceEffectValMode[i]==GUI_QUERY_REPLACE_ADD_OVERFLOW) {
if (ImGui::InputInt("##ERValue",&queryReplaceEffectVal[i],1,12)) {
if (ImGui::InputInt("##ERValueV",&queryReplaceEffectVal[i],1,12)) {
if (queryReplaceEffectVal[i]<-255) queryReplaceEffectVal[i]=-255;
if (queryReplaceEffectVal[i]>255) queryReplaceEffectVal[i]=255;
}

View file

@ -589,49 +589,49 @@ void FurnaceGUI::initSystemPresets() {
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Konami VRC6", {
"Famicom with Konami VRC6", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_VRC6, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Konami VRC7", {
"Famicom with Konami VRC7", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_VRC7, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with MMC5", {
"Famicom with MMC5", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_MMC5, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Sunsoft 5B", {
"Famicom with Sunsoft 5B", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 32,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Namco C163", {
"Famicom with Namco C163", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_N163, 64, 0, 112,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Family Noraebang", {
"Comboy with Family Noraebang", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_OPLL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Family Noraebang (drums mode)", {
"Comboy with Family Noraebang (drums mode)", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0,
0
@ -1282,6 +1282,29 @@ void FurnaceGUI::initSystemPresets() {
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega System E", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_SMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega System E (with FM expansion)", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_OPLL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega System E (with FM expansion in drums mode)", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Hang-On", {
DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz
@ -2071,7 +2094,7 @@ void FurnaceGUI::initSystemPresets() {
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Konami VRC7", {
"Famicom with Konami VRC7", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_VRC7, 64, 0, 0,
0

View file

@ -569,7 +569,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
case DIV_SYSTEM_OPL3:
case DIV_SYSTEM_OPL3_DRUMS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==0)) {
if (ImGui::RadioButton("14.32MHz (NTSC)",(flags&255)==0)) {
copyOfFlags=(flags&(~255))|0;
}
if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==1)) {
@ -591,7 +591,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
if (ImGui::RadioButton("16.9344MHz",(flags&255)==0)) {
copyOfFlags=(flags&(~255))|0;
}
if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==1)) {
if (ImGui::RadioButton("14.32MHz (NTSC)",(flags&255)==1)) {
copyOfFlags=(flags&(~255))|1;
}
if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==3)) {
@ -608,12 +608,34 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
}
break;
}
case DIV_SYSTEM_PCM_DAC: {
int sampRate=(flags&65535)+1;
int bitDepth=((flags>>16)&15)+1;
bool stereo=(flags>>20)&1;
ImGui::Text("Output rate:");
if (CWSliderInt("##SampRate",&sampRate,1,65536)) {
if (sampRate<1) sampRate=1;
if (sampRate>65536) sampRate=65536;
copyOfFlags=(flags&(~65535))|(sampRate-1);
} rightClickable
ImGui::Text("Output depth:");
if (CWSliderInt("##BitDepth",&bitDepth,1,16)) {
if (bitDepth<1) bitDepth=1;
if (bitDepth>16) bitDepth=16;
copyOfFlags=(flags&(~(15<<16)))|((bitDepth-1)<<16);
} rightClickable
if (ImGui::Checkbox("Stereo",&stereo)) {
copyOfFlags=(flags&(~(1<<20)))|(stereo<<20);
}
break;
}
case DIV_SYSTEM_GB:
case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_VERA:
case DIV_SYSTEM_BUBSYS_WSG:
case DIV_SYSTEM_YMU759:
case DIV_SYSTEM_PET:
case DIV_SYSTEM_T6W28:
ImGui::Text("nothing to configure");
break;
default: