Merge branch 'master' of https://github.com/tildearrow/furnace into nmk112
This commit is contained in:
commit
31977ab7c6
111 changed files with 2630 additions and 574 deletions
|
|
@ -20,6 +20,7 @@
|
|||
#include "c64.h"
|
||||
#include "../engine.h"
|
||||
#include "sound/c64_fp/siddefs-fp.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include <math.h>
|
||||
#include "../../ta-log.h"
|
||||
|
||||
|
|
@ -158,21 +159,10 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
|
||||
if (ins->c64.volIsCutoff) {
|
||||
if (ins->c64.filterIsAbs) {
|
||||
filtCut=MIN(2047,chan[i].std.vol.val);
|
||||
} else {
|
||||
filtCut-=((signed char)chan[i].std.vol.val)*7;
|
||||
if (filtCut>2047) filtCut=2047;
|
||||
if (filtCut<0) filtCut=0;
|
||||
}
|
||||
willUpdateFilter=true;
|
||||
} else {
|
||||
vol=MIN(15,chan[i].std.vol.val);
|
||||
willUpdateFilter=true;
|
||||
}
|
||||
vol=MIN(15,chan[i].std.vol.val);
|
||||
willUpdateFilter=true;
|
||||
}
|
||||
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
|
|
@ -186,14 +176,18 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
if (ins->c64.dutyIsAbs) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
} else {
|
||||
chan[i].duty-=((signed char)chan[i].std.duty.val)*4;
|
||||
if (multiplyRel) {
|
||||
chan[i].duty-=((signed char)chan[i].std.duty.val)*4;
|
||||
} else {
|
||||
chan[i].duty-=chan[i].std.duty.val;
|
||||
}
|
||||
}
|
||||
rWrite(i*7+2,chan[i].duty&0xff);
|
||||
rWrite(i*7+3,chan[i].duty>>8);
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].wave=chan[i].std.wave.val;
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active && chan[i].gate));
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
|
|
@ -204,6 +198,21 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.alg.had) { // new cutoff macro
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
|
||||
if (ins->c64.filterIsAbs) {
|
||||
filtCut=MIN(2047,chan[i].std.alg.val);
|
||||
} else {
|
||||
if (multiplyRel) {
|
||||
filtCut+=((signed char)chan[i].std.alg.val)*7;
|
||||
} else {
|
||||
filtCut+=chan[i].std.alg.val;
|
||||
}
|
||||
if (filtCut>2047) filtCut=2047;
|
||||
if (filtCut<0) filtCut=0;
|
||||
}
|
||||
willUpdateFilter=true;
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
filtControl=chan[i].std.ex1.val&15;
|
||||
willUpdateFilter=true;
|
||||
|
|
@ -212,15 +221,33 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
filtRes=chan[i].std.ex2.val&15;
|
||||
willUpdateFilter=true;
|
||||
}
|
||||
if (chan[i].std.ex3.had) {
|
||||
chan[i].sync=chan[i].std.ex3.val&1;
|
||||
chan[i].ring=chan[i].std.ex3.val&2;
|
||||
chan[i].freqChanged=true;
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
||||
}
|
||||
if (chan[i].std.ex4.had) {
|
||||
chan[i].test=chan[i].std.ex4.val&1;
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
||||
chan[i].gate=chan[i].std.ex4.val&1;
|
||||
chan[i].sync=chan[i].std.ex4.val&2;
|
||||
chan[i].ring=chan[i].std.ex4.val&4;
|
||||
chan[i].test=chan[i].std.ex4.val&8;
|
||||
chan[i].freqChanged=true;
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active && chan[i].gate));
|
||||
}
|
||||
|
||||
if (chan[i].std.ex5.had) {
|
||||
chan[i].attack=chan[i].std.ex5.val&15;
|
||||
rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
|
||||
}
|
||||
|
||||
if (chan[i].std.ex6.had) {
|
||||
chan[i].decay=chan[i].std.ex6.val&15;
|
||||
rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
|
||||
}
|
||||
|
||||
if (chan[i].std.ex7.had) {
|
||||
chan[i].sustain=chan[i].std.ex7.val&15;
|
||||
rWrite(i*7+6,(chan[i].sustain<<4)|(chan[i].release));
|
||||
}
|
||||
|
||||
if (chan[i].std.ex8.had) {
|
||||
chan[i].release=chan[i].std.ex8.val&15;
|
||||
rWrite(i*7+6,(chan[i].sustain<<4)|(chan[i].release));
|
||||
}
|
||||
|
||||
if (sysTick) {
|
||||
|
|
@ -243,7 +270,7 @@ void DivPlatformC64::tick(bool sysTick) {
|
|||
if (chan[i].keyOn) {
|
||||
rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
|
||||
rWrite(i*7+6,(chan[i].sustain<<4)|(chan[i].release));
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|1);
|
||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(chan[i].gate?1:0));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
|
||||
|
|
@ -387,7 +414,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_WAVE:
|
||||
chan[c.chan].wave=c.value;
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active && chan[c.chan].gate));
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
|
|
@ -396,7 +423,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) {
|
||||
if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) {
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
|
||||
chan[c.chan].keyOn=true;
|
||||
}
|
||||
|
|
@ -457,23 +484,35 @@ 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;
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active && chan[c.chan].gate));
|
||||
break;
|
||||
case 5:
|
||||
chan[c.chan].sync=c.value;
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active));
|
||||
rWrite(c.chan*7+4,(chan[c.chan].wave<<4)|(chan[c.chan].test<<3)|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active && chan[c.chan].gate));
|
||||
break;
|
||||
case 6:
|
||||
filtControl&=7;
|
||||
|
|
@ -481,6 +520,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;
|
||||
|
|
@ -546,6 +595,24 @@ DivMacroInt* DivPlatformC64::getChanMacroInt(int ch) {
|
|||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformC64::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FA_BELL_SLASH_O;
|
||||
ret.type[0]=0;
|
||||
if (ch==2 && (filtControl&8)) {
|
||||
ret.type[0]=7;
|
||||
} else if (chan[ch].test && !chan[ch].gate) {
|
||||
ret.type[0]=5;
|
||||
} else if (chan[ch].test) {
|
||||
ret.type[0]=6;
|
||||
} else if (!chan[ch].gate) {
|
||||
ret.type[0]=4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformC64::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
@ -594,7 +661,18 @@ void DivPlatformC64::reset() {
|
|||
needInitTables=false;
|
||||
} else if (sidCore==1) {
|
||||
sid_fp->reset();
|
||||
sid_fp->clockSilent(16000);
|
||||
for (int i=0; i<3; i++) {
|
||||
sid_fp->write(i*7+5,testAD);
|
||||
sid_fp->write(i*7+6,testSR);
|
||||
sid_fp->write(i*7+4,8);
|
||||
}
|
||||
sid_fp->clockSilent(30000);
|
||||
for (int i=0; i<3; i++) {
|
||||
sid_fp->write(i*7+5,testAD);
|
||||
sid_fp->write(i*7+6,testSR);
|
||||
sid_fp->write(i*7+4,0);
|
||||
}
|
||||
sid_fp->clockSilent(30000);
|
||||
} else {
|
||||
sid->reset();
|
||||
}
|
||||
|
|
@ -605,7 +683,7 @@ void DivPlatformC64::reset() {
|
|||
filtControl=7;
|
||||
filtRes=0;
|
||||
filtCut=2047;
|
||||
resetTime=1;
|
||||
resetTime=initResetTime;
|
||||
vol=15;
|
||||
|
||||
chanOrder[0]=0;
|
||||
|
|
@ -652,8 +730,12 @@ 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);
|
||||
multiplyRel=flags.getBool("multiplyRel",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);
|
||||
initResetTime=flags.getInt("initResetTime",2);
|
||||
if (initResetTime<0) initResetTime=1;
|
||||
|
||||
// init fake filter table
|
||||
// taken from dSID
|
||||
|
|
|
|||
|
|
@ -26,13 +26,17 @@
|
|||
#include "sound/c64_fp/SID.h"
|
||||
#include "sound/c64_d/dsid.h"
|
||||
|
||||
// TODO:
|
||||
// - ex3 (special) unify with ex4 (gate/test)
|
||||
// - ex4 (test) compatibility
|
||||
|
||||
class DivPlatformC64: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
int prevFreq, testWhen;
|
||||
unsigned char sweep, wave, attack, decay, sustain, release;
|
||||
short duty;
|
||||
bool sweepChanged, filter;
|
||||
bool resetMask, resetFilter, resetDuty, ring, sync, test;
|
||||
bool resetMask, resetFilter, resetDuty, gate, ring, sync, test;
|
||||
Channel():
|
||||
SharedChannel<signed char>(15),
|
||||
prevFreq(65535),
|
||||
|
|
@ -49,6 +53,7 @@ class DivPlatformC64: public DivDispatch {
|
|||
resetMask(false),
|
||||
resetFilter(false),
|
||||
resetDuty(false),
|
||||
gate(true),
|
||||
ring(false),
|
||||
sync(false),
|
||||
test(false) {}
|
||||
|
|
@ -70,9 +75,9 @@ class DivPlatformC64: public DivDispatch {
|
|||
unsigned char filtControl, filtRes, vol;
|
||||
unsigned char writeOscBuf;
|
||||
unsigned char sidCore;
|
||||
int filtCut, resetTime;
|
||||
int filtCut, resetTime, initResetTime;
|
||||
|
||||
bool keyPriority, sidIs6581, needInitTables;
|
||||
bool keyPriority, sidIs6581, needInitTables, no1EUpdate, multiplyRel;
|
||||
unsigned char chanOrder[3];
|
||||
unsigned char testAD, testSR;
|
||||
|
||||
|
|
@ -108,6 +113,7 @@ class DivPlatformC64: public DivDispatch {
|
|||
bool isVolGlobal();
|
||||
float getPostAmp();
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
|||
|
|
@ -191,22 +191,22 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
const int nextVol=VOL_SCALE_LOG((0xfff*chan[i].vol)/0xff,(0xfff*chan[i].std.vol.val)/chan[i].volMacroMax,0xfff);
|
||||
if (chan[i].outVol!=nextVol) {
|
||||
chan[i].outVol=nextVol;
|
||||
chan[i].volChanged.lVol=1;
|
||||
chan[i].volChanged.rVol=1;
|
||||
chan[i].volChangedES.lVol=1;
|
||||
chan[i].volChangedES.rVol=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
const int nextLVol=VOL_SCALE_LOG((0xfff*chan[i].lVol)/0xff,(0xfff*chan[i].std.panL.val)/chan[i].panMacroMax,0xfff);
|
||||
if (chan[i].outLVol!=nextLVol) {
|
||||
chan[i].outLVol=nextLVol;
|
||||
chan[i].volChanged.lVol=1;
|
||||
chan[i].volChangedES.lVol=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
const int nextRVol=VOL_SCALE_LOG((0xfff*chan[i].rVol)/0xff,(0xfff*chan[i].std.panR.val)/chan[i].panMacroMax,0xfff);
|
||||
if (chan[i].outRVol!=nextRVol) {
|
||||
chan[i].outRVol=nextRVol;
|
||||
chan[i].volChanged.rVol=1;
|
||||
chan[i].volChangedES.rVol=1;
|
||||
}
|
||||
}
|
||||
// arpeggio/pitch macros, frequency related
|
||||
|
|
@ -340,7 +340,7 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
if (chan[i].ca!=ca) {
|
||||
chan[i].ca=ca;
|
||||
if (!chan[i].keyOn) {
|
||||
chan[i].volChanged.ca=1;
|
||||
chan[i].volChangedES.ca=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -360,9 +360,9 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
// update registers
|
||||
if (chan[i].volChanged.changed) {
|
||||
if (chan[i].volChangedES.changed) {
|
||||
// calculate volume (16 bit)
|
||||
if (chan[i].volChanged.lVol) {
|
||||
if (chan[i].volChangedES.lVol) {
|
||||
chan[i].resLVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outLVol,0xfff);
|
||||
chan[i].resLVol-=volScale;
|
||||
if (chan[i].resLVol<0) chan[i].resLVol=0;
|
||||
|
|
@ -371,7 +371,7 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
pageWrite(0x00|i,0x02,chan[i].resLVol);
|
||||
}
|
||||
}
|
||||
if (chan[i].volChanged.rVol) {
|
||||
if (chan[i].volChangedES.rVol) {
|
||||
chan[i].resRVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outRVol,0xfff);
|
||||
chan[i].resRVol-=volScale;
|
||||
if (chan[i].resRVol<0) chan[i].resRVol=0;
|
||||
|
|
@ -380,10 +380,10 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
pageWrite(0x00|i,0x04,chan[i].resRVol);
|
||||
}
|
||||
}
|
||||
if (chan[i].volChanged.ca) {
|
||||
if (chan[i].volChangedES.ca) {
|
||||
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].ca<<10),0x1c00);
|
||||
}
|
||||
chan[i].volChanged.changed=0;
|
||||
chan[i].volChangedES.changed=0;
|
||||
}
|
||||
if (chan[i].pcmChanged.changed) {
|
||||
if (chan[i].pcmChanged.index) {
|
||||
|
|
@ -750,7 +750,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].pcmChanged.changed=0xff;
|
||||
chan[c.chan].noteChanged.changed=0xff;
|
||||
chan[c.chan].volChanged.changed=0xff;
|
||||
chan[c.chan].volChangedES.changed=0xff;
|
||||
}
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=(0xfff*chan[c.chan].vol)/0xff;
|
||||
|
|
@ -787,7 +787,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=(0xfff*c.value)/0xff;
|
||||
chan[c.chan].volChanged.changed=0xff;
|
||||
chan[c.chan].volChangedES.changed=0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -797,14 +797,14 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
case DIV_CMD_PANNING: {
|
||||
if (chan[c.chan].ca!=0) {
|
||||
chan[c.chan].ca=0;
|
||||
chan[c.chan].volChanged.ca=1;
|
||||
chan[c.chan].volChangedES.ca=1;
|
||||
}
|
||||
// Left volume
|
||||
if (chan[c.chan].lVol!=c.value) {
|
||||
chan[c.chan].lVol=c.value;
|
||||
if (!chan[c.chan].std.panL.has) {
|
||||
chan[c.chan].outLVol=(0xfff*c.value)/0xff;
|
||||
chan[c.chan].volChanged.lVol=1;
|
||||
chan[c.chan].volChangedES.lVol=1;
|
||||
}
|
||||
}
|
||||
// Right volume
|
||||
|
|
@ -812,7 +812,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].rVol=c.value2;
|
||||
if (!chan[c.chan].std.panR.has) {
|
||||
chan[c.chan].outRVol=(0xfff*c.value2)/0xff;
|
||||
chan[c.chan].volChanged.rVol=1;
|
||||
chan[c.chan].volChangedES.rVol=1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -821,7 +821,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
unsigned char ca=CLAMP(c.value>>1,0,5);
|
||||
if (chan[c.chan].ca!=ca) {
|
||||
chan[c.chan].ca=ca;
|
||||
chan[c.chan].volChanged.ca=1;
|
||||
chan[c.chan].volChangedES.ca=1;
|
||||
}
|
||||
if ((c.value&1)==0) {
|
||||
// Left volume
|
||||
|
|
@ -829,7 +829,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].lVol=c.value2;
|
||||
if (!chan[c.chan].std.panL.has) {
|
||||
chan[c.chan].outLVol=(0xfff*c.value2)/0xff;
|
||||
chan[c.chan].volChanged.lVol=1;
|
||||
chan[c.chan].volChangedES.lVol=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -839,7 +839,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].rVol=c.value2;
|
||||
if (!chan[c.chan].std.panR.has) {
|
||||
chan[c.chan].outRVol=(0xfff*c.value2)/0xff;
|
||||
chan[c.chan].volChanged.rVol=1;
|
||||
chan[c.chan].volChangedES.rVol=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1041,7 +1041,7 @@ void DivPlatformES5506::forceIns() {
|
|||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].noteChanged.changed=0xff;
|
||||
chan[i].volChanged.changed=0xff;
|
||||
chan[i].volChangedES.changed=0xff;
|
||||
chan[i].filterChanged.changed=0xff;
|
||||
chan[i].envChanged.changed=0xff;
|
||||
chan[i].pcmChanged.changed=0xff;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
|
||||
VolChanged() :
|
||||
changed(0) {}
|
||||
} volChanged;
|
||||
} volChangedES;
|
||||
|
||||
struct FilterChanged { // Filter changed flags
|
||||
union { // pack flag bits in single byte
|
||||
|
|
@ -198,7 +198,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
|||
isReverseLoop(false),
|
||||
cr(0),
|
||||
noteChanged(NoteChanged()),
|
||||
volChanged(VolChanged()),
|
||||
volChangedES(VolChanged()),
|
||||
filterChanged(FilterChanged()),
|
||||
envChanged(EnvChanged()),
|
||||
pcmChanged(PCMChanged()),
|
||||
|
|
|
|||
|
|
@ -800,7 +800,7 @@ DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) {
|
|||
}
|
||||
|
||||
unsigned short DivPlatformGenesisExt::getPan(int ch) {
|
||||
if (ch==csmChan) return 0;
|
||||
if (ch==4+csmChan) return 0;
|
||||
if (ch>=4+extChanOffs) return DivPlatformGenesis::getPan(ch-3);
|
||||
if (ch>=extChanOffs) {
|
||||
if (extMode) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "pce.h"
|
||||
#include "../engine.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) pendingWrites[a]=v;
|
||||
|
|
@ -512,6 +513,18 @@ unsigned short DivPlatformPCE::getPan(int ch) {
|
|||
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformPCE::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
if (ch<4) return ret;
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FUR_NOISE;
|
||||
ret.type[0]=0;
|
||||
|
||||
if (chan[ch].noise) ret.type[0]=4;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivSamplePos DivPlatformPCE::getSamplePos(int ch) {
|
||||
if (ch>=6) return DivSamplePos();
|
||||
if (!chan[ch].pcm) return DivSamplePos();
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
DivSamplePos getSamplePos(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "snes.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE 131072
|
||||
|
|
@ -710,6 +711,63 @@ DivChannelPair DivPlatformSNES::getPaired(int ch) {
|
|||
return DivChannelPair();
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformSNES::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
ret.count=1;
|
||||
ret.hint[0]="-";
|
||||
ret.type[0]=0;
|
||||
|
||||
const SPC_DSP::voice_t* v=dsp.get_voice(ch);
|
||||
if (v!=NULL) {
|
||||
if (v->regs[5]&128) {
|
||||
switch (v->env_mode) {
|
||||
case SPC_DSP::env_attack:
|
||||
ret.hint[0]=ICON_FUR_ADSR_A;
|
||||
ret.type[0]=12;
|
||||
break;
|
||||
case SPC_DSP::env_decay:
|
||||
ret.hint[0]=ICON_FUR_ADSR_D;
|
||||
ret.type[0]=13;
|
||||
break;
|
||||
case SPC_DSP::env_sustain:
|
||||
ret.hint[0]=ICON_FUR_ADSR_S;
|
||||
ret.type[0]=14;
|
||||
break;
|
||||
case SPC_DSP::env_release:
|
||||
ret.hint[0]=ICON_FUR_ADSR_R;
|
||||
ret.type[0]=15;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (v->regs[7]&128) {
|
||||
switch (v->regs[7]&0x60) {
|
||||
case 0:
|
||||
ret.hint[0]=ICON_FUR_DEC_LINEAR;
|
||||
ret.type[0]=16;
|
||||
break;
|
||||
case 32:
|
||||
ret.hint[0]=ICON_FUR_DEC_EXP;
|
||||
ret.type[0]=17;
|
||||
break;
|
||||
case 64:
|
||||
ret.hint[0]=ICON_FUR_INC_LINEAR;
|
||||
ret.type[0]=18;
|
||||
break;
|
||||
case 96:
|
||||
ret.hint[0]=ICON_FUR_INC_BENT;
|
||||
ret.type[0]=19;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret.hint[0]=ICON_FUR_VOL_DIRECT;
|
||||
ret.type[0]=20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivSamplePos DivPlatformSNES::getSamplePos(int ch) {
|
||||
if (ch>=8) return DivSamplePos();
|
||||
if (!chan[ch].active) return DivSamplePos();
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class DivPlatformSNES: public DivDispatch {
|
|||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelPair getPaired(int chan);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
DivSamplePos getSamplePos(int ch);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "swan.h"
|
||||
#include "../engine.h"
|
||||
#include "furIcons.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include <math.h>
|
||||
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);}}
|
||||
|
|
@ -480,6 +482,30 @@ unsigned short DivPlatformSwan::getPan(int ch) {
|
|||
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformSwan::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
|
||||
switch (ch) {
|
||||
case 1: // PCM
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FA_VOLUME_UP;
|
||||
ret.type[0]=pcm?4:0;
|
||||
break;
|
||||
case 2: // sweep
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FUR_SAW;
|
||||
ret.type[0]=sweep?2:0;
|
||||
break;
|
||||
case 3: // noise
|
||||
ret.count=1;
|
||||
ret.hint[0]=ICON_FUR_NOISE;
|
||||
ret.type[0]=noise?4:0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ class DivPlatformSwan: public DivDispatch {
|
|||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue