Merge branch 'master' into feature/esfm
This commit is contained in:
commit
85db9ca16e
17 changed files with 478 additions and 26 deletions
|
|
@ -238,13 +238,16 @@ enum DivDispatchCmds {
|
|||
|
||||
DIV_CMD_EXTERNAL, // (value)
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||
DIV_CMD_C64_AD, // (value)
|
||||
DIV_CMD_C64_SR, // (value)
|
||||
|
||||
DIV_CMD_ESFM_OP_PANNING, // (op, value)
|
||||
DIV_CMD_ESFM_OUTLVL, // (op, value)
|
||||
DIV_CMD_ESFM_MODIN, // (op, value)
|
||||
DIV_CMD_ESFM_ENV_DELAY, // (op, value)
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||
|
||||
DIV_CMD_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivWorkPool;
|
|||
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "dev184"
|
||||
#define DIV_ENGINE_VERSION 184
|
||||
#define DIV_VERSION "dev186"
|
||||
#define DIV_ENGINE_VERSION 186
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
|
|||
|
|
@ -3008,6 +3008,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// C64 1Exy compat
|
||||
if (ds.version<186) {
|
||||
for (int i=0; i<ds.systemLen; i++) {
|
||||
if (ds.system[i]==DIV_SYSTEM_C64_8580 || ds.system[i]==DIV_SYSTEM_C64_6581) {
|
||||
ds.systemFlags[i].set("no1EUpdate",true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
@ -3149,8 +3158,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
ds.sampleLen=ds.sample.size();
|
||||
|
||||
// orders
|
||||
ds.subsong[0]->ordersLen=ordCount=reader.readC();
|
||||
if (ds.subsong[0]->ordersLen<1 || ds.subsong[0]->ordersLen>127) {
|
||||
ds.subsong[0]->ordersLen=ordCount=(unsigned char)reader.readC();
|
||||
if (ds.subsong[0]->ordersLen<1 || ds.subsong[0]->ordersLen>128) {
|
||||
logD("invalid order count!");
|
||||
throw EndOfFileException(&reader,reader.tell());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,10 @@ bool DivInstrumentWaveSynth::operator==(const DivInstrumentWaveSynth& other) {
|
|||
}
|
||||
|
||||
bool DivInstrumentSoundUnit::operator==(const DivInstrumentSoundUnit& other) {
|
||||
return _C(switchRoles);
|
||||
return (
|
||||
_C(switchRoles) &&
|
||||
_C(hwSeqLen)
|
||||
);
|
||||
}
|
||||
|
||||
bool DivInstrumentES5506::operator==(const DivInstrumentES5506& other) {
|
||||
|
|
@ -714,6 +717,14 @@ void DivInstrument::writeFeatureSU(SafeWriter* w) {
|
|||
|
||||
w->writeC(su.switchRoles);
|
||||
|
||||
w->writeC(su.hwSeqLen);
|
||||
for (int i=0; i<su.hwSeqLen; i++) {
|
||||
w->writeC(su.hwSeq[i].cmd);
|
||||
w->writeC(su.hwSeq[i].bound);
|
||||
w->writeC(su.hwSeq[i].val);
|
||||
w->writeS(su.hwSeq[i].speed);
|
||||
}
|
||||
|
||||
FEATURE_END;
|
||||
}
|
||||
|
||||
|
|
@ -2585,6 +2596,16 @@ void DivInstrument::readFeatureSU(SafeReader& reader, short version) {
|
|||
|
||||
su.switchRoles=reader.readC();
|
||||
|
||||
if (version>=185) {
|
||||
su.hwSeqLen=reader.readC();
|
||||
for (int i=0; i<su.hwSeqLen; i++) {
|
||||
su.hwSeq[i].cmd=reader.readC();
|
||||
su.hwSeq[i].bound=reader.readC();
|
||||
su.hwSeq[i].val=reader.readC();
|
||||
su.hwSeq[i].speed=reader.readS();
|
||||
}
|
||||
}
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ struct DivInstrumentGB {
|
|||
|
||||
DIV_GB_HWCMD_MAX
|
||||
};
|
||||
struct HWSeqCommand {
|
||||
struct HWSeqCommandGB {
|
||||
unsigned char cmd;
|
||||
unsigned short data;
|
||||
} hwSeq[256];
|
||||
|
|
@ -406,7 +406,7 @@ struct DivInstrumentGB {
|
|||
hwSeqLen(0),
|
||||
softEnv(false),
|
||||
alwaysInit(false) {
|
||||
memset(hwSeq,0,256*sizeof(int));
|
||||
memset(hwSeq,0,256*sizeof(HWSeqCommandGB));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -666,6 +666,25 @@ struct DivInstrumentWaveSynth {
|
|||
|
||||
struct DivInstrumentSoundUnit {
|
||||
bool switchRoles;
|
||||
unsigned char hwSeqLen;
|
||||
enum HWSeqCommands: unsigned char {
|
||||
DIV_SU_HWCMD_VOL=0,
|
||||
DIV_SU_HWCMD_PITCH,
|
||||
DIV_SU_HWCMD_CUT,
|
||||
DIV_SU_HWCMD_WAIT,
|
||||
DIV_SU_HWCMD_WAIT_REL,
|
||||
DIV_SU_HWCMD_LOOP,
|
||||
DIV_SU_HWCMD_LOOP_REL,
|
||||
|
||||
DIV_SU_HWCMD_MAX
|
||||
};
|
||||
struct HWSeqCommandSU {
|
||||
unsigned char cmd;
|
||||
unsigned char bound;
|
||||
unsigned char val;
|
||||
unsigned short speed;
|
||||
unsigned short padding;
|
||||
} hwSeq[256];
|
||||
|
||||
bool operator==(const DivInstrumentSoundUnit& other);
|
||||
bool operator!=(const DivInstrumentSoundUnit& other) {
|
||||
|
|
@ -673,7 +692,10 @@ struct DivInstrumentSoundUnit {
|
|||
}
|
||||
|
||||
DivInstrumentSoundUnit():
|
||||
switchRoles(false) {}
|
||||
switchRoles(false),
|
||||
hwSeqLen(0) {
|
||||
memset(hwSeq,0,256*sizeof(HWSeqCommandSU));
|
||||
}
|
||||
};
|
||||
|
||||
struct DivInstrumentES5506 {
|
||||
|
|
|
|||
|
|
@ -457,15 +457,27 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
switch (c.value>>4) {
|
||||
case 0:
|
||||
chan[c.chan].attack=c.value&15;
|
||||
if (!no1EUpdate) {
|
||||
rWrite(c.chan*7+5,(chan[c.chan].attack<<4)|(chan[c.chan].decay));
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
chan[c.chan].decay=c.value&15;
|
||||
if (!no1EUpdate) {
|
||||
rWrite(c.chan*7+5,(chan[c.chan].attack<<4)|(chan[c.chan].decay));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
chan[c.chan].sustain=c.value&15;
|
||||
if (!no1EUpdate) {
|
||||
rWrite(c.chan*7+6,(chan[c.chan].sustain<<4)|(chan[c.chan].release));
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
chan[c.chan].release=c.value&15;
|
||||
if (!no1EUpdate) {
|
||||
rWrite(c.chan*7+6,(chan[c.chan].sustain<<4)|(chan[c.chan].release));
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
chan[c.chan].ring=c.value;
|
||||
|
|
@ -481,6 +493,16 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_C64_AD:
|
||||
chan[c.chan].attack=c.value>>4;
|
||||
chan[c.chan].decay=c.value&15;
|
||||
rWrite(c.chan*7+5,(chan[c.chan].attack<<4)|(chan[c.chan].decay));
|
||||
break;
|
||||
case DIV_CMD_C64_SR:
|
||||
chan[c.chan].sustain=c.value>>4;
|
||||
chan[c.chan].release=c.value&15;
|
||||
rWrite(c.chan*7+6,(chan[c.chan].sustain<<4)|(chan[c.chan].release));
|
||||
break;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
break;
|
||||
|
|
@ -652,6 +674,7 @@ void DivPlatformC64::setFlags(const DivConfig& flags) {
|
|||
if (sidCore==1) sid_fp->setSamplingParameters(chipClock,reSIDfp::DECIMATE,rate,0);
|
||||
}
|
||||
keyPriority=flags.getBool("keyPriority",true);
|
||||
no1EUpdate=flags.getBool("no1EUpdate",false);
|
||||
testAD=((flags.getInt("testAttack",0)&15)<<4)|(flags.getInt("testDecay",0)&15);
|
||||
testSR=((flags.getInt("testSustain",0)&15)<<4)|(flags.getInt("testRelease",0)&15);
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class DivPlatformC64: public DivDispatch {
|
|||
unsigned char sidCore;
|
||||
int filtCut, resetTime;
|
||||
|
||||
bool keyPriority, sidIs6581, needInitTables;
|
||||
bool keyPriority, sidIs6581, needInitTables, no1EUpdate;
|
||||
unsigned char chanOrder[3];
|
||||
unsigned char testAD, testSR;
|
||||
|
||||
|
|
|
|||
|
|
@ -134,6 +134,79 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
}
|
||||
writeControlUpper(i);
|
||||
}
|
||||
|
||||
// run hardware sequence
|
||||
if (chan[i].active) {
|
||||
if (--chan[i].hwSeqDelay<=0) {
|
||||
chan[i].hwSeqDelay=0;
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
int hwSeqCount=0;
|
||||
while (chan[i].hwSeqPos<ins->su.hwSeqLen && hwSeqCount<8) {
|
||||
bool leave=false;
|
||||
unsigned char bound=ins->su.hwSeq[chan[i].hwSeqPos].bound;
|
||||
unsigned char val=ins->su.hwSeq[chan[i].hwSeqPos].val;
|
||||
unsigned short speed=ins->su.hwSeq[chan[i].hwSeqPos].speed;
|
||||
switch (ins->su.hwSeq[chan[i].hwSeqPos].cmd) {
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_VOL:
|
||||
chan[i].volSweepP=speed;
|
||||
chan[i].volSweepV=val;
|
||||
chan[i].volSweepB=bound;
|
||||
chan[i].volSweep=(val>0);
|
||||
chWrite(i,0x14,chan[i].volSweepP&0xff);
|
||||
chWrite(i,0x15,chan[i].volSweepP>>8);
|
||||
chWrite(i,0x16,chan[i].volSweepV);
|
||||
chWrite(i,0x17,chan[i].volSweepB);
|
||||
writeControlUpper(i);
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_PITCH:
|
||||
chan[i].freqSweepP=speed;
|
||||
chan[i].freqSweepV=val;
|
||||
chan[i].freqSweepB=bound;
|
||||
chan[i].freqSweep=(val>0);
|
||||
chWrite(i,0x10,chan[i].freqSweepP&0xff);
|
||||
chWrite(i,0x11,chan[i].freqSweepP>>8);
|
||||
chWrite(i,0x12,chan[i].freqSweepV);
|
||||
chWrite(i,0x13,chan[i].freqSweepB);
|
||||
writeControlUpper(i);
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_CUT:
|
||||
chan[i].cutSweepP=speed;
|
||||
chan[i].cutSweepV=val;
|
||||
chan[i].cutSweepB=bound;
|
||||
chan[i].cutSweep=(val>0);
|
||||
chWrite(i,0x18,chan[i].cutSweepP&0xff);
|
||||
chWrite(i,0x19,chan[i].cutSweepP>>8);
|
||||
chWrite(i,0x1a,chan[i].cutSweepV);
|
||||
chWrite(i,0x1b,chan[i].cutSweepB);
|
||||
writeControlUpper(i);
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_WAIT:
|
||||
chan[i].hwSeqDelay=(val+1)*parent->tickMult;
|
||||
leave=true;
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_WAIT_REL:
|
||||
if (!chan[i].released) {
|
||||
chan[i].hwSeqPos--;
|
||||
leave=true;
|
||||
}
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_LOOP:
|
||||
chan[i].hwSeqPos=val-1;
|
||||
break;
|
||||
case DivInstrumentSoundUnit::DIV_SU_HWCMD_LOOP_REL:
|
||||
if (!chan[i].released) {
|
||||
chan[i].hwSeqPos=val-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
chan[i].hwSeqPos++;
|
||||
if (leave) break;
|
||||
hwSeqCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,chan[i].switchRoles,2,chan[i].pitch2,chipClock,chan[i].switchRoles?CHIP_DIVIDER:CHIP_FREQBASE);
|
||||
|
|
@ -160,8 +233,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].pcm) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||
int sNum=ins->amiga.getSample(chan[i].note);
|
||||
int sNum=chan[i].sample;
|
||||
DivSample* sample=parent->getSample(sNum);
|
||||
if (sample!=NULL && sNum>=0 && sNum<parent->song.sampleLen) {
|
||||
unsigned int sampleEnd=sampleOffSU[sNum]+(sample->getLoopEndPosition());
|
||||
|
|
@ -220,6 +292,9 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].released=false;
|
||||
chan[c.chan].hwSeqPos=0;
|
||||
chan[c.chan].hwSeqDelay=0;
|
||||
chWrite(c.chan,0x02,chan[c.chan].vol);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
|
|
@ -231,11 +306,14 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].hwSeqPos=0;
|
||||
chan[c.chan].hwSeqDelay=0;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
chan[c.chan].released=true;
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
signed char pan;
|
||||
unsigned char duty;
|
||||
bool noise, pcm, phaseReset, filterPhaseReset, switchRoles;
|
||||
bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep;
|
||||
bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep, released;
|
||||
unsigned short freqSweepP, volSweepP, cutSweepP;
|
||||
unsigned char freqSweepB, volSweepB, cutSweepB;
|
||||
unsigned char freqSweepV, volSweepV, cutSweepV;
|
||||
unsigned short syncTimer;
|
||||
signed short wave;
|
||||
unsigned short hwSeqPos;
|
||||
short hwSeqDelay;
|
||||
Channel():
|
||||
SharedChannel<signed char>(127),
|
||||
cutoff(16383),
|
||||
|
|
@ -56,6 +58,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
freqSweep(false),
|
||||
volSweep(false),
|
||||
cutSweep(false),
|
||||
released(false),
|
||||
freqSweepP(0),
|
||||
volSweepP(0),
|
||||
cutSweepP(0),
|
||||
|
|
@ -66,7 +69,9 @@ class DivPlatformSoundUnit: public DivDispatch {
|
|||
volSweepV(0),
|
||||
cutSweepV(0),
|
||||
syncTimer(0),
|
||||
wave(0) {}
|
||||
wave(0),
|
||||
hwSeqPos(0),
|
||||
hwSeqDelay(0) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
|
|
|
|||
|
|
@ -239,12 +239,16 @@ const char* cmdName[]={
|
|||
|
||||
"EXTERNAL",
|
||||
|
||||
"C64_AD",
|
||||
"C64_SR",
|
||||
|
||||
"ESFM_OP_PANNING",
|
||||
"ESFM_OUTLVL",
|
||||
"ESFM_MODIN",
|
||||
"ESFM_ENV_DELAY",
|
||||
|
||||
"ALWAYS_SET_VOLUME",
|
||||
|
||||
"DIV_CMD_ESFM_OP_PANNING",
|
||||
"DIV_CMD_ESFM_OUTLVL",
|
||||
"DIV_CMD_ESFM_MODIN",
|
||||
"DIV_CMD_ESFM_ENV_DELAY"
|
||||
};
|
||||
|
||||
static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!");
|
||||
|
|
|
|||
|
|
@ -606,6 +606,8 @@ void DivEngine::registerSystems() {
|
|||
{0x1b, {DIV_CMD_C64_FILTER_RESET, "1Bxy: Reset cutoff (x: on new note; y: now)"}},
|
||||
{0x1c, {DIV_CMD_C64_DUTY_RESET, "1Cxy: Reset pulse width (x: on new note; y: now)"}},
|
||||
{0x1e, {DIV_CMD_C64_EXTENDED, "1Exy: Change additional parameters"}},
|
||||
{0x20, {DIV_CMD_C64_AD, "20xy: Set attack/decay (x: attack; y: decay)"}},
|
||||
{0x21, {DIV_CMD_C64_SR, "21xy: Set sustain/release (x: sustain; y: release)"}},
|
||||
};
|
||||
const EffectHandler c64FineDutyHandler(DIV_CMD_C64_FINE_DUTY, "3xxx: Set pulse width (0 to FFF)", effectValLong<12>);
|
||||
const EffectHandler c64FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to 7FF)", effectValLong<11>);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue