Merge branch 'master' into ZSMv1

This commit is contained in:
ZeroByteOrg 2022-06-06 09:44:57 -05:00
commit 378f6a957b
3651 changed files with 495554 additions and 653 deletions

View file

@ -271,6 +271,9 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].useWave) {
chan[c.chan].ws.init(ins,chan[c.chan].audLen<<1,255,chan[c.chan].insChanged);
}
@ -424,6 +427,10 @@ bool DivPlatformAmiga::keyOffAffectsArp(int ch) {
return true;
}
DivMacroInt* DivPlatformAmiga::getChanMacroInt(int ch) {
return &chan[ch].std;
}
void DivPlatformAmiga::notifyInsChange(int ins) {
for (int i=0; i<4; i++) {
if (chan[i].ins==ins) {

View file

@ -99,6 +99,7 @@ class DivPlatformAmiga: public DivDispatch {
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
DivMacroInt* getChanMacroInt(int ch);
void setFlags(unsigned int flags);
void notifyInsChange(int ins);
void notifyWaveChange(int wave);

View file

@ -284,12 +284,12 @@ void DivPlatformArcade::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -378,7 +378,7 @@ void DivPlatformArcade::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -432,7 +432,7 @@ void DivPlatformArcade::tick(bool sysTick) {
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -528,7 +528,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
DivInstrumentFM::Operator op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -585,7 +585,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -676,7 +676,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.tl=c.value2;
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -876,7 +876,7 @@ void DivPlatformArcade::forceIns() {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -913,6 +913,10 @@ void* DivPlatformArcade::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformArcade::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -116,6 +116,7 @@ class DivPlatformArcade: public DivDispatch {
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
DivMacroInt* getChanMacroInt(int ch);
void notifyInsChange(int ins);
void setFlags(unsigned int flags);
bool isStereo();

View file

@ -315,6 +315,9 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
} else if (intellivision && (chan[c.chan].psgMode&4)) {
@ -506,6 +509,10 @@ void* DivPlatformAY8910::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformAY8910::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -102,6 +102,7 @@ class DivPlatformAY8910: public DivDispatch {
void setFlags(unsigned int flags);
bool isStereo();
bool keyOffAffectsArp(int ch);
DivMacroInt* getChanMacroInt(int ch);
bool getDCOffRequired();
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);

View file

@ -346,6 +346,9 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (isMuted[c.chan]) {
rWrite(0x08+c.chan,0);
} else {
@ -536,6 +539,10 @@ void* DivPlatformAY8930::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformAY8930::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformAY8930::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -98,6 +98,7 @@ class DivPlatformAY8930: public DivDispatch {
void setFlags(unsigned int flags);
bool isStereo();
bool keyOffAffectsArp(int ch);
DivMacroInt* getChanMacroInt(int ch);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);

View file

@ -169,6 +169,9 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -278,6 +281,10 @@ void* DivPlatformBubSysWSG::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformBubSysWSG::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformBubSysWSG::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -78,6 +78,7 @@ class DivPlatformBubSysWSG: public DivDispatch {
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
DivMacroInt* getChanMacroInt(int ch);
void setFlags(unsigned int flags);
void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins);

View file

@ -491,6 +491,10 @@ void* DivPlatformC64::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformC64::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformC64::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -97,6 +97,7 @@ class DivPlatformC64: public DivDispatch {
void setFlags(unsigned int flags);
void notifyInsChange(int ins);
bool getDCOffRequired();
DivMacroInt* getChanMacroInt(int ch);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);

View file

@ -139,7 +139,7 @@ void DivPlatformFDS::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(32,chan[i].std.vol.val)-(32-MIN(32,chan[i].vol));
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol,chan[i].std.vol.val,32);
if (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x4080,0x80|chan[i].outVol);
}
@ -285,6 +285,9 @@ int DivPlatformFDS::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
ws.changeWave1(chan[c.chan].wave);
@ -433,6 +436,10 @@ void* DivPlatformFDS::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformFDS::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformFDS::getOscBuffer(int ch) {
return oscBuf;
}

View file

@ -88,6 +88,7 @@ class DivPlatformFDS: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -433,6 +433,10 @@ void* DivPlatformGB::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -72,6 +72,7 @@ class DivPlatformGB: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -24,10 +24,13 @@
#include "genesisshared.h"
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
static unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
#define CHIP_DIVIDER 72
#define CHIP_FREQBASE 9440540
const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
@ -144,10 +147,13 @@ void DivPlatformGenesis::processDAC() {
DivSample* s=parent->getSample(chan[i].dacSample);
if (!isMuted[i] && s->samples>0) {
if (parent->song.noOPN2Vol) {
sample+=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
} else {
sample+=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
chan[i].dacOutput=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
}
sample+=chan[i].dacOutput;
} else {
chan[i].dacOutput=0;
}
chan[i].dacPeriod+=chan[i].dacRate;
if (chan[i].dacPeriod>=(chipClock/576)) {
@ -249,7 +255,20 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
//OPN2_Write(&fm,0,0);
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
if (i==5) {
if (fm.dacen) {
if (softPCM) {
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7;
}
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
}
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
}
}
os[0]=(os[0]<<5);
@ -293,7 +312,20 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
//OPN2_Write(&fm,0,0);
for (int i=0; i<6; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
if (i==5) {
if (fm_ymfm->debug_dac_enable()) {
if (softPCM) {
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7;
}
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
}
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
}
}
if (os[0]<-32768) os[0]=-32768;
@ -321,7 +353,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -329,7 +361,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -355,7 +387,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
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));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.pitch.had) {
@ -384,7 +416,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -397,11 +429,11 @@ void DivPlatformGenesis::tick(bool sysTick) {
}
if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -437,7 +469,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -495,8 +527,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
}
}
for (int i=0; i<8; i++) {
for (int i=0; i<7; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
@ -545,27 +576,45 @@ void DivPlatformGenesis::tick(bool sysTick) {
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (ch>5) return;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[ch].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
if (ch>6) return;
if (ch<6) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
if (isOutput[chan[ch].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
} else {
ch--;
}
rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
}
int DivPlatformGenesis::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
if (c.chan==7 && extMode && softPCM) { // CSM
chan[c.chan].macroInit(ins);
chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].portaPause=false;
chan[c.chan].note=c.value;
chan[c.chan].freqChanged=true;
}
chan[c.chan].keyOn=true;
chan[c.chan].active=true;
break;
}
if (c.chan>=5) {
if (ins->type==DIV_INS_AMIGA) {
chan[c.chan].dacMode=1;
@ -634,7 +683,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -653,7 +702,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
if (chan[c.chan].insChanged) {
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
}
chan[c.chan].insChanged=false;
@ -668,7 +717,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_OFF:
if (c.chan>=5) {
if (c.chan>=5 && c.chan<7) {
chan[c.chan].dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
if (parent->song.brokenDACMode) {
@ -706,7 +755,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -731,7 +780,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} else {
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
}
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
break;
}
case DIV_CMD_PITCH: {
@ -763,6 +812,29 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
break;
}
if (c.chan==7) {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
}
chan[c.chan].freqChanged=true;
if (return2) {
chan[c.chan].inPorta=false;
return 2;
}
break;
}
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
bool return2=false;
@ -809,7 +881,9 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break;
}
case DIV_CMD_LEGATO: {
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
if (c.chan==7) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
} else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
} else {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
@ -847,7 +921,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1038,7 +1112,7 @@ void DivPlatformGenesis::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1051,7 +1125,7 @@ void DivPlatformGenesis::forceIns() {
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
if (chan[i].active) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
@ -1071,6 +1145,10 @@ void* DivPlatformGenesis::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformGenesis::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -51,6 +51,7 @@ class DivPlatformGenesis: public DivDispatch {
bool dacReady;
bool dacDirection;
unsigned char sampleBank;
signed char dacOutput;
void macroInit(DivInstrument* which) {
std.init(which);
pitch2=0;
@ -85,7 +86,8 @@ class DivPlatformGenesis: public DivDispatch {
dacDelay(0),
dacReady(true),
dacDirection(false),
sampleBank(0) {}
sampleBank(0),
dacOutput(0) {}
};
Channel chan[10];
DivDispatchOscBuffer* oscBuf[10];
@ -128,6 +130,7 @@ class DivPlatformGenesis: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -23,6 +23,7 @@
#include "genesisshared.h"
#define CHIP_DIVIDER 72
#define CHIP_FREQBASE 9440540
int DivPlatformGenesisExt::dispatch(DivCommand c) {
@ -54,7 +55,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
@ -92,7 +93,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
break;
}
@ -179,6 +180,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
rWrite(0x22,lfoValue);
break;
}
case DIV_CMD_FM_FB: {
chan[2].state.fb=c.value&7;
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
break;
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
@ -193,7 +199,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[chan[2].state.alg][c.value]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -376,8 +382,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
rWrite(baseAddr+0x40,127);
immWrite(baseAddr+0x40,127);
} else if (isOutput[chan[2].state.alg][ordch]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
immWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
immWrite(baseAddr+0x40,op.tl);
@ -441,9 +447,43 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
opChan[i].keyOn=false;
}
}
if (extMode && softPCM) {
if (chan[7].freqChanged) {
chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER);
if (chan[7].freq<1) chan[7].freq=1;
if (chan[7].freq>1024) chan[7].freq=1024;
int wf=0x400-chan[7].freq;
immWrite(0x24,wf>>2);
immWrite(0x25,wf&3);
chan[7].freqChanged=false;
}
if (chan[7].keyOff || chan[7].keyOn) {
writeNoteOn=true;
for (int i=0; i<4; i++) {
writeMask|=opChan[i].active<<(4+i);
}
}
}
if (writeNoteOn) {
if (chan[7].active) { // CSM
writeMask^=0xf0;
}
immWrite(0x28,writeMask);
}
if (extMode && softPCM) {
if (chan[7].keyOn) {
immWrite(0x27,0x81);
chan[7].keyOn=false;
}
if (chan[7].keyOff) {
immWrite(0x27,0x40);
chan[7].keyOff=false;
}
}
}
void DivPlatformGenesisExt::forceIns() {
@ -455,7 +495,7 @@ void DivPlatformGenesisExt::forceIns() {
if (isOpMuted[j]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -464,7 +504,7 @@ void DivPlatformGenesisExt::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -503,6 +543,12 @@ void* DivPlatformGenesisExt::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) {
if (ch>=6) return &chan[ch-3].std;
if (ch>=2) return NULL; // currently not implemented
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];

View file

@ -55,6 +55,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
public:
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -297,6 +297,9 @@ 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].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
}
case DIV_CMD_NOTE_OFF:
@ -421,6 +424,10 @@ void* DivPlatformLynx::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformLynx::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -88,6 +88,7 @@ class DivPlatformLynx: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -107,7 +107,7 @@ void DivPlatformMMC5::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
if (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
}
@ -241,6 +241,9 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
break;
case DIV_CMD_NOTE_OFF:
@ -350,6 +353,10 @@ void* DivPlatformMMC5::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformMMC5::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformMMC5::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -31,50 +31,73 @@ const char** DivPlatformMSM6258::getRegisterSheet() {
}
const char* DivPlatformMSM6258::getEffectName(unsigned char effect) {
switch (effect) {
case 0x20:
return "20xx: Set frequency divider (0-2)";
break;
case 0x21:
return "21xx: Select clock rate (0: full; 1: half)";
break;
}
return NULL;
}
void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t len) {
short* outs[2]={
&msmOut,
NULL
};
for (size_t h=start; h<start+len; h++) {
short* outs[2]={
&bufL[h],
NULL
};
if (!writes.empty()) {
QueuedWrite& w=writes.front();
switch (w.addr) {
case 0:
msm->ctrl_w(w.val);
break;
}
writes.pop();
}
if (sample>=0 && sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(sample);
unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4);
if (msm->data_w(nextData)) {
samplePos++;
if (samplePos>=(int)s->lengthVOX) {
sample=-1;
samplePos=0;
msm->ctrl_w(1);
if (--msmClockCount<0) {
if (--msmDividerCount<=0) {
if (!writes.empty()) {
QueuedWrite& w=writes.front();
switch (w.addr) {
case 0:
msm->ctrl_w(w.val);
break;
case 2:
msmPan=w.val;
break;
case 8:
msmClock=w.val;
break;
case 12:
msmDivider=4-(w.val&3);
if (msmDivider<2) msmDivider=2;
break;
}
writes.pop();
}
if (sample>=0 && sample<parent->song.sampleLen) {
DivSample* s=parent->getSample(sample);
unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4);
if (msm->data_w(nextData)) {
samplePos++;
if (samplePos>=(int)s->lengthVOX) {
sample=-1;
samplePos=0;
msm->ctrl_w(1);
}
}
}
msm->sound_stream_update(outs,1);
msmDividerCount=msmDivider;
}
msmClockCount=msmClock;
}
msm->sound_stream_update(outs,1);
if (isMuted[0]) {
bufL[h]=0;
bufR[h]=0;
oscBuf[0]->data[oscBuf[0]->needle++]=0;
} else {
bufL[h]=(msmPan&2)?msmOut:0;
bufR[h]=(msmPan&1)?msmOut:0;
oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?msmOut:0;
}
/*if (++updateOsc>=22) {
updateOsc=0;
// TODO: per-channel osc
for (int i=0; i<1; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=msm->m_voice[i].m_muted?0:(msm->m_voice[i].m_out<<6);
}
}*/
}
}
@ -176,6 +199,23 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_SAMPLE_FREQ:
rateSel=c.value&3;
rWrite(12,rateSel);
break;
case DIV_CMD_SAMPLE_MODE:
clockSel=c.value&1;
rWrite(8,clockSel);
break;
case DIV_CMD_PANNING: {
if (c.value==0 && c.value2==0) {
chan[c.chan].pan=3;
} else {
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
}
rWrite(2,chan[c.chan].pan);
break;
}
case DIV_CMD_LEGATO: {
break;
}
@ -205,12 +245,19 @@ void DivPlatformMSM6258::forceIns() {
for (int i=0; i<1; i++) {
chan[i].insChanged=true;
}
rWrite(12,rateSel);
rWrite(8,clockSel);
rWrite(2,chan[0].pan);
}
void* DivPlatformMSM6258::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) {
return oscBuf[ch];
}
@ -234,6 +281,14 @@ void DivPlatformMSM6258::poke(std::vector<DivRegWrite>& wlist) {
void DivPlatformMSM6258::reset() {
while (!writes.empty()) writes.pop();
msm->device_reset();
msmClock=chipClock;
msmDivider=2;
msmDividerCount=0;
msmClock=0;
msmClockCount=0;
msmPan=3;
rateSel=2;
clockSel=0;
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -253,6 +308,10 @@ void DivPlatformMSM6258::reset() {
delay=0;
}
bool DivPlatformMSM6258::isStereo() {
return true;
}
bool DivPlatformMSM6258::keyOffAffectsArp(int ch) {
return false;
}
@ -307,15 +366,23 @@ void DivPlatformMSM6258::renderSamples() {
}
void DivPlatformMSM6258::setFlags(unsigned int flags) {
if (flags&1) {
chipClock=4096000;
} else {
chipClock=4000000;
switch (flags) {
case 3:
chipClock=8192000;
break;
case 2:
chipClock=8000000;
break;
case 1:
chipClock=4096000;
break;
default:
chipClock=4000000;
break;
}
rate=chipClock/256;
rate=chipClock/128;
for (int i=0; i<1; i++) {
isMuted[i]=false;
oscBuf[i]->rate=rate/256;
oscBuf[i]->rate=rate;
}
}

View file

@ -87,7 +87,9 @@ class DivPlatformMSM6258: public DivDispatch {
unsigned char* adpcmMem;
size_t adpcmMemLen;
unsigned char sampleBank;
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
signed char msmDividerCount, msmClockCount;
short msmOut;
int delay, updateOsc, sample, samplePos;
@ -102,6 +104,7 @@ class DivPlatformMSM6258: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
@ -109,6 +112,7 @@ class DivPlatformMSM6258: public DivDispatch {
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);

View file

@ -23,13 +23,18 @@
#include <string.h>
#include <math.h>
#define rWrite(v) if (!skipRegisterWrites) {writes.emplace(0,v); if (dumpWrites) {addWrite(0,v);} }
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
const char** DivPlatformMSM6295::getRegisterSheet() {
return NULL;
}
const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
switch (effect) {
case 0x20:
return "20xx: Set chip output rate (0: clock/132; 1: clock/165)";
break;
}
return NULL;
}
@ -42,7 +47,28 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
if (delay<=0) {
if (!writes.empty()) {
QueuedWrite& w=writes.front();
msm->command_w(w.val);
switch (w.addr) {
case 0: // command
msm->command_w(w.val);
break;
case 8: // chip clock select (VGM)
case 9:
case 10:
case 11:
break;
case 12: // rate select
msm->ss_w(!w.val);
break;
case 14: // enable bankswitch
break;
case 15: // set bank base
break;
case 16: // switch bank
case 17:
case 18:
case 19:
break;
}
writes.pop();
delay=32;
}
@ -92,9 +118,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
rWrite((8<<c.chan)); // turn off
rWrite(0x80|chan[c.chan].sample); // set phrase
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
rWrite(0,(8<<c.chan)); // turn off
rWrite(0,0x80|chan[c.chan].sample); // set phrase
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
} else {
break;
}
@ -107,9 +133,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
}
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
chan[c.chan].sample=12*sampleBank+c.value%12;
rWrite((8<<c.chan)); // turn off
rWrite(0x80|chan[c.chan].sample); // set phrase
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
rWrite(0,(8<<c.chan)); // turn off
rWrite(0,0x80|chan[c.chan].sample); // set phrase
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
}
break;
}
@ -117,14 +143,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
rWrite((8<<c.chan)); // turn off
rWrite(0,(8<<c.chan)); // turn off
chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
rWrite((8<<c.chan)); // turn off
rWrite(0,(8<<c.chan)); // turn off
chan[c.chan].std.release();
break;
case DIV_CMD_ENV_RELEASE:
@ -153,6 +179,10 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
case DIV_CMD_NOTE_PORTA: {
return 2;
}
case DIV_CMD_SAMPLE_FREQ:
rateSel=c.value;
rWrite(12,!rateSel);
break;
case DIV_CMD_SAMPLE_BANK:
sampleBank=c.value;
if (sampleBank>(parent->song.sample.size()/12)) {
@ -190,12 +220,17 @@ void DivPlatformMSM6295::forceIns() {
for (int i=0; i<4; i++) {
chan[i].insChanged=true;
}
rWrite(12,!rateSel);
}
void* DivPlatformMSM6295::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformMSM6295::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformMSM6295::getOscBuffer(int ch) {
return oscBuf[ch];
}
@ -219,6 +254,7 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
void DivPlatformMSM6295::reset() {
while (!writes.empty()) writes.pop();
msm->reset();
msm->ss_w(false);
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -232,6 +268,7 @@ void DivPlatformMSM6295::reset() {
}
sampleBank=0;
rateSel=false;
delay=0;
}
@ -240,6 +277,10 @@ bool DivPlatformMSM6295::keyOffAffectsArp(int ch) {
return false;
}
float DivPlatformMSM6295::getPostAmp() {
return 3.0f;
}
void DivPlatformMSM6295::notifyInsChange(int ins) {
for (int i=0; i<4; i++) {
if (chan[i].ins==ins) {
@ -302,14 +343,52 @@ void DivPlatformMSM6295::renderSamples() {
}
void DivPlatformMSM6295::setFlags(unsigned int flags) {
if (flags&1) {
chipClock=8448000;
} else {
chipClock=8000000;
switch (flags) {
case 0:
chipClock=4000000/4;
break;
case 1:
chipClock=4224000/4;
break;
case 2:
chipClock=4000000;
break;
case 3:
chipClock=4224000;
break;
case 4:
chipClock=COLOR_NTSC;
break;
case 5:
chipClock=COLOR_NTSC/2.0;
break;
case 6:
chipClock=COLOR_NTSC*2.0/7.0;
break;
case 7:
chipClock=COLOR_NTSC/4.0;
break;
case 8:
chipClock=4000000/2;
break;
case 9:
chipClock=4224000/2;
break;
case 10:
chipClock=875000;
break;
case 11:
chipClock=937500;
break;
case 12:
chipClock=1500000;
break;
default:
chipClock=4000000/4;
break;
}
rate=chipClock/((flags&2)?6:24);
rate=chipClock/3;
for (int i=0; i<4; i++) {
isMuted[i]=false;
oscBuf[i]->rate=rate/22;
}
}

View file

@ -101,6 +101,7 @@ class DivPlatformMSM6295: public DivDispatch {
int delay, updateOsc;
bool extMode;
bool rateSel;
short oldWrites[512];
short pendingWrites[512];
@ -111,6 +112,7 @@ class DivPlatformMSM6295: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
@ -119,6 +121,7 @@ class DivPlatformMSM6295: public DivDispatch {
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
float getPostAmp();
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);

View file

@ -625,6 +625,10 @@ void* DivPlatformN163::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformN163::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformN163::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -95,6 +95,7 @@ class DivPlatformN163: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -349,6 +349,9 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -464,6 +467,10 @@ void* DivPlatformNamcoWSG::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -79,6 +79,7 @@ class DivPlatformNamcoWSG: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -230,7 +230,7 @@ void DivPlatformNES::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
// ok, why are the volumes like that?
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
if (chan[i].outVol<0) chan[i].outVol=0;
if (i==2) { // triangle
rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255);
@ -446,6 +446,9 @@ int DivPlatformNES::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (c.chan==2) {
rWrite(0x4000+c.chan*4,0xff);
} else {
@ -607,6 +610,10 @@ void* DivPlatformNES::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformNES::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformNES::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -89,6 +89,7 @@ class DivPlatformNES: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -342,7 +342,7 @@ void DivPlatformOPL::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(63,chan[i].std.vol.val),63);
for (int j=0; j<ops; j++) {
unsigned char slot=slots[j][i];
if (slot==255) continue;
@ -353,7 +353,7 @@ void DivPlatformOPL::tick(bool sysTick) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -480,7 +480,7 @@ void DivPlatformOPL::tick(bool sysTick) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -689,7 +689,7 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[ch].state.alg][i] || ch>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[ch].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -784,10 +784,23 @@ int DivPlatformOPL::dispatch(DivCommand c) {
}
break;
}
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
DivInstrument* ins=parent->getIns(chan[c.chan].ins,c.chan>melodicChans?DIV_INS_OPL_DRUMS:DIV_INS_OPL);
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
for (int i=0; i<4; i++) {
chan[melodicChans+i+1].state.alg=ins->fm.alg;
chan[melodicChans+i+1].state.fb=ins->fm.fb;
chan[melodicChans+i+1].state.opllPreset=ins->fm.opllPreset;
chan[melodicChans+i+1].state.fixedDrums=ins->fm.fixedDrums;
chan[melodicChans+i+1].state.kickFreq=ins->fm.kickFreq;
chan[melodicChans+i+1].state.snareHatFreq=ins->fm.snareHatFreq;
chan[melodicChans+i+1].state.tomTopFreq=ins->fm.tomTopFreq;
chan[melodicChans+i+1].state.op[0]=ins->fm.op[i];
}
} else {
chan[c.chan].state=ins->fm;
}
}
chan[c.chan].macroInit(ins);
@ -795,49 +808,81 @@ int DivPlatformOPL::dispatch(DivCommand c) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].insChanged) {
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
chan[c.chan].fourOp=(ops==4);
if (chan[c.chan].fourOp) {
chan[c.chan+1].macroInit(NULL);
}
update4OpMask=true;
for (int i=0; i<ops; i++) {
unsigned char slot=slots[i][c.chan];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
for (int i=0; i<4; i++) {
int ch=melodicChans+1+i;
unsigned char slot=slots[0][ch];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[ch].state.op[0];
chan[ch].fourOp=false;
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6));
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
if (isMuted[ch]) {
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
} else {
oldWrites[chanMap[ch]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)|((chan[ch].pan&3)<<4));
}
}
} else {
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
chan[c.chan].fourOp=(ops==4);
if (chan[c.chan].fourOp) {
chan[c.chan+1].macroInit(NULL);
}
update4OpMask=true;
for (int i=0; i<ops; i++) {
unsigned char slot=slots[i][c.chan];
if (slot==255) continue;
unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
}
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
}
if (isMuted[c.chan]) {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
}
} else {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (isMuted[c.chan]) {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
}
} else {
oldWrites[chanMap[c.chan]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (ops==4) {
oldWrites[chanMap[c.chan+1]+ADDR_LR_FB_ALG]=-1;
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
}
}
}
}
@ -845,20 +890,32 @@ int DivPlatformOPL::dispatch(DivCommand c) {
chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
if (c.chan>=melodicChans && chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) { // drums
if (c.chan==melodicChans) {
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
if (c.chan>melodicChans && ins->type==DIV_INS_OPL_DRUMS && chan[c.chan].state.fixedDrums) {
chan[melodicChans+1].fixedFreq=(chan[melodicChans+1].state.snareHatFreq&1023)<<(chan[melodicChans+1].state.snareHatFreq>>10);
chan[melodicChans+2].fixedFreq=(chan[melodicChans+2].state.tomTopFreq&1023)<<(chan[melodicChans+2].state.tomTopFreq>>10);
chan[melodicChans+3].fixedFreq=chan[melodicChans+2].fixedFreq;
chan[melodicChans+4].fixedFreq=chan[melodicChans+1].fixedFreq;
chan[melodicChans+1].freqChanged=true;
chan[melodicChans+2].freqChanged=true;
chan[melodicChans+3].freqChanged=true;
chan[melodicChans+4].freqChanged=true;
} else {
if (c.chan>=melodicChans && (chan[c.chan].state.opllPreset==16 || ins->type==DIV_INS_OPL_DRUMS) && chan[c.chan].state.fixedDrums) { // drums
if (c.chan==melodicChans) {
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&1023)<<(chan[c.chan].state.kickFreq>>10);
} else if (c.chan==melodicChans+1 || c.chan==melodicChans+4) {
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&1023)<<(chan[c.chan].state.snareHatFreq>>10);
} else if (c.chan==melodicChans+2 || c.chan==melodicChans+3) {
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&1023)<<(chan[c.chan].state.tomTopFreq>>10);
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
} else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].fixedFreq=0;
}
chan[c.chan].note=c.value;
chan[c.chan].freqChanged=true;
@ -914,7 +971,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -1063,7 +1120,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -1293,7 +1350,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -1310,7 +1367,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -1384,7 +1441,7 @@ void DivPlatformOPL::forceIns() {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else {
if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) {
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6));
rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
}
@ -1426,6 +1483,10 @@ void* DivPlatformOPL::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
if (ch>=18) return NULL;
return oscBuf[ch];

View file

@ -125,6 +125,7 @@ class DivPlatformOPL: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -149,9 +149,9 @@ void DivPlatformOPLL::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(15,chan[i].std.vol.val),15);
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
}
}
@ -174,7 +174,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) {
chan[i].state.opllPreset=chan[i].std.wave.val;
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
}
}
@ -244,7 +244,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
op.tl=((j==1)?15:63)-m.tl.val;
if (j==1) {
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
}
} else {
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(op.tl&63));
@ -384,21 +384,6 @@ int DivPlatformOPLL::toFreq(int freq) {
void DivPlatformOPLL::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
/*
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[ch].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));*/
}
int DivPlatformOPLL::dispatch(DivCommand c) {
@ -483,7 +468,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
}
}
if (c.chan<9) {
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
}
}
}
@ -553,7 +538,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
break;
} else if (c.chan<6 || !drums) {
if (c.chan<9) {
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
}
}
break;
@ -647,7 +632,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
car.tl=c.value2&15;
if (c.chan<9) {
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
}
}
break;
@ -862,7 +847,7 @@ void DivPlatformOPLL::forceIns() {
rWrite(0x07,(car.sl<<4)|(car.rr));
}
if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
}
if (!(i>=6 && properDrums)) {
if (chan[i].active) {
@ -911,6 +896,10 @@ void* DivPlatformOPLL::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformOPLL::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) {
if (ch>=9) return NULL;
return oscBuf[ch];

View file

@ -102,6 +102,7 @@ class DivPlatformOPLL: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -154,7 +154,7 @@ void DivPlatformPCE::tick(bool sysTick) {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31);
if (chan[i].furnaceDac && chan[i].pcm) {
// ignore for now
} else {
@ -328,6 +328,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -474,6 +477,10 @@ void* DivPlatformPCE::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformPCE::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -89,6 +89,7 @@ class DivPlatformPCE: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -19,6 +19,7 @@
#include "pcspkr.h"
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#ifdef __linux__
@ -28,6 +29,8 @@
#include <unistd.h>
#include <linux/input.h>
#include <linux/kd.h>
#include <time.h>
#include <sys/io.h>
#endif
#define PCSPKR_DIVIDER 4
@ -38,6 +41,137 @@ const char* regCheatSheetPCSpeaker[]={
NULL
};
void _pcSpeakerThread(void* inst) {
((DivPlatformPCSpeaker*)inst)->pcSpeakerThread();
}
void DivPlatformPCSpeaker::pcSpeakerThread() {
std::unique_lock<std::mutex> unique(realOutSelfLock);
RealQueueVal r(0,0,0);
logD("starting PC speaker out thread");
while (!realOutQuit) {
realQueueLock.lock();
if (realQueue.empty()) {
realQueueLock.unlock();
realOutCond.wait(unique);
continue;
} else {
r=realQueue.front();
realQueue.pop();
}
realQueueLock.unlock();
#ifdef __linux__
static struct timespec ts, tSleep, rSleep;
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
logW("could not get time!");
tSleep.tv_sec=0;
tSleep.tv_nsec=0;
} else {
tSleep.tv_sec=r.tv_sec-ts.tv_sec;
tSleep.tv_nsec=r.tv_nsec-ts.tv_nsec;
if (tSleep.tv_nsec<0) {
tSleep.tv_sec--;
tSleep.tv_nsec+=1000000000;
}
}
if (tSleep.tv_nsec>0 || tSleep.tv_sec>0) {
nanosleep(&tSleep,&rSleep);
}
if (beepFD>=0) {
switch (realOutMethod) {
case 0: { // evdev
static struct input_event ie;
ie.time.tv_sec=r.tv_sec;
ie.time.tv_usec=r.tv_nsec/1000;
ie.type=EV_SND;
ie.code=SND_TONE;
if (r.val>0) {
ie.value=chipClock/r.val;
} else {
ie.value=0;
}
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
logW("error while writing frequency! %s",strerror(errno));
} else {
//logV("writing freq: %d",r.val);
}
break;
}
case 1: // KIOCSOUND (on tty)
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
logW("ioctl error! %s",strerror(errno));
}
break;
case 2: { // /dev/port
unsigned char bOut;
bOut=0;
if (r.val==0) {
lseek(beepFD,0x61,SEEK_SET);
if (read(beepFD,&bOut,1)<1) {
logW("read from 0x61: %s",strerror(errno));
}
bOut&=(~3);
lseek(beepFD,0x61,SEEK_SET);
if (write(beepFD,&bOut,1)<1) {
logW("write to 0x61: %s",strerror(errno));
}
} else {
lseek(beepFD,0x43,SEEK_SET);
bOut=0xb6;
if (write(beepFD,&bOut,1)<1) {
logW("write to 0x43: %s",strerror(errno));
}
lseek(beepFD,0x42,SEEK_SET);
bOut=r.val&0xff;
if (write(beepFD,&bOut,1)<1) {
logW("write to 0x42: %s",strerror(errno));
}
lseek(beepFD,0x42,SEEK_SET);
bOut=r.val>>8;
if (write(beepFD,&bOut,1)<1) {
logW("write to 0x42: %s",strerror(errno));
}
lseek(beepFD,0x61,SEEK_SET);
if (read(beepFD,&bOut,1)<1) {
logW("read from 0x61: %s",strerror(errno));
}
bOut|=3;
lseek(beepFD,0x61,SEEK_SET);
if (write(beepFD,&bOut,1)<1) {
logW("write to 0x61: %s",strerror(errno));
}
}
break;
}
case 3: // KIOCSOUND (on stdout)
if (ioctl(beepFD,KIOCSOUND,r.val)<0) {
logW("ioctl error! %s",strerror(errno));
}
break;
case 4: // outb()
if (r.val==0) {
outb(inb(0x61)&(~3),0x61);
realOutEnabled=false;
} else {
outb(0xb6,0x43);
outb(r.val&0xff,0x42);
outb(r.val>>8,0x42);
if (!realOutEnabled) {
outb(inb(0x61)|3,0x61);
realOutEnabled=true;
}
}
break;
}
} else {
//logV("not writing because fd is less than 0");
}
#endif
}
logD("stopping PC speaker out thread");
}
const char** DivPlatformPCSpeaker::getRegisterSheet() {
return regCheatSheetPCSpeaker;
}
@ -126,25 +260,28 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start,
}
}
void DivPlatformPCSpeaker::beepFreq(int freq) {
void DivPlatformPCSpeaker::beepFreq(int freq, int delay) {
realQueueLock.lock();
#ifdef __linux__
static struct input_event ie;
if (beepFD>=0) {
gettimeofday(&ie.time,NULL);
ie.type=EV_SND;
ie.code=SND_TONE;
if (freq>0) {
ie.value=chipClock/freq;
} else {
ie.value=0;
}
if (write(beepFD,&ie,sizeof(struct input_event))<0) {
perror("error while writing frequency!");
} else {
//printf("writing freq: %d\n",freq);
struct timespec ts;
double addition=1000000000.0*(double)delay/(double)rate;
addition+=1500000000.0*((double)parent->getAudioDescGot().bufsize/parent->getAudioDescGot().rate);
if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) {
ts.tv_sec=0;
ts.tv_nsec=0;
} else {
ts.tv_nsec+=addition;
while (ts.tv_nsec>=1000000000) {
ts.tv_sec++;
ts.tv_nsec-=1000000000;
}
}
realQueue.push(RealQueueVal(ts.tv_sec,ts.tv_nsec,freq));
#else
realQueue.push(RealQueueVal(0,0,freq));
#endif
realQueueLock.unlock();
realOutCond.notify_one();
}
void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start, size_t len) {
@ -152,7 +289,7 @@ void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start,
if (lastOn!=on || lastFreq!=freq) {
lastOn=on;
lastFreq=freq;
beepFreq((on && !isMuted[0])?freq:0);
beepFreq((on && !isMuted[0])?freq:0,start);
}
for (size_t i=start; i<start+len; i++) {
if (on) {
@ -251,6 +388,9 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -345,6 +485,10 @@ void* DivPlatformPCSpeaker::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformPCSpeaker::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformPCSpeaker::getOscBuffer(int ch) {
return oscBuf;
}
@ -382,18 +526,51 @@ void DivPlatformPCSpeaker::reset() {
low=0;
band=0;
if (speakerType==3) {
//if (speakerType==3) {
#ifdef __linux__
if (beepFD==-1) {
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
switch (realOutMethod) {
case 0: // evdev
beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY);
break;
case 1: // KIOCSOUND (on tty)
beepFD=open("/dev/tty1",O_WRONLY);
break;
case 2: // /dev/port
beepFD=open("/dev/port",O_WRONLY);
break;
case 3: // KIOCSOUND (on stdout)
beepFD=STDOUT_FILENO;
break;
case 4: // outb()
beepFD=-1;
if (ioperm(0x61,8,1)<0) {
logW("ioperm 0x61: %s",strerror(errno));
break;
}
if (ioperm(0x43,8,1)<0) {
logW("ioperm 0x43: %s",strerror(errno));
break;
}
if (ioperm(0x42,8,1)<0) {
logW("ioperm 0x42: %s",strerror(errno));
break;
}
beepFD=STDOUT_FILENO;
break;
}
if (beepFD<0) {
perror("error while opening PC speaker");
logW("error while opening PC speaker! %s",strerror(errno));
}
}
#endif
beepFreq(0);
} else {
/*} else {
beepFreq(0);
}*/
if (realOutThread==NULL) {
realOutThread=new std::thread(_pcSpeakerThread,this);
}
memset(regPool,0,2);
@ -433,6 +610,10 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned
dumpWrites=false;
skipRegisterWrites=false;
beepFD=-1;
realOutQuit=false;
realOutThread=NULL;
realOutMethod=parent->getConfInt("pcSpeakerOutMethod",0);
realOutEnabled=false;
for (int i=0; i<1; i++) {
isMuted[i]=false;
}
@ -447,8 +628,14 @@ void DivPlatformPCSpeaker::quit() {
if (speakerType==3) {
beepFreq(0);
}
if (realOutThread!=NULL) {
realOutQuit=true;
realOutCond.notify_one();
realOutThread->join();
delete realOutThread;
}
#ifdef __linux__
if (beepFD>=0) close(beepFD);
if (beepFD>=0 && realOutMethod<3) close(beepFD);
#endif
delete oscBuf;
}

View file

@ -22,6 +22,10 @@
#include "../dispatch.h"
#include "../macroInt.h"
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
class DivPlatformPCSpeaker: public DivDispatch {
struct Channel {
@ -57,9 +61,23 @@ class DivPlatformPCSpeaker: public DivDispatch {
};
Channel chan[1];
DivDispatchOscBuffer* oscBuf;
std::thread* realOutThread;
std::mutex realOutSelfLock;
std::condition_variable realOutCond;
bool realOutQuit;
struct RealQueueVal {
int tv_sec, tv_nsec;
unsigned short val;
RealQueueVal(int sec, int nsec, unsigned short v):
tv_sec(sec),
tv_nsec(nsec),
val(v) {}
};
std::queue<RealQueueVal> realQueue;
std::mutex realQueueLock;
bool isMuted[1];
bool on, flip, lastOn;
int pos, speakerType, beepFD;
bool on, flip, lastOn, realOutEnabled;
int pos, speakerType, beepFD, realOutMethod;
float low, band;
float low2, high2, band2;
float low3, band3;
@ -68,7 +86,7 @@ class DivPlatformPCSpeaker: public DivDispatch {
friend void putDispatchChan(void*,int,int);
void beepFreq(int freq);
void beepFreq(int freq, int delay=0);
void acquire_unfilt(short* bufL, short* bufR, size_t start, size_t len);
void acquire_cone(short* bufL, short* bufR, size_t start, size_t len);
@ -76,9 +94,11 @@ class DivPlatformPCSpeaker: public DivDispatch {
void acquire_real(short* bufL, short* bufR, size_t start, size_t len);
public:
void pcSpeakerThread();
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -149,6 +149,9 @@ int DivPlatformPET::dispatch(DivCommand c) {
chan.active=true;
chan.keyOn=true;
chan.macroInit(ins);
if (!parent->song.brokenOutVol && !chan.std.vol.will) {
chan.outVol=chan.vol;
}
break;
}
case DIV_CMD_NOTE_OFF:
@ -246,6 +249,10 @@ void* DivPlatformPET::getChanState(int ch) {
return &chan;
}
DivMacroInt* DivPlatformPET::getChanMacroInt(int ch) {
return &chan.std;
}
DivDispatchOscBuffer* DivPlatformPET::getOscBuffer(int ch) {
return oscBuf;
}

View file

@ -66,6 +66,7 @@ class DivPlatformPET: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -404,6 +404,9 @@ int DivPlatformQSound::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
}
case DIV_CMD_NOTE_OFF:
@ -527,6 +530,10 @@ void* DivPlatformQSound::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformQSound::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -78,6 +78,7 @@ class DivPlatformQSound: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -189,6 +189,9 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
}
case DIV_CMD_NOTE_OFF:
@ -297,6 +300,10 @@ void* DivPlatformRF5C68::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -75,6 +75,7 @@ class DivPlatformRF5C68: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -136,7 +136,7 @@ void DivPlatformSAA1099::tick(bool sysTick) {
for (int i=0; i<6; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(i,0);
@ -264,6 +264,9 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (isMuted[c.chan]) {
rWrite(c.chan,0);
} else {
@ -398,6 +401,10 @@ void* DivPlatformSAA1099::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -91,6 +91,7 @@ class DivPlatformSAA1099: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -184,6 +184,9 @@ int DivPlatformSCC::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (!isMuted[c.chan]) {
rWrite(regBase+15,regPool[regBase+15]|(1<<c.chan));
}
@ -307,6 +310,10 @@ void* DivPlatformSCC::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSCC::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSCC::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -70,6 +70,7 @@ class DivPlatformSCC: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -17,6 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// TODO: new macro formula
#include "segapcm.h"
#include "../engine.h"
#include <string.h>
@ -84,10 +85,17 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
for (int i=0; i<16; i++) {
chan[i].std.next();
// TODO: fix
/*if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
}*/
if (parent->song.newSegaPCM) {
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
if (dumpWrites) {
addWrite(0x10002+(i<<3),chan[i].chVolL);
addWrite(0x10003+(i<<3),chan[i].chVolR);
}
}
}
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
@ -106,14 +114,24 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
}
if (chan[i].std.panL.had) {
chan[i].chVolL=chan[i].std.panL.val&127;
if (parent->song.newSegaPCM) {
chan[i].chPanL=chan[i].std.panL.val&127;
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
} else {
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 (parent->song.newSegaPCM) {
chan[i].chPanR=chan[i].std.panR.val&127;
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
} else {
chan[i].chVolR=chan[i].std.panR.val&127;
}
if (dumpWrites) {
addWrite(0x10003+(i<<3),chan[i].chVolR);
}
@ -169,6 +187,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
addWrite(0x10086+(c.chan<<3),3);
}
chan[c.chan].macroInit(NULL);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
}
chan[c.chan].pcm.pos=0;
@ -257,8 +278,13 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
chan[c.chan].chVolL=c.value;
chan[c.chan].chVolR=c.value;
if (parent->song.newSegaPCM) {
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
} else {
chan[c.chan].chVolL=c.value;
chan[c.chan].chVolR=c.value;
}
if (dumpWrites) {
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
@ -276,8 +302,15 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].ins=c.value;
break;
case DIV_CMD_PANNING: {
chan[c.chan].chVolL=c.value>>1;
chan[c.chan].chVolR=c.value2>>1;
if (parent->song.newSegaPCM) {
chan[c.chan].chPanL=c.value>>1;
chan[c.chan].chPanR=c.value2>>1;
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127;
} else {
chan[c.chan].chVolL=c.value>>1;
chan[c.chan].chVolR=c.value2>>1;
}
if (dumpWrites) {
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
@ -367,6 +400,10 @@ void* DivPlatformSegaPCM::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSegaPCM::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -34,6 +34,7 @@ class DivPlatformSegaPCM: public DivDispatch {
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
int vol, outVol;
unsigned char chVolL, chVolR;
unsigned char chPanL, chPanR;
struct PCMChannel {
int sample;
@ -46,7 +47,29 @@ class DivPlatformSegaPCM: public DivDispatch {
std.init(which);
pitch2=0;
}
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
Channel():
freqH(0),
freqL(0),
freq(0),
baseFreq(0),
pitch(0),
pitch2(0),
note(0),
ins(-1),
active(false),
insChanged(true),
freqChanged(false),
keyOn(false),
keyOff(false),
inPorta(false),
portaPause(false),
furnacePCM(false),
vol(0),
outVol(0),
chVolL(127),
chVolR(127),
chPanL(127),
chPanR(127) {}
};
Channel chan[16];
DivDispatchOscBuffer* oscBuf[16];
@ -78,6 +101,7 @@ class DivPlatformSegaPCM: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -69,14 +69,13 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
if (o<-32768) o=-32768;
if (o>32767) o=32767;
bufL[h]=o;
/*
for (int i=0; i<4; i++) {
if (isMuted[i]) {
oscBuf[i]->data[oscBuf[i]->needle++]=0;
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i);
oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]];
}
}*/
}
}
}
@ -245,6 +244,9 @@ 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].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -316,6 +318,8 @@ int DivPlatformSMS::dispatch(DivCommand c) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
}
chan[c.chan].inPorta=c.value;
// TODO: pre porta cancel arp compat flag
//if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
break;
case DIV_CMD_GET_VOLMAX:
return 15;
@ -348,6 +352,10 @@ void* DivPlatformSMS::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -76,6 +76,7 @@ class DivPlatformSMS: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900
Konami K005289 emulation core
This chip is used at infamous Konami Bubble System, for part of Wavetable sound generator.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900
Konami K005289 emulation core
See k005289.cpp for more info.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Namco 163 Sound emulation core
This chip is one of NES mapper with sound expansion, This one is by Namco.
@ -99,7 +100,7 @@ void n163_core::tick()
m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8);
m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
const u8 prev_voice_cycle = m_voice_cycle;
const u8 prev_voice_cycle = m_voice_cycle;
// update voice cycle
bool flush = m_multiplex ? true : false;
@ -112,8 +113,8 @@ void n163_core::tick()
}
// output 4 bit waveform and volume, multiplexed
const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7;
m_ch_out[chan_index]=wave * volume;
const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7;
m_ch_out[chan_index]=wave * volume;
m_acc += m_ch_out[chan_index];
if (flush)
{
@ -127,12 +128,12 @@ void n163_core::reset()
// reset this chip
m_disable = false;
m_multiplex = true;
memset(m_ram,0,sizeof(m_ram));
memset(m_ram,0,sizeof(m_ram));
m_voice_cycle = 0x78;
m_addr_latch.reset();
m_out = 0;
m_acc = 0;
memset(m_ch_out,0,sizeof(m_ch_out));
memset(m_ch_out,0,sizeof(m_ch_out));
}
// accessor

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Namco 163 Sound emulation core
*/
@ -46,11 +47,11 @@ public:
// sound output pin
s16 out() { return m_out; }
// get channel output
s16 chan_out(u8 ch) { return m_ch_out[ch]; }
// get channel output
s16 chan_out(u8 ch) { return m_ch_out[ch]; }
// get voice cycle
u8 voice_cycle() { return m_voice_cycle; }
// get voice cycle
u8 voice_cycle() { return m_voice_cycle; }
// register pool
u8 reg(u8 addr) { return m_ram[addr & 0x7f]; }
@ -63,7 +64,7 @@ private:
addr_latch_t()
: addr(0)
, incr(0)
{ };
{ }
void reset()
{
@ -80,7 +81,7 @@ private:
u8 m_voice_cycle = 0x78; // Voice cycle for processing
addr_latch_t m_addr_latch; // address latch
s16 m_out = 0; // output
s16 m_ch_out[8] = {0}; // per channel output
s16 m_ch_out[8] = {0}; // per channel output
// demultiplex related
bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate!
s16 m_acc = 0; // accumulated output

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: tildearrow
OKI MSM6295 emulation core
It is 4 channel ADPCM playback chip from OKI semiconductor.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: tildearrow
OKI MSM6295 emulation core
See msm6295.cpp for more info.
@ -71,7 +72,7 @@ public:
msm6295_core &m_host;
u16 m_clock = 0; // clock counter
bool m_busy = false; // busy status
bool m_muted = false; // muted
bool m_muted = false; // muted
u8 m_command = 0; // current command
u32 m_addr = 0; // current address
s8 m_nibble = 0; // current nibble

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holders: cam900
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: tildearrow
Various core utilities for vgsound_emu
*/

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: tildearrow
Dialogic ADPCM core
*/

View file

@ -1,8 +1,10 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst
Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw
Konami SCC emulation core
Konami SCC means "Sound Creative Chip", it's actually MSX MegaROM/RAM Mapper with 5 channel Wavetable sound generator.
@ -373,12 +375,12 @@ void scc_core::reset()
m_test.reset();
m_out = 0;
memset(m_reg,0,sizeof(m_reg));
memset(m_reg,0,sizeof(m_reg));
}
void scc_core::voice_t::reset()
{
memset(wave,0,sizeof(wave));
memset(wave,0,sizeof(wave));
enable = false;
pitch = 0;
volume = 0;

View file

@ -1,8 +1,10 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Contributor(s): Natt Akuma, James Alan Nguyen, Laurens Holst
Modifiers and Contributors for Furnace: Natt Akuma, tildearrow, Grauw
Konami SCC emulation core
See scc.cpp for more info.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Konami VRC VI sound emulation core
It's one of NES mapper with built-in sound chip, and also one of 2 Konami VRCs with this feature. (rest one has OPLL derivatives.)

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Konami VRC VI sound emulation core
See vrcvi.cpp to more infos.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holders: cam900
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Seta/Allumer X1-010 Emulation core
the chip has 16 voices, all voices can be switchable to Wavetable or PCM sample playback mode.

View file

@ -1,8 +1,9 @@
/*
License: BSD-3-Clause
see https://github.com/cam900/vgsound_emu/LICENSE for more details
see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details
Copyright holders: cam900
Copyright holder(s): cam900
Modifiers and Contributors for Furnace: cam900, tildearrow
Seta/Allumer X1-010 Emulation core
See x1_010.cpp for more info.
@ -63,7 +64,7 @@ public:
// getters
s32 output(u8 channel) { return m_out[channel & 1]; }
s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; }
s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; }
// internal state
void reset();

View file

@ -778,6 +778,10 @@ public:
// get the engine
fm_engine* debug_engine() { return &m_fm; }
// get DAC state
uint16_t debug_dac_data() { return m_dac_data; }
uint8_t debug_dac_enable() { return m_dac_enable; }
protected:
// simulate the DAC discontinuity
constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); }

View file

@ -264,6 +264,9 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chWrite(c.chan,0x02,chan[c.chan].vol);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
chan[c.chan].insChanged=false;
break;
}
@ -481,6 +484,10 @@ void* DivPlatformSoundUnit::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -112,6 +112,7 @@ class DivPlatformSoundUnit: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -313,6 +313,9 @@ int DivPlatformSwan::dispatch(DivCommand c) {
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -461,6 +464,10 @@ void* DivPlatformSwan::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -79,6 +79,7 @@ class DivPlatformSwan: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -88,7 +88,7 @@ void DivPlatformTIA::tick(bool sysTick) {
for (int i=0; i<2; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
if (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) {
rWrite(0x19+i,0);
@ -170,6 +170,9 @@ int DivPlatformTIA::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
rWrite(0x15+c.chan,chan[c.chan].shape);
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (isMuted[c.chan]) {
rWrite(0x19+c.chan,0);
} else {
@ -290,6 +293,10 @@ void* DivPlatformTIA::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformTIA::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformTIA::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -52,6 +52,7 @@ class DivPlatformTIA: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -270,7 +270,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -278,7 +278,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -354,7 +354,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -407,7 +407,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -499,7 +499,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[ch].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -529,7 +529,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -594,7 +594,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -694,7 +694,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -985,7 +985,7 @@ void DivPlatformTX81Z::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1027,6 +1027,10 @@ void* DivPlatformTX81Z::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformTX81Z::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformTX81Z::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -103,6 +103,7 @@ class DivPlatformTX81Z: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -285,6 +285,9 @@ int DivPlatformVERA::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
@ -396,6 +399,10 @@ void* DivPlatformVERA::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -66,6 +66,7 @@ class DivPlatformVERA: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -278,6 +278,10 @@ void* DivPlatformVIC20::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformVIC20::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformVIC20::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -68,6 +68,7 @@ class DivPlatformVIC20: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -264,6 +264,9 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
//chan[c.chan].keyOn=true;
chan[c.chan].furnaceDac=true;
} else {
@ -435,6 +438,10 @@ void* DivPlatformVRC6::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformVRC6::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformVRC6::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -85,6 +85,7 @@ class DivPlatformVRC6: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -609,6 +609,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
chan[c.chan].keyOn=true;
chan[c.chan].envChanged=true;
chan[c.chan].macroInit(ins);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
if (chan[c.chan].wave<0) {
chan[c.chan].wave=0;
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
@ -839,6 +842,10 @@ void* DivPlatformX1_010::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -129,6 +129,7 @@ class DivPlatformX1_010: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -338,7 +338,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
@ -346,7 +346,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -396,7 +396,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -441,7 +441,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -553,7 +553,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -612,7 +612,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -690,7 +690,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -882,7 +882,7 @@ void DivPlatformYM2203::muteChannel(int ch, bool mute) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[ch].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -899,7 +899,7 @@ void DivPlatformYM2203::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -933,6 +933,11 @@ void* DivPlatformYM2203::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) {
if (ch>=3) return ay->getChanMacroInt(ch-3);
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -108,6 +108,7 @@ class DivPlatformYM2203: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -45,7 +45,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
@ -84,7 +84,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
break;
}
@ -155,6 +155,11 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
rWrite(0x22,(c.value&7)|((c.value>>4)<<3));
break;
}
case DIV_CMD_FM_FB: {
chan[2].state.fb=c.value&7;
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
break;
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
@ -411,7 +416,7 @@ void DivPlatformYM2203Ext::muteChannel(int ch, bool mute) {
if (isOpMuted[ch-2]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[ins->fm.alg][ordch]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -426,7 +431,7 @@ void DivPlatformYM2203Ext::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -466,6 +471,12 @@ void* DivPlatformYM2203Ext::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) {
if (ch>=6) return ay->getChanMacroInt(ch-6);
if (ch>=2) return NULL; // currently not implemented
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];

View file

@ -40,6 +40,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 {
public:
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -500,12 +500,12 @@ void DivPlatformYM2608::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -559,7 +559,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -609,7 +609,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -836,7 +836,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -916,7 +916,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1020,7 +1020,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.tl=c.value2;
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1223,7 +1223,7 @@ void DivPlatformYM2608::forceIns() {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1257,6 +1257,11 @@ void* DivPlatformYM2608::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) {
if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6);
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2608::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -121,6 +121,7 @@ class DivPlatformYM2608: public DivDispatch {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -45,7 +45,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
@ -84,7 +84,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
break;
}
@ -155,6 +155,11 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
rWrite(0x22,(c.value&7)|((c.value>>4)<<3));
break;
}
case DIV_CMD_FM_FB: {
chan[2].state.fb=c.value&7;
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
break;
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
@ -411,7 +416,7 @@ void DivPlatformYM2608Ext::muteChannel(int ch, bool mute) {
if (isOpMuted[ch-2]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[ins->fm.alg][ordch]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -426,7 +431,7 @@ void DivPlatformYM2608Ext::forceIns() {
if (isOpMuted[j]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -435,7 +440,7 @@ void DivPlatformYM2608Ext::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -479,6 +484,13 @@ void* DivPlatformYM2608Ext::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) {
if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9);
if (ch>=6) return &chan[ch-3].std;
if (ch>=2) return NULL; // currently not implemented
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2608Ext::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];

View file

@ -40,6 +40,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 {
public:
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -544,12 +544,12 @@ void DivPlatformYM2610::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -603,7 +603,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -653,7 +653,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -883,7 +883,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -963,7 +963,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1067,7 +1067,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.tl=c.value2;
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1270,7 +1270,7 @@ void DivPlatformYM2610::forceIns() {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1304,6 +1304,11 @@ void* DivPlatformYM2610::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) {
if (ch>=4 && ch<7) return ay->getChanMacroInt(ch-4);
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2610::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -134,6 +134,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -523,12 +523,12 @@ void DivPlatformYM2610B::tick(bool sysTick) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127);
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -582,7 +582,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -632,7 +632,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
if (m.tl.had) {
op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -861,7 +861,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
@ -941,7 +941,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isOutput[chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1045,7 +1045,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.tl=c.value2;
if (isOutput[chan[c.chan].state.alg][c.value]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1248,7 +1248,7 @@ void DivPlatformYM2610B::forceIns() {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -1282,6 +1282,11 @@ void* DivPlatformYM2610B::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2610B::getChanMacroInt(int ch) {
if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6);
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2610B::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -107,6 +107,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -45,7 +45,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
@ -84,7 +84,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
}
break;
}
@ -155,6 +155,11 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
rWrite(0x22,(c.value&7)|((c.value>>4)<<3));
break;
}
case DIV_CMD_FM_FB: {
chan[2].state.fb=c.value&7;
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
break;
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
@ -411,7 +416,7 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
if (isOpMuted[ch-2]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[ins->fm.alg][ordch]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -426,7 +431,7 @@ void DivPlatformYM2610BExt::forceIns() {
if (isOpMuted[j]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127));
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
@ -435,7 +440,7 @@ void DivPlatformYM2610BExt::forceIns() {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
@ -479,6 +484,13 @@ void* DivPlatformYM2610BExt::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) {
if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9);
if (ch>=6) return &chan[ch-3].std;
if (ch>=2) return NULL; // currently not implemented
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];

Some files were not shown because too many files have changed in this diff Show more