mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-16 17:45:10 +00:00
add Y8950 system
This commit is contained in:
parent
4a563a416e
commit
7218710268
6 changed files with 225 additions and 15 deletions
|
@ -273,6 +273,14 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
||||||
dispatch=new DivPlatformOPL;
|
dispatch=new DivPlatformOPL;
|
||||||
((DivPlatformOPL*)dispatch)->setOPLType(3,true);
|
((DivPlatformOPL*)dispatch)->setOPLType(3,true);
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_Y8950:
|
||||||
|
dispatch=new DivPlatformOPL;
|
||||||
|
((DivPlatformOPL*)dispatch)->setOPLType(8950,false);
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_Y8950_DRUMS:
|
||||||
|
dispatch=new DivPlatformOPL;
|
||||||
|
((DivPlatformOPL*)dispatch)->setOPLType(8950,true);
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_OPZ:
|
case DIV_SYSTEM_OPZ:
|
||||||
dispatch=new DivPlatformTX81Z;
|
dispatch=new DivPlatformTX81Z;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -286,7 +286,8 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
||||||
adpcmB->output<2>(aOut,0);
|
adpcmB->output<2>(aOut,0);
|
||||||
|
|
||||||
os[0]+=aOut.data[0];
|
os[0]+=aOut.data[0];
|
||||||
os[1]+=aOut.data[1];
|
os[1]+=aOut.data[0];
|
||||||
|
oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]+=aOut.data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
|
@ -322,6 +323,15 @@ void DivPlatformOPL::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DivPlatformOPL::NOTE_ADPCMB(int note) {
|
||||||
|
if (adpcmChan<0) return 0;
|
||||||
|
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||||
|
double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0;
|
||||||
|
return parent->calcBaseFreq((double)chipClock/144,off,note,false);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::tick(bool sysTick) {
|
void DivPlatformOPL::tick(bool sysTick) {
|
||||||
for (int i=0; i<totalChans; i++) {
|
for (int i=0; i<totalChans; i++) {
|
||||||
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
||||||
|
@ -531,6 +541,45 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ADPCM
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
if (chan[adpcmChan].furnacePCM) {
|
||||||
|
chan[adpcmChan].std.next();
|
||||||
|
|
||||||
|
if (chan[adpcmChan].std.vol.had) {
|
||||||
|
chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(64,chan[adpcmChan].std.vol.val))/64;
|
||||||
|
immWrite(18,chan[adpcmChan].outVol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[adpcmChan].std.arp.had) {
|
||||||
|
if (!chan[adpcmChan].inPorta) {
|
||||||
|
if (chan[adpcmChan].std.arp.mode) {
|
||||||
|
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].std.arp.val);
|
||||||
|
} else {
|
||||||
|
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note+(signed char)chan[adpcmChan].std.arp.val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan[adpcmChan].freqChanged=true;
|
||||||
|
} else {
|
||||||
|
if (chan[adpcmChan].std.arp.mode && chan[adpcmChan].std.arp.finished) {
|
||||||
|
chan[adpcmChan].baseFreq=NOTE_ADPCMB(chan[adpcmChan].note);
|
||||||
|
chan[adpcmChan].freqChanged=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[adpcmChan].freqChanged) {
|
||||||
|
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||||
|
double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0;
|
||||||
|
chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off);
|
||||||
|
} else {
|
||||||
|
chan[adpcmChan].freq=0;
|
||||||
|
}
|
||||||
|
immWrite(16,chan[adpcmChan].freq&0xff);
|
||||||
|
immWrite(17,(chan[adpcmChan].freq>>8)&0xff);
|
||||||
|
chan[adpcmChan].freqChanged=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<512; i++) {
|
for (int i=0; i<512; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
immWrite(i,pendingWrites[i]&0xff);
|
immWrite(i,pendingWrites[i]&0xff);
|
||||||
|
@ -655,13 +704,77 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::dispatch(DivCommand c) {
|
int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (c.chan>=totalChans) return 0;
|
if (c.chan>=totalChans && c.chan!=adpcmChan) return 0;
|
||||||
// ineffective in 4-op mode
|
// ineffective in 4-op mode
|
||||||
if (oplType==3 && c.chan<14 && (c.chan&1) && c.cmd!=DIV_CMD_GET_VOLMAX && c.cmd!=DIV_ALWAYS_SET_VOLUME) {
|
if (oplType==3 && c.chan!=adpcmChan && c.chan<14 && (c.chan&1) && c.cmd!=DIV_CMD_GET_VOLMAX && c.cmd!=DIV_ALWAYS_SET_VOLUME) {
|
||||||
if (chan[c.chan-1].fourOp) return 0;
|
if (chan[c.chan-1].fourOp) return 0;
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
|
if (c.chan==adpcmChan) { // ADPCM
|
||||||
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
|
if (ins->type==DIV_INS_AMIGA) {
|
||||||
|
chan[c.chan].furnacePCM=true;
|
||||||
|
} else {
|
||||||
|
chan[c.chan].furnacePCM=false;
|
||||||
|
}
|
||||||
|
if (skipRegisterWrites) break;
|
||||||
|
if (chan[c.chan].furnacePCM) {
|
||||||
|
chan[c.chan].macroInit(ins);
|
||||||
|
if (!chan[c.chan].std.vol.will) {
|
||||||
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
|
immWrite(18,chan[c.chan].outVol);
|
||||||
|
}
|
||||||
|
chan[c.chan].sample=ins->amiga.initSample;
|
||||||
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
|
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||||
|
immWrite(9,(s->offB>>2)&0xff);
|
||||||
|
immWrite(10,(s->offB>>10)&0xff);
|
||||||
|
int end=s->offB+s->lengthB-1;
|
||||||
|
immWrite(11,(end>>2)&0xff);
|
||||||
|
immWrite(12,(end>>10)&0xff);
|
||||||
|
immWrite(8,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
|
||||||
|
immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat
|
||||||
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
chan[c.chan].note=c.value;
|
||||||
|
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||||
|
chan[c.chan].freqChanged=true;
|
||||||
|
}
|
||||||
|
chan[c.chan].active=true;
|
||||||
|
chan[c.chan].keyOn=true;
|
||||||
|
} else {
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
|
immWrite(9,0);
|
||||||
|
immWrite(10,0);
|
||||||
|
immWrite(11,0);
|
||||||
|
immWrite(12,0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[c.chan].sample=-1;
|
||||||
|
chan[c.chan].macroInit(NULL);
|
||||||
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
|
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
|
immWrite(9,0);
|
||||||
|
immWrite(10,0);
|
||||||
|
immWrite(11,0);
|
||||||
|
immWrite(12,0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
|
immWrite(9,(s->offB>>2)&0xff);
|
||||||
|
immWrite(10,(s->offB>>10)&0xff);
|
||||||
|
int end=s->offB+s->lengthB-1;
|
||||||
|
immWrite(11,(end>>2)&0xff);
|
||||||
|
immWrite(12,(end>>10)&0xff);
|
||||||
|
immWrite(8,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
|
immWrite(7,(s->loopStart>=0)?0x90:0x80); // start/repeat
|
||||||
|
chan[c.chan].baseFreq=(((unsigned int)s->rate)<<16)/(chipClock/144);
|
||||||
|
chan[c.chan].freqChanged=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL);
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
if (chan[c.chan].insChanged) {
|
||||||
|
@ -744,11 +857,19 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
case DIV_CMD_NOTE_OFF:
|
||||||
|
if (c.chan==adpcmChan) {
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
|
break;
|
||||||
|
}
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
|
if (c.chan==adpcmChan) {
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
|
break;
|
||||||
|
}
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
|
@ -758,7 +879,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
chan[c.chan].std.release();
|
chan[c.chan].std.release();
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_VOLUME: {
|
case DIV_CMD_VOLUME: {
|
||||||
if (pretendYMU) {
|
if (pretendYMU && c.chan!=adpcmChan) {
|
||||||
c.value=pow(((double)c.value/127.0),0.5)*63.0;
|
c.value=pow(((double)c.value/127.0),0.5)*63.0;
|
||||||
if (c.value<0) c.value=0;
|
if (c.value<0) c.value=0;
|
||||||
if (c.value>63) c.value=63;
|
if (c.value>63) c.value=63;
|
||||||
|
@ -767,6 +888,10 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
|
if (c.chan==adpcmChan) { // ADPCM-B
|
||||||
|
immWrite(18,chan[c.chan].outVol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
unsigned char slot=slots[i][c.chan];
|
unsigned char slot=slots[i][c.chan];
|
||||||
|
@ -787,7 +912,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_GET_VOLUME: {
|
case DIV_CMD_GET_VOLUME: {
|
||||||
if (pretendYMU) {
|
if (pretendYMU && c.chan!=adpcmChan) {
|
||||||
return pow(((double)chan[c.chan].vol/63.0),2.0)*127.0;
|
return pow(((double)chan[c.chan].vol/63.0),2.0)*127.0;
|
||||||
}
|
}
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
|
@ -801,6 +926,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PANNING: {
|
case DIV_CMD_PANNING: {
|
||||||
if (oplType!=3) break;
|
if (oplType!=3) break;
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
if (c.value==0 && c.value2==0) {
|
if (c.value==0 && c.value2==0) {
|
||||||
chan[c.chan].pan=3;
|
chan[c.chan].pan=3;
|
||||||
} else {
|
} else {
|
||||||
|
@ -826,7 +952,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
int destFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value2)):(NOTE_FREQUENCY(c.value2));
|
||||||
int newFreq;
|
int newFreq;
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
|
@ -857,13 +983,22 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DIV_CMD_SAMPLE_BANK:
|
||||||
|
if (adpcmChan<0) break;
|
||||||
|
sampleBank=c.value;
|
||||||
|
if (sampleBank>(int)(parent->song.sample.size()/12)) {
|
||||||
|
sampleBank=parent->song.sample.size()/12;
|
||||||
|
}
|
||||||
|
iface.sampleBank=sampleBank;
|
||||||
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_LFO: {
|
case DIV_CMD_FM_LFO: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
if (c.value&2) {
|
if (c.value&2) {
|
||||||
dvb=c.value&1;
|
dvb=c.value&1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -873,6 +1008,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
chan[c.chan].state.fb=c.value&7;
|
chan[c.chan].state.fb=c.value&7;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
|
@ -889,6 +1025,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: {
|
case DIV_CMD_FM_MULT: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value>=ops) break;
|
if (c.value>=ops) break;
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||||
|
@ -900,6 +1037,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: {
|
case DIV_CMD_FM_TL: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value>=ops) break;
|
if (c.value>=ops) break;
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||||
|
@ -919,6 +1057,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -941,6 +1080,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_DR: {
|
case DIV_CMD_FM_DR: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -963,6 +1103,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SL: {
|
case DIV_CMD_FM_SL: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -985,6 +1126,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RR: {
|
case DIV_CMD_FM_RR: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -1007,6 +1149,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AM: {
|
case DIV_CMD_FM_AM: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -1029,6 +1172,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_VIB: {
|
case DIV_CMD_FM_VIB: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -1051,6 +1195,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SUS: {
|
case DIV_CMD_FM_SUS: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -1073,6 +1218,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_KSR: {
|
case DIV_CMD_FM_KSR: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<ops; i++) {
|
for (int i=0; i<ops; i++) {
|
||||||
|
@ -1095,6 +1241,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_WS: {
|
case DIV_CMD_FM_WS: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
if (oplType<2) break;
|
if (oplType<2) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1118,6 +1265,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RS: {
|
case DIV_CMD_FM_RS: {
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
if (oplType<2) break;
|
if (oplType<2) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1173,12 +1321,14 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_HARD_RESET:
|
case DIV_CMD_FM_HARD_RESET:
|
||||||
|
if (c.chan==adpcmChan) break;
|
||||||
chan[c.chan].hardReset=c.value;
|
chan[c.chan].hardReset=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_ALWAYS_SET_VOLUME:
|
case DIV_ALWAYS_SET_VOLUME:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
|
if (c.chan==adpcmChan) return 255;
|
||||||
if (pretendYMU) return 127;
|
if (pretendYMU) return 127;
|
||||||
return 63;
|
return 63;
|
||||||
break;
|
break;
|
||||||
|
@ -1267,7 +1417,7 @@ unsigned char* DivPlatformOPL::getRegisterPool() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::getRegisterPoolSize() {
|
int DivPlatformOPL::getRegisterPoolSize() {
|
||||||
return 512;
|
return (oplType<3)?256:512;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::reset() {
|
void DivPlatformOPL::reset() {
|
||||||
|
@ -1303,6 +1453,21 @@ void DivPlatformOPL::reset() {
|
||||||
chan[i].outVol=0x3f;
|
chan[i].outVol=0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (adpcmChan>=0) {
|
||||||
|
chan[adpcmChan]=DivPlatformOPL::Channel();
|
||||||
|
chan[adpcmChan].std.setEngine(parent);
|
||||||
|
chan[adpcmChan].vol=0xff;
|
||||||
|
chan[adpcmChan].outVol=0xff;
|
||||||
|
|
||||||
|
adpcmB->reset();
|
||||||
|
|
||||||
|
// volume
|
||||||
|
immWrite(18,0xff);
|
||||||
|
// ADPCM limit
|
||||||
|
immWrite(20,0xff);
|
||||||
|
immWrite(19,0xff);
|
||||||
|
}
|
||||||
|
|
||||||
if (oplType<3) for (int i=0; i<melodicChans; i++) {
|
if (oplType<3) for (int i=0; i<melodicChans; i++) {
|
||||||
fm.channel[outChanMap[i]].muted=isMuted[i];
|
fm.channel[outChanMap[i]].muted=isMuted[i];
|
||||||
}
|
}
|
||||||
|
@ -1315,6 +1480,7 @@ void DivPlatformOPL::reset() {
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
lfoValue=8;
|
lfoValue=8;
|
||||||
drumState=0;
|
drumState=0;
|
||||||
|
sampleBank=0;
|
||||||
|
|
||||||
drumVol[0]=0;
|
drumVol[0]=0;
|
||||||
drumVol[1]=0;
|
drumVol[1]=0;
|
||||||
|
@ -1469,7 +1635,7 @@ const void* DivPlatformOPL::getSampleMem(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
||||||
return (index==0 && adpcmChan>=0) ? 2097152 : 0;
|
return (index==0 && adpcmChan>=0) ? 262144 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
||||||
|
|
|
@ -40,8 +40,8 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
DivInstrumentFM state;
|
DivInstrumentFM state;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
unsigned char freqH, freqL;
|
unsigned char freqH, freqL;
|
||||||
int freq, baseFreq, pitch, pitch2, note, ins;
|
int freq, baseFreq, pitch, pitch2, note, ins, sample;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, fourOp, hardReset;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnacePCM, inPorta, fourOp, hardReset;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
|
@ -57,13 +57,14 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
pitch2(0),
|
pitch2(0),
|
||||||
note(0),
|
note(0),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
|
sample(-1),
|
||||||
active(false),
|
active(false),
|
||||||
insChanged(true),
|
insChanged(true),
|
||||||
freqChanged(false),
|
freqChanged(false),
|
||||||
keyOn(false),
|
keyOn(false),
|
||||||
keyOff(false),
|
keyOff(false),
|
||||||
portaPause(false),
|
portaPause(false),
|
||||||
furnaceDac(false),
|
furnacePCM(false),
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
fourOp(false),
|
fourOp(false),
|
||||||
hardReset(false),
|
hardReset(false),
|
||||||
|
@ -94,7 +95,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
const unsigned short* chanMap;
|
const unsigned short* chanMap;
|
||||||
const unsigned char* outChanMap;
|
const unsigned char* outChanMap;
|
||||||
double chipFreqBase;
|
double chipFreqBase;
|
||||||
int delay, oplType, chans, melodicChans, totalChans, adpcmChan;
|
int delay, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank;
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
unsigned char drumState;
|
unsigned char drumState;
|
||||||
unsigned char drumVol[5];
|
unsigned char drumVol[5];
|
||||||
|
@ -112,6 +113,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
|
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
double NOTE_ADPCMB(int note);
|
||||||
|
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
|
|
@ -1736,7 +1736,10 @@ void DivEngine::registerSystems() {
|
||||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"},
|
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"},
|
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"},
|
||||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM},
|
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM},
|
||||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA},
|
||||||
|
{},
|
||||||
|
oplEffectHandler,
|
||||||
|
fmOPLPostEffectHandler
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef(
|
||||||
|
@ -1744,7 +1747,10 @@ void DivEngine::registerSystems() {
|
||||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"},
|
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"},
|
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"},
|
||||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA},
|
||||||
|
{},
|
||||||
|
oplEffectHandler,
|
||||||
|
fmOPLPostEffectHandler
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_SCC_PLUS]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_SCC_PLUS]=new DivSysDef(
|
||||||
|
|
|
@ -841,6 +841,8 @@ const int availableSystems[]={
|
||||||
DIV_SYSTEM_VRC7,
|
DIV_SYSTEM_VRC7,
|
||||||
DIV_SYSTEM_OPL,
|
DIV_SYSTEM_OPL,
|
||||||
DIV_SYSTEM_OPL_DRUMS,
|
DIV_SYSTEM_OPL_DRUMS,
|
||||||
|
DIV_SYSTEM_Y8950,
|
||||||
|
DIV_SYSTEM_Y8950_DRUMS,
|
||||||
DIV_SYSTEM_OPL2,
|
DIV_SYSTEM_OPL2,
|
||||||
DIV_SYSTEM_OPL2_DRUMS,
|
DIV_SYSTEM_OPL2_DRUMS,
|
||||||
DIV_SYSTEM_OPL3,
|
DIV_SYSTEM_OPL3,
|
||||||
|
|
|
@ -106,6 +106,18 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha Y8950", {
|
||||||
|
DIV_SYSTEM_Y8950, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha Y8950 (drums mode)", {
|
||||||
|
DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
cat.systems.push_back(FurnaceGUISysDef(
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
"Yamaha YM3812", {
|
"Yamaha YM3812", {
|
||||||
DIV_SYSTEM_OPL2, 64, 0, 0,
|
DIV_SYSTEM_OPL2, 64, 0, 0,
|
||||||
|
@ -411,6 +423,20 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"MSX + MSX-AUDIO", {
|
||||||
|
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||||
|
DIV_SYSTEM_Y8950, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"MSX + MSX-AUDIO (drums mode)", {
|
||||||
|
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||||
|
DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
cat.systems.push_back(FurnaceGUISysDef(
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
"MSX + MSX-MUSIC", {
|
"MSX + MSX-MUSIC", {
|
||||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||||
|
|
Loading…
Reference in a new issue