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

* 'master' of https://github.com/tildearrow/furnace: (77 commits)
  GUI: use pattern font for input latch
  GUI: partially implement note input latch UI
  GUI: transpose value does not transpose effect ID
  GUI: prepare for note input latch UI
  GUI: min ins selector width fix
  GUI: separate operation masks
  GUI: add missing FDS preset
  GUI: prepare for separate operation mask
  GUI: "none" instrument should not remove inscolumn
  GUI: fix ins 0 being inserted on blank song
  GUI: add a "none" option to instrument list
  update to-do list
  GUI: add "absorb" instrument input mode
  use good default instrument when adding ins
  better default instrument for OPL/OPLL
  GUI: fix selection being visible in dummy row area
  Further fix looped sample preview
  GUI: fix about screen in power saving mode
  VRC6: saw volume 63
  GUI: add an effect list window
  ...

# Conflicts:
#	src/engine/platform/amiga.cpp
#	src/engine/vgmOps.cpp
#	src/gui/dataList.cpp
#	src/gui/guiConst.cpp
#	src/gui/insEdit.cpp
#	src/gui/sampleEdit.cpp
This commit is contained in:
cam900 2022-04-26 12:04:23 +09:00
commit 49a41ff862
116 changed files with 2535 additions and 993 deletions

View file

@ -22,7 +22,7 @@
void DivDispatch::acquire(short* bufL, short* bufR, size_t start, size_t len) {
}
void DivDispatch::tick() {
void DivDispatch::tick(bool sysTick) {
}
void* DivDispatch::getChanState(int chan) {

View file

@ -108,7 +108,9 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
} else {
DivSample* s=parent->getSample(chan[i].sample);
if (s->samples>0) {
writeAudDat(s->data8[chan[i].audPos++]);
if (chan[i].audPos<s->samples) {
writeAudDat(s->data8[chan[i].audPos++]);
}
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].audPos>=s->loopEnd) || (chan[i].audPos>=s->samples) || (chan[i].audPos>=131071)) {
if (s->isLoopable()) {
chan[i].audPos=s->loopStart;
@ -155,7 +157,7 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
}
}
void DivPlatformAmiga::tick() {
void DivPlatformAmiga::tick(bool sysTick) {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -204,7 +206,7 @@ void DivPlatformAmiga::tick() {
}
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins);
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
if (chan[i].freq>4095) chan[i].freq=4095;
if (chan[i].freq<0) chan[i].freq=0;
@ -222,7 +224,7 @@ void DivPlatformAmiga::tick() {
int DivPlatformAmiga::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
double off=1.0;
if (ins->amiga.useWave) {
chan[c.chan].useWave=true;
@ -312,7 +314,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
break;
case DIV_CMD_NOTE_PORTA: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
chan[c.chan].sample=ins->amiga.initSample;
double off=1.0;
if (!chan[c.chan].useWave && chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
@ -362,7 +364,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -88,7 +88,7 @@ class DivPlatformAmiga: public DivDispatch {
void* getChanState(int chan);
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -219,7 +219,7 @@ inline int hScale(int note) {
return ((note/12)<<4)+(noteMap[note%12]);
}
void DivPlatformArcade::tick() {
void DivPlatformArcade::tick(bool sysTick) {
for (int i=0; i<8; i++) {
chan[i].std.next();
@ -264,6 +264,20 @@ void DivPlatformArcade::tick() {
rWrite(0x1b,chan[i].std.wave.val&3);
}
if (chan[i].std.panL.had) {
chan[i].chVolL=(chan[i].std.panL.val&2)>>1;
chan[i].chVolR=chan[i].std.panL.val&1;
if (isMuted[i]) {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} else {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7));
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -432,7 +446,7 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) {
int DivPlatformArcade::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;

View file

@ -107,7 +107,7 @@ class DivPlatformArcade: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsChange(int ins);
void setFlags(unsigned int flags);

View file

@ -172,7 +172,7 @@ void DivPlatformAY8910::updateOutSel(bool immediate) {
}
}
void DivPlatformAY8910::tick() {
void DivPlatformAY8910::tick(bool sysTick) {
// PSG
for (int i=0; i<3; i++) {
chan[i].std.next();
@ -215,6 +215,9 @@ void DivPlatformAY8910::tick() {
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
oldWrites[0x08+i]=-1;
@ -291,7 +294,7 @@ void DivPlatformAY8910::tick() {
int DivPlatformAY8910::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
@ -454,7 +457,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -90,7 +90,7 @@ class DivPlatformAY8910: public DivDispatch {
void flushWrites();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
bool isStereo();

View file

@ -187,7 +187,7 @@ const unsigned char regMode[3]={
0x0d, 0x14, 0x15
};
void DivPlatformAY8930::tick() {
void DivPlatformAY8930::tick(bool sysTick) {
// PSG
for (int i=0; i<3; i++) {
chan[i].std.next();
@ -226,6 +226,9 @@ void DivPlatformAY8930::tick() {
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
oldWrites[0x08+i]=-1;
@ -315,7 +318,7 @@ void DivPlatformAY8930::tick() {
int DivPlatformAY8930::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
@ -479,7 +482,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -78,7 +78,7 @@ class DivPlatformAY8930: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
bool isStereo();

View file

@ -81,7 +81,7 @@ void DivPlatformBubSysWSG::updateWave(int ch) {
}
}
void DivPlatformBubSysWSG::tick() {
void DivPlatformBubSysWSG::tick(bool sysTick) {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -110,13 +110,16 @@ void DivPlatformBubSysWSG::tick() {
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].active) {
if (chan[i].ws.tick()) {
updateWave(i);
}
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins);
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC);
chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>4095) chan[i].freq=4095;
@ -139,7 +142,7 @@ void DivPlatformBubSysWSG::tick() {
int DivPlatformBubSysWSG::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SCC);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
@ -225,7 +228,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -67,7 +67,7 @@ class DivPlatformBubSysWSG: public DivDispatch {
int getRegisterPoolDepth();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -122,11 +122,11 @@ void DivPlatformC64::updateFilter() {
rWrite(0x18,(filtControl<<4)|vol);
}
void DivPlatformC64::tick() {
void DivPlatformC64::tick(bool sysTick) {
for (int i=0; i<3; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
DivInstrument* ins=parent->getIns(chan[i].ins);
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);
@ -157,7 +157,7 @@ void DivPlatformC64::tick() {
}
}
if (chan[i].std.duty.had) {
DivInstrument* ins=parent->getIns(chan[i].ins);
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64);
if (ins->c64.dutyIsAbs) {
chan[i].duty=chan[i].std.duty.val;
} else {
@ -166,12 +166,14 @@ void DivPlatformC64::tick() {
rWrite(i*7+2,chan[i].duty&0xff);
rWrite(i*7+3,chan[i].duty>>8);
}
if (chan[i].testWhen>0) {
if (--chan[i].testWhen<1) {
if (!chan[i].resetMask) {
rWrite(i*7+5,0);
rWrite(i*7+6,0);
rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1));
if (sysTick) {
if (chan[i].testWhen>0) {
if (--chan[i].testWhen<1) {
if (!chan[i].resetMask && !chan[i].inPorta) {
rWrite(i*7+5,0);
rWrite(i*7+6,0);
rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1));
}
}
}
}
@ -179,6 +181,9 @@ void DivPlatformC64::tick() {
chan[i].wave=chan[i].std.wave.val;
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.ex1.had) {
filtControl=chan[i].std.ex1.val&15;
updateFilter();
@ -218,7 +223,7 @@ void DivPlatformC64::tick() {
int DivPlatformC64::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].freqChanged=true;
@ -339,8 +344,8 @@ 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].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) {
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
chan[c.chan].keyOn=true;
}
}
@ -378,7 +383,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case DIV_CMD_C64_FILTER_RESET:
if (c.value&15) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
if (ins->c64.initFilter) {
filtCut=ins->c64.cut;
updateFilter();
@ -388,7 +393,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
break;
case DIV_CMD_C64_DUTY_RESET:
if (c.value&15) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64);
chan[c.chan].duty=ins->c64.duty;
rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
rWrite(c.chan*7+3,chan[c.chan].duty>>8);

View file

@ -83,7 +83,7 @@ class DivPlatformC64: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
void notifyInsChange(int ins);

View file

@ -38,10 +38,12 @@ void DivPlatformDummy::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
}
void DivPlatformDummy::tick() {
void DivPlatformDummy::tick(bool sysTick) {
for (unsigned char i=0; i<chans; i++) {
chan[i].amp-=3;
if (chan[i].amp<16) chan[i].amp=16;
if (sysTick) {
chan[i].amp-=3;
if (chan[i].amp<16) chan[i].amp=16;
}
if (chan[i].freqChanged) {
chan[i].freqChanged=false;
@ -115,4 +117,4 @@ void DivPlatformDummy::quit() {
}
DivPlatformDummy::~DivPlatformDummy() {
}
}

View file

@ -41,7 +41,7 @@ class DivPlatformDummy: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
void reset();
void tick();
void tick(bool sysTick=true);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
~DivPlatformDummy();

View file

@ -23,7 +23,7 @@
#include <math.h>
#include <map>
#define CHIP_FREQBASE (16*2048)
#define CHIP_FREQBASE (16*2048*(chanMax+1))
#define NOTE_ES5506(c,note) (chan[c].pcm.freqOffs*NOTE_FREQUENCY(note))
#define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }}
@ -106,14 +106,40 @@ const char** DivPlatformES5506::getRegisterSheet() {
const char* DivPlatformES5506::getEffectName(unsigned char effect) {
switch (effect) {
case 0x10:
return "10xx: Set echo feedback level (00 to FF)";
return "10xx: Change waveform";
break;
case 0x11:
return "11xx: Set channel echo level (00 to FF)";
return "11xx: Set filter mode (00 to 03)";
break;
case 0x20:
return "20xx: Set envelope count (000 to 0FF)";
break;
case 0x21:
return "21xx: Set envelope count (100 to 1FF)";
break;
case 0x22:
return "22xx: Set envelope left volume ramp (signed)";
break;
case 0x23:
return "23xx: Set envelope right volume ramp (signed)";
break;
case 0x24:
return "24xx: Set envelope k1 ramp (signed)";
break;
case 0x25:
return "25xx: Set envelope k1 ramp (signed, slower)";
break;
case 0x26:
return "26xx: Set envelope k2 ramp (signed)";
break;
case 0x27:
return "27xx: Set envelope k2 ramp (signed, slower)";
break;
default:
if ((effect & 0xf0) == 0x30) {
return "3xxx: Set echo delay buffer length (000 to AA5)";
if ((effect&0xf0)==0x30) {
return "3xxx: Set filter K1";
} else if ((effect&0xf0)==0x40) {
return "4xxx: Set filter K2";
}
}
return NULL;
@ -190,9 +216,9 @@ void DivPlatformES5506::e(bool state)
irqTrigger=false;
if ((irqv&0x80)==0) {
unsigned char ch=irqv&0x1f;
if (chan[ch].isReversed) { // Reversed loop
pageWriteMask(0x00|ch,0x5f,0x00,0x48,0x78);
chan[ch].isReversed=false;
if (chan[ch].isReverseLoop) { // Reversed loop
pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0040:0x0000)|0x08,0x78);
chan[ch].isReverseLoop=false;
}
}
}
@ -204,7 +230,7 @@ void DivPlatformES5506::irqb(bool state) {
irqTrigger=true;
}
void DivPlatformES5506::tick() {
void DivPlatformES5506::tick(bool sysTick) {
for (int i=0; i<=chanMax; i++) {
chan[i].std.next();
DivInstrument* ins=parent->getIns(chan[i].ins);
@ -252,6 +278,104 @@ void DivPlatformES5506::tick() {
chan[i].keyOn=true;
}
}
// filter macros
if (chan[i].std.duty.had) {
if (chan[i].filter.mode!=DivInstrumentES5506::Filter::FilterMode(chan[i].std.duty.val&3)) {
chan[i].filter.mode=DivInstrumentES5506::Filter::FilterMode(chan[i].std.duty.val&3);
chan[i].filterChanged.mode=1;
}
}
if (chan[i].std.ex1.had) {
switch (chan[i].std.ex1.mode) {
case 0: // relative
if (chan[i].k1Offs!=chan[i].std.ex1.val) {
chan[i].k1Offs=chan[i].std.ex1.val;
chan[i].filterChanged.k1=1;
}
case 1: // absolute
if (chan[i].filter.k1!=(chan[i].std.ex1.val&0xffff)) {
chan[i].filter.k1=chan[i].std.ex1.val&0xffff;
chan[i].filterChanged.k1=1;
}
break;
case 2: { // delta
signed int next_k1=MAX(0,MIN(65535,chan[i].filter.k1+chan[i].std.ex1.val));
if (chan[i].filter.k1!=next_k1) {
chan[i].filter.k1=next_k1;
chan[i].filterChanged.k1=1;
}
break;
}
default:
break;
}
}
if (chan[i].std.ex2.had) {
switch (chan[i].std.ex2.mode) {
case 0: // relative
if (chan[i].k2Offs!=chan[i].std.ex1.val) {
chan[i].k2Offs=chan[i].std.ex1.val;
chan[i].filterChanged.k2=1;
}
case 1: // absolute
if (chan[i].filter.k2!=(chan[i].std.ex2.val&0xffff)) {
chan[i].filter.k2=chan[i].std.ex2.val&0xffff;
chan[i].filterChanged.k2=1;
}
break;
case 2: { // delta
signed int next_k2=MAX(0,MIN(65535,chan[i].filter.k2+chan[i].std.ex2.val));
if (chan[i].filter.k2!=next_k2) {
chan[i].filter.k2=next_k2;
chan[i].filterChanged.k2=1;
}
break;
}
default:
break;
}
}
// envelope macros
if (chan[i].std.ex3.had) {
if (chan[i].envelope.ecount!=(chan[i].std.ex3.val&0x1ff)) {
chan[i].envelope.ecount=chan[i].std.ex3.val&0x1ff;
chan[i].envChanged.ecount=1;
}
}
if (chan[i].std.ex4.had) {
if (chan[i].envelope.lVRamp!=chan[i].std.ex4.val) {
chan[i].envelope.lVRamp=chan[i].std.ex4.val;
chan[i].envChanged.lVRamp=1;
}
}
if (chan[i].std.ex5.had) {
if (chan[i].envelope.rVRamp!=chan[i].std.ex5.val) {
chan[i].envelope.rVRamp=chan[i].std.ex5.val;
chan[i].envChanged.rVRamp=1;
}
}
if (chan[i].std.ex6.had) {
if (chan[i].envelope.k1Ramp!=chan[i].std.ex6.val) {
chan[i].envelope.k1Ramp=chan[i].std.ex6.val;
chan[i].envChanged.k1Ramp=1;
}
}
if (chan[i].std.ex7.had) {
if (chan[i].envelope.k2Ramp!=chan[i].std.ex7.val) {
chan[i].envelope.k2Ramp=chan[i].std.ex7.val;
chan[i].envChanged.k2Ramp=1;
}
}
if (chan[i].std.ex8.had) {
if (chan[i].envelope.k1Slow!=(chan[i].std.ex8.val&1)) {
chan[i].envelope.k1Slow=chan[i].std.ex8.val&1;
chan[i].envChanged.k1Ramp=1;
}
if (chan[i].envelope.k2Slow!=(chan[i].std.ex8.val&2)) {
chan[i].envelope.k2Slow=chan[i].std.ex8.val&2;
chan[i].envChanged.k2Ramp=1;
}
}
// update registers
if (chan[i].volChanged) {
if (!isMuted[i]) { // calculate volume (16 bit)
@ -267,72 +391,96 @@ void DivPlatformES5506::tick() {
}
chan[i].volChanged=false;
}
if (chan[i].filterChanged) {
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
if (chan[i].filterChanged.changed) {
if (!chan[i].keyOn) {
pageWrite(0x00|i,0x07,chan[i].filter.k2);
pageWrite(0x00|i,0x09,chan[i].filter.k1);
if (chan[i].filterChanged.mode) {
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
}
if (chan[i].filterChanged.k2) {
if (chan[i].std.ex2.mode==0) { // Relative
pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
} else {
pageWrite(0x00|i,0x07,chan[i].filter.k2);
}
}
if (chan[i].filterChanged.k1) {
if (chan[i].std.ex1.mode==0) { // Relative
pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
} else {
pageWrite(0x00|i,0x09,chan[i].filter.k1);
}
}
}
chan[i].filterChanged=false;
chan[i].filterChanged.changed=0;
}
if (chan[i].envChanged) {
if (chan[i].envChanged.changed) {
if (!chan[i].keyOn) {
pageWrite(0x00|i,0x06,chan[i].envelope.ecount);
if (chan[i].envChanged.lVRamp) {
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
}
if (chan[i].envChanged.rVRamp) {
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
}
if (chan[i].envChanged.ecount) {
pageWrite(0x00|i,0x06,chan[i].envelope.ecount);
}
if (chan[i].envChanged.k2Ramp) {
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
}
if (chan[i].envChanged.k1Ramp) {
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
}
}
chan[i].envChanged=false;
}
if (chan[i].rampChanged) {
if (!chan[i].keyOn) {
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
}
chan[i].rampChanged=false;
chan[i].envChanged.changed=0;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq*(chanMax+1),chan[i].pitch,false)+chan[i].std.pitch.val;
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff;
if (chan[i].keyOn) {
if (chan[i].pcm.index>=0) {
pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR
pageWrite(0x00|i,0x06,0); // Clear ECOUNT
pageWrite(0x20|i,0x03,chan[i].pcm.base); // Set ACCUM to start address
pageWrite(0x00|i,0x09,0xffff); // Set K1 and K2 to 0xffff
pageWrite(0x00|i,0x07,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay
pageWrite(0x20|i,0x03,chan[i].pcm.reversed?chan[i].pcm.end:chan[i].pcm.start); // Set ACCUM to start address
pageWrite(0x00|i,0x07,0xffff); // Set K1 and K2 to 0xffff
pageWrite(0x00|i,0x09,0xffff);
pageWrite(0x00|i,0x01,chan[i].freq);
if (chan[i].pcm.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) {
pageWrite(0x20|i,0x01,chan[i].pcm.loopStart);
}
pageWrite(0x20|i,0x02,chan[i].pcm.loopEnd);
pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart);
pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd);
// initialize envelope
pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8);
pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8);
pageWrite(0x00|i,0x0a,(((unsigned char)chan[i].envelope.k1Ramp)<<8)|(chan[i].envelope.k1Slow?1:0));
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0),~0,(chanMax+1)*4*2); // needs to 4 sample period delay
// initialize filter
pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300);
pageWrite(0x00|i,0x09,chan[i].filter.k1);
pageWrite(0x00|i,0x07,chan[i].filter.k2);
if ((chan[i].std.ex2.mode==0) && (chan[i].std.ex2.had)) {
pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
} else {
pageWrite(0x00|i,0x07,chan[i].filter.k2);
}
if ((chan[i].std.ex1.mode==0) && (chan[i].std.ex1.had)) {
pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
} else {
pageWrite(0x00|i,0x09,chan[i].filter.k1);
}
pageWrite(0x00|i,0x02,chan[i].resLVol);
pageWrite(0x00|i,0x04,chan[i].resRVol);
unsigned int loopFlag=0x0000;
chan[i].isReversed=false;
unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000;
chan[i].isReverseLoop=false;
switch (chan[i].pcm.loopMode) {
case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop)
default:
loopFlag=0x0000;
break;
case DIV_SAMPLE_LOOPMODE_FOWARD: // Foward loop
loopFlag=0x0008;
loopFlag|=0x0008;
break;
case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable
loopFlag=0x0038;
chan[i].isReversed=true;
loopFlag|=0x0038;
chan[i].isReverseLoop=true;
break;
case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support
loopFlag=0x0018;
loopFlag|=0x0018;
break;
}
// Run sample
@ -341,7 +489,7 @@ void DivPlatformES5506::tick() {
}
}
if (chan[i].keyOff) {
pageWriteMask(0x00|i,0x5f,0x00,0x0003); // Wipeout CR
pageWriteMask(0x00|i,0x5f,0x00,0x0303); // Wipeout CR
} else if (chan[i].active) {
pageWrite(0x00|i,0x01,chan[i].freq);
}
@ -356,30 +504,38 @@ int DivPlatformES5506::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample;
double off=1.0;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
chan[c.chan].pcm.index=chan[c.chan].sample;
DivSample* s=parent->getSample(chan[c.chan].sample);
if (s->centerRate<1) {
off=1.0;
if (chan[c.chan].insChanged) {
chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample;
double off=1.0;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
chan[c.chan].pcm.index=chan[c.chan].sample;
DivSample* s=parent->getSample(chan[c.chan].sample);
if (s->centerRate<1) {
off=1.0;
} else {
off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0);
}
const unsigned int start=s->offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT;
chan[c.chan].pcm.freqOffs=off;
chan[c.chan].pcm.reversed=ins->amiga.reversed;
chan[c.chan].pcm.bank=(s->offES5506>>22)&3;
chan[c.chan].pcm.start=start;
chan[c.chan].pcm.end=end;
chan[c.chan].pcm.length=length;
chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800;
chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80;
chan[c.chan].filter=ins->es5506.filter;
chan[c.chan].envelope=ins->es5506.envelope;
} else {
off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0);
chan[c.chan].sample=-1;
chan[c.chan].pcm.index=-1;
chan[c.chan].filter=DivInstrumentES5506::Filter();
chan[c.chan].envelope=DivInstrumentES5506::Envelope();
}
unsigned int base=s->offES5506<<10;
chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT;
chan[c.chan].pcm.freqOffs=off;
chan[c.chan].pcm.bank=(s->offES5506>>22)&3;
chan[c.chan].pcm.base=base;
chan[c.chan].pcm.loopStart=(base+(s->loopStart<<11))&0xfffff800;
chan[c.chan].pcm.loopEnd=((base+(s->loopEnd<<11))-0x800)&0xffffff80;
chan[c.chan].filter=ins->es5506.filter;
chan[c.chan].envelope=ins->es5506.envelope;
} else {
chan[c.chan].sample=-1;
chan[c.chan].pcm.index=-1;
chan[c.chan].filter=DivInstrumentES5506::Filter();
chan[c.chan].envelope=DivInstrumentES5506::Envelope();
chan[c.chan].insChanged=false;
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value);
@ -466,6 +622,45 @@ int DivPlatformES5506::dispatch(DivCommand c) {
chan[c.chan].pitch=c.value;
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_WAVE:
// reserved for useWave
break;
// Filter commands
case DIV_CMD_ES5506_FILTER_MODE:
chan[c.chan].filter.mode=DivInstrumentES5506::Filter::FilterMode(c.value&3);
chan[c.chan].filterChanged.mode=1;
break;
case DIV_CMD_ES5506_FILTER_K1:
chan[c.chan].filter.k1=(chan[c.chan].filter.k1&0xf)|((c.value&0xfff)<<4);
chan[c.chan].filterChanged.k1=1;
break;
case DIV_CMD_ES5506_FILTER_K2:
chan[c.chan].filter.k2=(chan[c.chan].filter.k2&0xf)|((c.value&0xfff)<<4);
chan[c.chan].filterChanged.k2=1;
break;
// Envelope commands
case DIV_CMD_ES5506_ENVELOPE_COUNT:
chan[c.chan].envelope.ecount=c.value&0x1ff;
chan[c.chan].envChanged.ecount=1;
break;
case DIV_CMD_ES5506_ENVELOPE_LVRAMP:
chan[c.chan].envelope.lVRamp=(signed char)(c.value&0xff);
chan[c.chan].envChanged.lVRamp=1;
break;
case DIV_CMD_ES5506_ENVELOPE_RVRAMP:
chan[c.chan].envelope.rVRamp=(signed char)(c.value&0xff);
chan[c.chan].envChanged.rVRamp=1;
break;
case DIV_CMD_ES5506_ENVELOPE_K1RAMP:
chan[c.chan].envelope.k1Ramp=(signed char)(c.value&0xff);
chan[c.chan].envelope.k1Slow=c.value2&1;
chan[c.chan].envChanged.k1Ramp=1;
break;
case DIV_CMD_ES5506_ENVELOPE_K2RAMP:
chan[c.chan].envelope.k2Ramp=(signed char)(c.value&0xff);
chan[c.chan].envelope.k2Slow=c.value2&1;
chan[c.chan].envChanged.k2Ramp=1;
break;
case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_ES5506(c.chan,c.value2);
bool return2=false;
@ -501,6 +696,16 @@ int DivPlatformES5506::dispatch(DivCommand c) {
}
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_SAMPLE_POS: {
if (chan[c.chan].useWave) break;
if (chan[c.chan].active) {
unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value;
if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && pos<chan[c.chan].pcm.length)) {
pageWrite(0x20|c.chan,0x03,chan[c.chan].pcm.start+(pos<<11));
}
}
break;
}
case DIV_CMD_GET_VOLMAX:
return 255;
break;
@ -523,6 +728,8 @@ void DivPlatformES5506::forceIns() {
chan[i].insChanged=true;
chan[i].freqChanged=true;
chan[i].volChanged=true;
chan[i].filterChanged.changed=(unsigned char)(~0);
chan[i].envChanged.changed=(unsigned char)(~0);
chan[i].sample=-1;
}
}
@ -629,7 +836,7 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned in
setFlags(flags);
chipClock=16000000;
rate=chipClock/16;
rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice
reset();
return 32;
}

View file

@ -32,33 +32,69 @@
class DivPlatformES5506: public DivDispatch, public es550x_intf {
struct Channel {
struct PCM {
double freqOffs;
int index;
double freqOffs;
bool reversed;
unsigned int bank;
unsigned int base;
unsigned int start;
unsigned int end;
unsigned int length;
unsigned int loopStart;
unsigned int loopEnd;
DivSampleLoopMode loopMode;
PCM():
freqOffs(1.0),
index(-1),
freqOffs(1.0),
reversed(false),
bank(0),
base(0),
start(0),
end(0),
length(0),
loopStart(0),
loopEnd(0),
loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
} pcm;
int freq, baseFreq, pitch;
unsigned short audLen;
unsigned int audPos;
int sample, wave;
unsigned char ins;
int note;
int panning;
bool active, insChanged, freqChanged, volChanged, filterChanged, envChanged, rampChanged, keyOn, keyOff, inPorta, useWave, isReversed;
int vol, outVol;
int lVol, outLVol;
int rVol, outRVol;
bool active, insChanged, freqChanged, volChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop;
struct FilterChanged { // Filter changed flags
union { // pack flag bits in single byte
struct { // flag bits
unsigned char mode: 1; // Filter mode
unsigned char k1: 1; // K1
unsigned char k2: 1; // K2
unsigned char dummy: 5; // dummy for bit padding
};
unsigned char changed; // Packed flags are stored here
};
FilterChanged():
changed(0) {}
} filterChanged;
struct EnvChanged { // Envelope changed flags
union { // pack flag bits in single byte
struct { // flag bits
unsigned char ecount: 1; // Envelope count
unsigned char lVRamp: 1; // Left volume Ramp
unsigned char rVRamp: 1; // Right volume Ramp
unsigned char k1Ramp: 1; // K1 Ramp w/Slow flag
unsigned char k2Ramp: 1; // K2 Ramp w/Slow flag
unsigned char dummy: 3; // dummy for bit padding
};
unsigned char changed; // Packed flags are stored here
};
EnvChanged():
changed(0) {}
} envChanged;
signed int k1Offs, k2Offs;
int vol, lVol, rVol;
int outVol, outLVol, outRVol;
int resLVol, resRVol;
DivInstrumentES5506::Filter filter;
DivInstrumentES5506::Envelope envelope;
@ -67,27 +103,23 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
freq(0),
baseFreq(0),
pitch(0),
audLen(0),
audPos(0),
sample(-1),
ins(-1),
note(0),
panning(0x10),
active(false),
insChanged(true),
freqChanged(false),
volChanged(false),
filterChanged(false),
envChanged(false),
rampChanged(false),
keyOn(false),
keyOff(false),
inPorta(false),
vol(0xffff),
k1Offs(0),
k2Offs(0),
vol(0xff),
lVol(0xf),
rVol(0xf),
outVol(0xffff),
lVol(0xffff),
outLVol(0xffff),
rVol(0xffff),
outRVol(0xffff),
resLVol(0xffff),
resRVol(0xffff) {}
@ -150,7 +182,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
virtual int getRegisterPoolSize() override;
virtual void reset() override;
virtual void forceIns() override;
virtual void tick() override;
virtual void tick(bool sysTick=true) override;
virtual void muteChannel(int ch, bool mute) override;
virtual bool isStereo() override;
virtual bool keyOffAffectsArp(int ch) override;

View file

@ -97,7 +97,7 @@ void DivPlatformFDS::updateWave() {
rWrite(0x4089,0);
}
void DivPlatformFDS::tick() {
void DivPlatformFDS::tick(bool sysTick) {
for (int i=0; i<1; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -107,21 +107,11 @@ void DivPlatformFDS::tick() {
rWrite(0x4080,0x80|chan[i].outVol);
}
if (chan[i].std.arp.had) {
if (i==3) { // noise
if (!chan[i].inPorta) {
if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp.val;
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
}
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else {
if (!chan[i].inPorta) {
if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
}
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
}
}
chan[i].freqChanged=true;
@ -155,6 +145,9 @@ void DivPlatformFDS::tick() {
//if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].active) {
if (ws.tick()) {
updateWave();
@ -205,7 +198,7 @@ void DivPlatformFDS::tick() {
int DivPlatformFDS::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FDS);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].freqChanged=true;
@ -365,7 +358,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -77,7 +77,7 @@ class DivPlatformFDS: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void setFlags(unsigned int flags);

View file

@ -146,7 +146,7 @@ static unsigned char noiseTable[256]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void DivPlatformGB::tick() {
void DivPlatformGB::tick(bool sysTick) {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.arp.had) {
@ -176,7 +176,7 @@ void DivPlatformGB::tick() {
}
if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty.val;
DivInstrument* ins=parent->getIns(chan[i].ins);
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB);
if (i!=2) {
rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
} else {
@ -192,6 +192,14 @@ void DivPlatformGB::tick() {
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].std.panL.had) {
lastPan&=~(0x11<<i);
lastPan|=((chan[i].std.panL.val&1)<<i)|((chan[i].std.panL.val&2)<<(i+3));
rWrite(0x25,procMute());
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -212,7 +220,7 @@ void DivPlatformGB::tick() {
}
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
DivInstrument* ins=parent->getIns(chan[i].ins);
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB);
if (i==3) { // noise
int ntPos=chan[i].baseFreq;
if (ntPos<0) ntPos=0;
@ -261,7 +269,7 @@ void DivPlatformGB::muteChannel(int ch, bool mute) {
int DivPlatformGB::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB);
if (c.value!=DIV_NOTE_NULL) {
if (c.chan==3) { // noise
chan[c.chan].baseFreq=c.value;
@ -298,7 +306,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].ins=c.value;
chan[c.chan].insChanged=true;
if (c.chan!=2) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB);
chan[c.chan].vol=ins->gb.envVol;
if (parent->song.gbInsAffectsEnvelope) {
rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
@ -352,7 +360,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].duty=c.value;
if (c.chan!=2) {
chan[c.chan].freqChanged=true;
rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins)->gb.soundLen&63)));
rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins,DIV_INS_GB)->gb.soundLen&63)));
}
break;
case DIV_CMD_PANNING: {
@ -371,7 +379,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -70,7 +70,7 @@ class DivPlatformGB: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
void notifyInsChange(int ins);

View file

@ -222,7 +222,7 @@ void DivPlatformGenesis::acquire(short* bufL, short* bufR, size_t start, size_t
}
}
void DivPlatformGenesis::tick() {
void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<6; i++) {
if (i==2 && extMode) continue;
chan[i].std.next();
@ -260,6 +260,15 @@ void DivPlatformGenesis::tick() {
}
}
if (chan[i].std.panL.had) {
chan[i].pan=chan[i].std.panL.val&3;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -477,7 +486,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
int DivPlatformGenesis::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
if (c.chan==5) {
if (ins->type==DIV_INS_AMIGA) {
dacMode=1;

View file

@ -109,7 +109,7 @@ class DivPlatformGenesis: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
void setYMFM(bool use);

View file

@ -37,7 +37,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
int ordch=orderedOps[ch];
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (opChan[ch].insChanged) {
chan[2].state.alg=ins->fm.alg;
@ -266,7 +266,7 @@ static int opChanOffsH[4]={
0xad, 0xae, 0xac, 0xa6
};
void DivPlatformGenesisExt::tick() {
void DivPlatformGenesisExt::tick(bool sysTick) {
if (extMode) {
bool writeSomething=false;
unsigned char writeMask=2;
@ -283,7 +283,7 @@ void DivPlatformGenesisExt::tick() {
}
}
DivPlatformGenesis::tick();
DivPlatformGenesis::tick(sysTick);
bool writeNoteOn=false;
unsigned char writeMask=2;

View file

@ -41,7 +41,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
void* getChanState(int chan);
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);

View file

@ -145,7 +145,7 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
mikey->sampleAudio( bufL + start, bufR + start, len );
}
void DivPlatformLynx::tick() {
void DivPlatformLynx::tick(bool sysTick) {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -171,6 +171,24 @@ void DivPlatformLynx::tick() {
}
}
if (chan[i].std.panL.had) {
chan[i].pan&=0x0f;
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
}
if (chan[i].std.panR.had) {
chan[i].pan&=0xf0;
chan[i].pan|=chan[i].std.panR.val&15;
}
if (chan[i].std.panL.had || chan[i].std.panR.had) {
WRITE_ATTEN(i,chan[i].pan);
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged) {
if (chan[i].lfsr >= 0) {
WRITE_LFSR(i, (chan[i].lfsr&0xff));
@ -184,8 +202,8 @@ void DivPlatformLynx::tick() {
}
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
WRITE_BACKUP( i, chan[i].fd.backup );
}
else if (chan[i].std.duty.had) {
chan[i].freqChanged=false;
} else if (chan[i].std.duty.had) {
chan[i].duty = chan[i].std.duty.val;
WRITE_FEEDBACK(i, chan[i].duty.feedback);
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
@ -206,7 +224,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -223,7 +241,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
break;
case DIV_CMD_INSTRUMENT:
chan[c.chan].ins=c.value;
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
@ -279,7 +297,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -80,7 +80,7 @@ class DivPlatformLynx: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -96,7 +96,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
}
}
void DivPlatformMMC5::tick() {
void DivPlatformMMC5::tick(bool sysTick) {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -124,6 +124,9 @@ void DivPlatformMMC5::tick() {
chan[i].duty=chan[i].std.duty.val;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].freqChanged=true;
@ -175,7 +178,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.chan==2) { // PCM
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD);
if (ins->type==DIV_INS_AMIGA) {
dacSample=ins->amiga.initSample;
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
@ -225,7 +228,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
break;
case DIV_CMD_NOTE_OFF:
@ -303,7 +306,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -71,7 +71,7 @@ class DivPlatformMMC5: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
float getPostAmp();

View file

@ -214,7 +214,7 @@ void DivPlatformN163::updateWaveCh(int ch) {
}
}
void DivPlatformN163::tick() {
void DivPlatformN163::tick(bool sysTick) {
for (int i=0; i<=chanMax; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -261,6 +261,9 @@ void DivPlatformN163::tick() {
}
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.ex1.had) {
if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
chan[i].waveLen=chan[i].std.ex1.val&0xfc;
@ -371,7 +374,7 @@ void DivPlatformN163::tick() {
int DivPlatformN163::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_N163);
if (chan[c.chan].insChanged) {
chan[c.chan].wave=ins->n163.wave;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -543,7 +546,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) {
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_N163));
chan[c.chan].keyOn=true;
}
}

View file

@ -93,7 +93,7 @@ class DivPlatformN163: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
void notifyWaveChange(int wave);

View file

@ -141,7 +141,7 @@ static unsigned char noiseTable[253]={
15
};
void DivPlatformNES::tick() {
void DivPlatformNES::tick(bool sysTick) {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -196,6 +196,9 @@ void DivPlatformNES::tick() {
chan[i].freqChanged=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].sweepChanged) {
chan[i].sweepChanged=false;
if (i==0) {
@ -269,7 +272,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.chan==4) { // PCM
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD);
if (ins->type==DIV_INS_AMIGA) {
dacSample=ins->amiga.initSample;
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
@ -323,7 +326,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (c.chan==2) {
rWrite(0x4000+c.chan*4,0xff);
} else {
@ -426,7 +429,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -72,7 +72,7 @@ class DivPlatformNES: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
float getPostAmp();

View file

@ -228,7 +228,7 @@ void DivPlatformOPL::acquire(short* bufL, short* bufR, size_t start, size_t len)
//}
}
void DivPlatformOPL::tick() {
void DivPlatformOPL::tick(bool sysTick) {
for (int i=0; i<totalChans; i++) {
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
chan[i].std.next();
@ -269,6 +269,14 @@ void DivPlatformOPL::tick() {
}
}
if (oplType==3 && chan[i].std.panL.had) {
chan[i].pan=((chan[i].std.panL.val&1)<<1)|((chan[i].std.panL.val&2)>>1);
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -282,7 +290,7 @@ void DivPlatformOPL::tick() {
chan[i].state.fb=chan[i].std.fb.val;
}
if (chan[i].std.alg.had || chan[i].std.fb.had) {
if (chan[i].std.alg.had || chan[i].std.fb.had || (oplType==3 && chan[i].std.panL.had)) {
if (isMuted[i]) {
rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1));
if (ops==4) {
@ -527,7 +535,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
}
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;

View file

@ -104,7 +104,7 @@ class DivPlatformOPL: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
void setYMFM(bool use);

View file

@ -111,7 +111,7 @@ void DivPlatformOPLL::acquire(short* bufL, short* bufR, size_t start, size_t len
acquire_nuked(bufL,bufR,start,len);
}
void DivPlatformOPLL::tick() {
void DivPlatformOPLL::tick(bool sysTick) {
for (int i=0; i<11; i++) {
chan[i].std.next();
@ -145,6 +145,10 @@ void DivPlatformOPLL::tick() {
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -361,7 +365,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
if (c.chan>=9 && !properDrums) return 0;
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;
}

View file

@ -100,7 +100,7 @@ class DivPlatformOPLL: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setYMFM(bool use);
bool keyOffAffectsArp(int ch);

View file

@ -146,7 +146,7 @@ static unsigned char noiseFreq[12]={
4,13,15,18,21,23,25,27,29,31,0,2
};
void DivPlatformPCE::tick() {
void DivPlatformPCE::tick(bool sysTick) {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -196,13 +196,27 @@ void DivPlatformPCE::tick() {
if (!chan[i].keyOff) chan[i].keyOn=true;
}
}
if (chan[i].std.panL.had) {
chan[i].pan&=0x0f;
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
}
if (chan[i].std.panR.had) {
chan[i].pan&=0xf0;
chan[i].pan|=chan[i].std.panR.val&15;
}
if (chan[i].std.panL.had || chan[i].std.panR.had) {
chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].active) {
if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) {
updateWave(i);
}
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins);
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
if (chan[i].furnaceDac) {
double off=1.0;
@ -237,7 +251,7 @@ void DivPlatformPCE::tick() {
int DivPlatformPCE::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].pcm=true;
} else if (chan[c.chan].furnaceDac) {
@ -415,7 +429,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -87,7 +87,7 @@ class DivPlatformPCE: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -164,7 +164,7 @@ void DivPlatformPCSpeaker::acquire(short* bufL, short* bufR, size_t start, size_
}
}
void DivPlatformPCSpeaker::tick() {
void DivPlatformPCSpeaker::tick(bool sysTick) {
for (int i=0; i<1; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -186,6 +186,9 @@ void DivPlatformPCSpeaker::tick() {
chan[i].freqChanged=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
if (chan[i].freq<0) chan[i].freq=0;
@ -214,7 +217,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -279,7 +282,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -77,7 +77,7 @@ class DivPlatformPCSpeaker: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void setFlags(unsigned int flags);

View file

@ -85,7 +85,7 @@ void DivPlatformPET::writeOutVol() {
}
}
void DivPlatformPET::tick() {
void DivPlatformPET::tick(bool sysTick) {
chan.std.next();
if (chan.std.vol.had) {
chan.outVol=chan.std.vol.val&chan.vol;
@ -112,6 +112,9 @@ void DivPlatformPET::tick() {
rWrite(10,chan.wave);
}
}
if (chan.std.pitch.had) {
chan.freqChanged=true;
}
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true)+chan.std.pitch.val;
if (chan.freq>257) chan.freq=257;
@ -135,7 +138,7 @@ void DivPlatformPET::tick() {
int DivPlatformPET::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan.ins);
DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_PET);
if (c.value!=DIV_NOTE_NULL) {
chan.baseFreq=NOTE_PERIODIC(c.value);
chan.freqChanged=true;
@ -210,7 +213,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan.active && c.value2) {
if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins));
if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins,DIV_INS_PET));
}
chan.inPorta=c.value;
break;

View file

@ -65,7 +65,7 @@ class DivPlatformPET: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsDeletion(void* ins);
bool isStereo();

View file

@ -274,7 +274,7 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l
}
}
void DivPlatformQSound::tick() {
void DivPlatformQSound::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -326,8 +326,11 @@ void DivPlatformQSound::tick() {
chan[i].freqChanged=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
//DivInstrument* ins=parent->getIns(chan[i].ins);
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
if (chan[i].freq>0xffff) chan[i].freq=0xffff;
if (chan[i].keyOn) {
@ -360,7 +363,7 @@ void DivPlatformQSound::tick() {
int DivPlatformQSound::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
chan[c.chan].sample=ins->amiga.initSample;
double off=1.0;
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
@ -484,7 +487,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
}
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -74,7 +74,7 @@ class DivPlatformQSound: public DivDispatch {
int getRegisterPoolDepth();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -132,7 +132,7 @@ inline unsigned char applyPan(unsigned char vol, unsigned char pan) {
return ((vol*(pan>>4))/15)|(((vol*(pan&15))/15)<<4);
}
void DivPlatformSAA1099::tick() {
void DivPlatformSAA1099::tick(bool sysTick) {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -166,6 +166,29 @@ void DivPlatformSAA1099::tick() {
if (chan[i].std.wave.had) {
chan[i].psgMode=chan[i].std.wave.val&3;
}
if (chan[i].std.panL.had) {
chan[i].pan&=0x0f;
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
}
if (chan[i].std.panR.had) {
chan[i].pan&=0xf0;
chan[i].pan|=chan[i].std.panR.val&15;
}
if (chan[i].std.panL.had || chan[i].std.panR.had) {
if (isMuted[i]) {
rWrite(i,0);
} else {
if (chan[i].std.vol.had) {
if (chan[i].active) rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan));
} else {
if (chan[i].active) rWrite(i,applyPan(chan[i].vol&15,chan[i].pan));
}
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.ex1.had) {
saaEnv[i/3]=chan[i].std.ex1.val;
rWrite(0x18+(i/3),saaEnv[i/3]);
@ -226,7 +249,7 @@ void DivPlatformSAA1099::tick() {
int DivPlatformSAA1099::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
@ -333,7 +356,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -90,7 +90,7 @@ class DivPlatformSAA1099: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setCore(DivSAACores core);
void setFlags(unsigned int flags);

View file

@ -76,13 +76,14 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
}
}
void DivPlatformSegaPCM::tick() {
void DivPlatformSegaPCM::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
// TODO: fix
/*if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
}
}*/
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
@ -99,6 +100,24 @@ void DivPlatformSegaPCM::tick() {
chan[i].freqChanged=true;
}
}
if (chan[i].std.panL.had) {
chan[i].chVolL=chan[i].std.panL.val&127;
if (dumpWrites) {
addWrite(0x10002+(i<<3),chan[i].chVolL);
}
}
if (chan[i].std.panR.had) {
chan[i].chVolR=chan[i].std.panR.val&127;
if (dumpWrites) {
addWrite(0x10003+(i<<3),chan[i].chVolR);
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
/*if (chan[i].keyOn || chan[i].keyOff) {
chan[i].keyOff=false;
}*/
@ -130,7 +149,7 @@ void DivPlatformSegaPCM::muteChannel(int ch, bool mute) {
int DivPlatformSegaPCM::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
if (skipRegisterWrites) break;
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].pcm.sample=ins->amiga.initSample;
@ -139,14 +158,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
if (dumpWrites) {
addWrite(0x10086+(c.chan<<3),3);
}
chan[c.chan].std.init(NULL);
break;
}
chan[c.chan].pcm.pos=0;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value;
chan[c.chan].baseFreq=(c.value<<6);
chan[c.chan].freqChanged=true;
}
chan[c.chan].furnacePCM=true;
chan[c.chan].std.init(ins);
if (dumpWrites) { // Sega PCM writes
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
@ -163,6 +185,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
}
}
} else {
chan[c.chan].std.init(NULL);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value;
}
@ -204,6 +227,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
chan[c.chan].std.init(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;

View file

@ -78,7 +78,7 @@ class DivPlatformSegaPCM: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsChange(int ins);
void setFlags(unsigned int flags);

View file

@ -23,8 +23,6 @@
#define rWrite(v) {if (!skipRegisterWrites) {sn->write(v); if (dumpWrites) {addWrite(0x200,v);}}}
#define CHIP_DIVIDER 64
const char* regCheatSheetSN[]={
"DATA", "0",
NULL
@ -53,8 +51,10 @@ int DivPlatformSMS::acquireOne() {
return v;
}
void DivPlatformSMS::tick() {
void DivPlatformSMS::tick(bool sysTick) {
for (int i=0; i<4; i++) {
int CHIP_DIVIDER=64;
if (i==3 && isRealSN) CHIP_DIVIDER=60;
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));
@ -98,6 +98,9 @@ void DivPlatformSMS::tick() {
}
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
}
for (int i=0; i<3; i++) {
if (chan[i].freqChanged) {
@ -116,8 +119,7 @@ void DivPlatformSMS::tick() {
}
}
if (chan[3].freqChanged || updateSNMode) {
// seems arbitrary huh?
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch-1-(isRealSN?127:0),true)+chan[3].std.pitch.val;
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true)+chan[3].std.pitch.val;
if (chan[3].freq>1023) chan[3].freq=1023;
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
if (snNoiseMode&2) { // take period from channel 3
@ -161,6 +163,8 @@ void DivPlatformSMS::tick() {
}
int DivPlatformSMS::dispatch(DivCommand c) {
int CHIP_DIVIDER=64;
if (c.chan==3 && isRealSN) CHIP_DIVIDER=60;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.value!=DIV_NOTE_NULL) {
@ -171,7 +175,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -184,7 +188,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
break;
case DIV_CMD_INSTRUMENT:
chan[c.chan].ins=c.value;
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
//chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
@ -240,7 +244,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -63,7 +63,7 @@ class DivPlatformSMS: public DivDispatch {
void* getChanState(int chan);
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);

View file

@ -21,6 +21,7 @@ namespace es550x
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
@ -250,12 +251,14 @@ protected:
: m_integer(integer)
, m_fraction(fraction)
, m_total_bits(integer + fraction)
, m_accum_mask(u32(std::min<u64>(~0, u64(u64(1) << u64(integer + fraction)) - 1)))
, m_transwave(transwave)
{}
const u8 m_integer;
const u8 m_fraction;
const u8 m_total_bits;
const u32 m_accum_mask;
const bool m_transwave;
void reset();

View file

@ -29,15 +29,14 @@ bool es550x_shared_core::es550x_alu_t::busy()
bool es550x_shared_core::es550x_alu_t::tick()
{
if (m_cr.dir)
{
m_accum = bitfield(m_accum - m_fc, 0, m_total_bits);
return ((!m_cr.lei) && (m_accum < m_start)) ? true : false;
}
m_accum -= m_fc;
else
{
m_accum = bitfield(m_accum + m_fc, 0, m_total_bits);
return ((!m_cr.lei) && (m_accum > m_end)) ? true : false;
}
m_accum += m_fc;
m_accum &= m_accum_mask;
return ((!m_cr.lei)
&& ((( m_cr.dir) && (m_accum < m_start))
|| ((!m_cr.dir) && (m_accum > m_end)))) ? true : false;
}
void es550x_shared_core::es550x_alu_t::loop_exec()

View file

@ -141,13 +141,13 @@ void DivPlatformSwan::writeOutVol(int ch) {
}
}
void DivPlatformSwan::tick() {
void DivPlatformSwan::tick(bool sysTick) {
unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0);
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
int env=chan[i].std.vol.val;
if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) {
if(parent->getIns(chan[i].ins,DIV_INS_SWAN)->type==DIV_INS_AMIGA) {
env=MIN(env/4,15);
}
calcAndWriteOutVol(i,env);
@ -173,6 +173,20 @@ void DivPlatformSwan::tick() {
chan[i].ws.changeWave1(chan[i].wave);
}
}
if (chan[i].std.panL.had) {
chan[i].pan&=0x0f;
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
}
if (chan[i].std.panR.had) {
chan[i].pan&=0xf0;
chan[i].pan|=chan[i].std.panR.val&15;
}
if (chan[i].std.panL.had || chan[i].std.panR.had) {
calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15);
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].active) {
sndCtrl|=(1<<i);
if (chan[i].ws.tick()) {
@ -226,7 +240,7 @@ void DivPlatformSwan::tick() {
int DivPlatformSwan::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN);
if (c.chan==1) {
if (ins->type==DIV_INS_AMIGA) {
pcm=true;
@ -401,7 +415,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -77,7 +77,7 @@ class DivPlatformSwan: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins);

View file

@ -84,7 +84,7 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi
return 0;
}
void DivPlatformTIA::tick() {
void DivPlatformTIA::tick(bool sysTick) {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -116,6 +116,9 @@ void DivPlatformTIA::tick() {
rWrite(0x15+i,chan[i].shape);
chan[i].freqChanged=true;
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (chan[i].insChanged) {
if (!chan[i].std.wave.will) {
@ -151,7 +154,7 @@ void DivPlatformTIA::tick() {
int DivPlatformTIA::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_TIA);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=c.value<<8;
chan[c.chan].freqChanged=true;
@ -245,7 +248,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -51,7 +51,7 @@ class DivPlatformTIA: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
bool isStereo();

View file

@ -183,7 +183,7 @@ inline int hScale(int note) {
return ((note/12)<<4)+(noteMap[note%12]);
}
void DivPlatformTX81Z::tick() {
void DivPlatformTX81Z::tick(bool sysTick) {
for (int i=0; i<8; i++) {
chan[i].std.next();
@ -228,6 +228,10 @@ void DivPlatformTX81Z::tick() {
rWrite(0x1b,chan[i].std.wave.val&3);
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -420,7 +424,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) {
int DivPlatformTX81Z::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;

View file

@ -102,7 +102,7 @@ class DivPlatformTX81Z: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsChange(int ins);
void setFlags(unsigned int flags);

View file

@ -114,8 +114,8 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
psg_render(psg,buf[0],buf[1],curLen);
pcm_render(pcm,buf[2],buf[3],curLen);
for (int i=0; i<curLen; i++) {
bufL[pos]=(short)(((int)buf[0][i]+(buf[2][i]>>1))/2);
bufR[pos]=(short)(((int)buf[1][i]+(buf[3][i]>>1))/2);
bufL[pos]=(short)(((int)buf[0][i]+buf[2][i])/2);
bufR[pos]=(short)(((int)buf[1][i]+buf[3][i])/2);
pos++;
}
len-=curLen;
@ -156,7 +156,7 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) {
}
}
void DivPlatformVERA::tick() {
void DivPlatformVERA::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -184,6 +184,15 @@ void DivPlatformVERA::tick() {
if (chan[i].std.wave.had) {
rWriteHi(i,3,chan[i].std.wave.val);
}
if (i<16) {
if (chan[i].std.panL.had) {
chan[i].pan=chan[i].std.panL.val&3;
rWriteHi(i,2,isMuted[i]?0:chan[i].pan);
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8)+chan[i].std.pitch.val;
if (chan[i].freq>65535) chan[i].freq=65535;
@ -228,7 +237,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
if(c.chan<16) {
rWriteLo(c.chan,2,chan[c.chan].vol)
} else {
chan[16].pcm.sample=parent->getIns(chan[16].ins)->amiga.initSample;
chan[16].pcm.sample=parent->getIns(chan[16].ins,DIV_INS_VERA)->amiga.initSample;
if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) {
chan[16].pcm.sample=-1;
}
@ -250,7 +259,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
chan[c.chan].note=c.value;
}
chan[c.chan].active=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -318,7 +327,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
}
chan[c.chan].inPorta=c.value;
break;
@ -374,7 +383,7 @@ void DivPlatformVERA::muteChannel(int ch, bool mute) {
}
float DivPlatformVERA::getPostAmp() {
return 4.0f;
return 8.0f;
}
bool DivPlatformVERA::isStereo() {

View file

@ -63,7 +63,7 @@ class DivPlatformVERA: public DivDispatch {
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void notifyInsDeletion(void* ins);
float getPostAmp();

View file

@ -91,7 +91,7 @@ void DivPlatformVIC20::writeOutVol(int ch) {
}
}
void DivPlatformVIC20::tick() {
void DivPlatformVIC20::tick(bool sysTick) {
for (int i=0; i<4; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -119,6 +119,9 @@ void DivPlatformVIC20::tick() {
chan[i].keyOn=true;
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
if (i<3) {
@ -155,7 +158,7 @@ void DivPlatformVIC20::tick() {
int DivPlatformVIC20::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VIC);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
@ -229,7 +232,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -66,7 +66,7 @@ class DivPlatformVIC20: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(unsigned int flags);
void notifyInsDeletion(void* ins);

View file

@ -135,7 +135,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
}
}
void DivPlatformVRC6::tick() {
void DivPlatformVRC6::tick(bool sysTick) {
for (int i=0; i<3; i++) {
// 16 for pulse; 14 for saw
int CHIP_DIVIDER=(i==2)?14:16;
@ -178,6 +178,9 @@ void DivPlatformVRC6::tick() {
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4));
}
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (i==2) { // sawtooth
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
@ -217,7 +220,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.chan!=2) { // pulse wave
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6);
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].pcm=true;
} else if (chan[c.chan].furnaceDac) {
@ -281,7 +284,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
if (!isMuted[c.chan]) {
if (c.chan==2) { // sawtooth
chWrite(c.chan,0,chan[c.chan].vol);
@ -377,7 +380,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
}
chan[c.chan].inPorta=c.value;
break;
@ -431,9 +434,9 @@ void DivPlatformVRC6::reset() {
chan[i]=DivPlatformVRC6::Channel();
chan[i].std.setEngine(parent);
}
// a poll may be necessary to decide the default
chan[2].vol=30;
chan[2].outVol=30;
// HELP
chan[2].vol=63;
chan[2].outVol=63;
if (dumpWrites) {
addWrite(0xffffffff,0);
}

View file

@ -82,7 +82,7 @@ class DivPlatformVRC6: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void setFlags(unsigned int flags);

View file

@ -336,7 +336,7 @@ void DivPlatformX1_010::updateEnvelope(int ch) {
}
}
void DivPlatformX1_010::tick() {
void DivPlatformX1_010::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
@ -372,6 +372,19 @@ void DivPlatformX1_010::tick() {
}
}
}
if (chan[i].std.panL.had) {
chan[i].pan&=0x0f;
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
chan[i].envChanged=true;
}
if (chan[i].std.panR.had) {
chan[i].pan&=0xf0;
chan[i].pan|=chan[i].std.panR.val&15;
chan[i].envChanged=true;
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.ex1.had) {
bool nextEnable=(chan[i].std.ex1.val&1);
if (nextEnable!=(chan[i].env.flag.envEnable)) {
@ -512,7 +525,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
chWrite(c.chan,0,0); // reset previous note
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010);
if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) {
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].furnacePCM=true;
@ -690,7 +703,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
}
chan[c.chan].inPorta=c.value;
break;

View file

@ -126,7 +126,7 @@ class DivPlatformX1_010: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -365,9 +365,9 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
}
}
void DivPlatformYM2610::tick() {
void DivPlatformYM2610::tick(bool sysTick) {
// PSG
ay->tick();
ay->tick(sysTick);
ay->flushWrites();
for (DivRegWrite& i: ay->getRegisterWrites()) {
immWrite(i.addr&15,i.val);
@ -408,6 +408,15 @@ void DivPlatformYM2610::tick() {
}
}
if (chan[i].std.panL.had) {
chan[i].pan=chan[i].std.panL.val&3;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -626,7 +635,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
if (c.chan>12) { // ADPCM-B
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].furnacePCM=true;
} else {
@ -709,7 +718,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
immWrite(0x100,0x00|(1<<(c.chan-7)));
break;
}
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
chan[c.chan].std.init(ins);
if (c.chan<4) {
if (!chan[c.chan].std.vol.will) {
@ -972,7 +981,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>3) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -116,7 +116,7 @@ class DivPlatformYM2610: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -429,9 +429,9 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t
}
}
void DivPlatformYM2610B::tick() {
void DivPlatformYM2610B::tick(bool sysTick) {
// PSG
ay->tick();
ay->tick(sysTick);
ay->flushWrites();
for (DivRegWrite& i: ay->getRegisterWrites()) {
immWrite(i.addr&15,i.val);
@ -472,6 +472,15 @@ void DivPlatformYM2610B::tick() {
}
}
if (chan[i].std.panL.had) {
chan[i].pan=chan[i].std.panL.val&3;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.pitch.had) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.val==1) {
chan[i].keyOn=true;
@ -689,7 +698,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
if (c.chan>14) { // ADPCM-B
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].furnacePCM=true;
} else {
@ -772,7 +781,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
immWrite(0x100,0x00|(1<<(c.chan-9)));
break;
}
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
chan[c.chan].std.init(ins);
if (c.chan<6) {
if (!chan[c.chan].std.vol.will) {
@ -1035,7 +1044,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
case DIV_CMD_PRE_PORTA:
if (c.chan>5) {
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
}
}
chan[c.chan].inPorta=c.value;

View file

@ -107,7 +107,7 @@ class DivPlatformYM2610B: public DivDispatch {
int getRegisterPoolSize();
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);

View file

@ -36,7 +36,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
int ordch=orderedOps[ch];
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
@ -78,7 +78,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
opChan[ch].vol=c.value;
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch]) {
@ -104,7 +104,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
} else {
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
}
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (parent->song.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
@ -159,14 +159,14 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
break;
}
case DIV_CMD_FM_TL: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (isOutput[ins->fm.alg][c.value]) {
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
} else {
@ -175,7 +175,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_FM_AR: {
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator op=ins->fm.op[i];
@ -212,7 +212,7 @@ static int opChanOffsH[4]={
0xad, 0xae, 0xac, 0xa6
};
void DivPlatformYM2610BExt::tick() {
void DivPlatformYM2610BExt::tick(bool sysTick) {
if (extMode) {
bool writeSomething=false;
unsigned char writeMask=2;
@ -229,7 +229,7 @@ void DivPlatformYM2610BExt::tick() {
}
}
DivPlatformYM2610B::tick();
DivPlatformYM2610B::tick(sysTick);
bool writeNoteOn=false;
unsigned char writeMask=2;
@ -268,7 +268,7 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
isOpMuted[ch-2]=mute;
int ordch=orderedOps[ch-2];
DivInstrument* ins=parent->getIns(opChan[ch-2].ins);
DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch-2]) {

View file

@ -41,7 +41,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B {
void* getChanState(int chan);
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);

View file

@ -36,7 +36,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
int ordch=orderedOps[ch];
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
@ -78,7 +78,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
break;
case DIV_CMD_VOLUME: {
opChan[ch].vol=c.value;
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch]) {
@ -104,7 +104,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
} else {
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
}
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (parent->song.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
@ -159,14 +159,14 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
break;
}
case DIV_CMD_FM_TL: { // TODO
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (isOutput[ins->fm.alg][c.value]) {
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
} else {
@ -175,7 +175,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_FM_AR: {
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator op=ins->fm.op[i];
@ -212,7 +212,7 @@ static int opChanOffsH[4]={
0xad, 0xae, 0xac, 0xa6
};
void DivPlatformYM2610Ext::tick() {
void DivPlatformYM2610Ext::tick(bool sysTick) {
if (extMode) {
bool writeSomething=false;
unsigned char writeMask=2;
@ -229,7 +229,7 @@ void DivPlatformYM2610Ext::tick() {
}
}
DivPlatformYM2610::tick();
DivPlatformYM2610::tick(sysTick);
bool writeNoteOn=false;
unsigned char writeMask=2;
@ -268,7 +268,7 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) {
isOpMuted[ch-1]=mute;
int ordch=orderedOps[ch-1];
DivInstrument* ins=parent->getIns(opChan[ch].ins);
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch]) {

View file

@ -41,7 +41,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
void* getChanState(int chan);
void reset();
void forceIns();
void tick();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);