mirror of
https://github.com/tildearrow/furnace.git
synced 2025-01-03 14:11:11 +00:00
compound system flattening, part 1
as of now compound systems (Genesis and Arcade) are translated to separate chips. this improves audio quality and makes things easier. it also allows you to change the volume of each chip on a Genesis. also adds SegaPCM system with 16 channels!
This commit is contained in:
parent
a7ecb4ecdb
commit
e4b9a6d1d9
13 changed files with 641 additions and 286 deletions
|
@ -310,6 +310,7 @@ src/engine/platform/ay8930.cpp
|
|||
src/engine/platform/tia.cpp
|
||||
src/engine/platform/saa.cpp
|
||||
src/engine/platform/amiga.cpp
|
||||
src/engine/platform/segapcm.cpp
|
||||
src/engine/platform/qsound.cpp
|
||||
src/engine/platform/dummy.cpp
|
||||
src/engine/platform/lynx.cpp
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "platform/tia.h"
|
||||
#include "platform/saa.h"
|
||||
#include "platform/amiga.h"
|
||||
#include "platform/segapcm.h"
|
||||
#include "platform/qsound.h"
|
||||
#include "platform/dummy.h"
|
||||
#include "platform/lynx.h"
|
||||
|
@ -140,12 +141,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
bbInLen=32768;
|
||||
|
||||
switch (sys) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_YM2612:
|
||||
dispatch=new DivPlatformGenesis;
|
||||
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
break;
|
||||
case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
dispatch=new DivPlatformGenesisExt;
|
||||
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
break;
|
||||
|
@ -169,7 +169,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
dispatch=new DivPlatformC64;
|
||||
((DivPlatformC64*)dispatch)->setChipModel(false);
|
||||
break;
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2151:
|
||||
dispatch=new DivPlatformArcade;
|
||||
((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0);
|
||||
|
@ -207,6 +206,10 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_QSOUND:
|
||||
dispatch=new DivPlatformQSound;
|
||||
break;
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
dispatch=new DivPlatformSegaPCM;
|
||||
break;
|
||||
default:
|
||||
logW("this system is not supported yet! using dummy platform.\n");
|
||||
dispatch=new DivPlatformDummy;
|
||||
|
|
|
@ -1023,11 +1023,11 @@ int DivEngine::getEffectiveSampleRate(int rate) {
|
|||
switch (song.system[0]) {
|
||||
case DIV_SYSTEM_YMU759:
|
||||
return 8000;
|
||||
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612_EXT:
|
||||
return 1278409/(1280000/rate);
|
||||
case DIV_SYSTEM_PCE:
|
||||
return 1789773/(1789773/rate);
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return (31250*MIN(255,(rate*255/31250)))/255;
|
||||
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL: case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
return 18518;
|
||||
|
|
|
@ -649,7 +649,24 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// handle special systems
|
||||
// handle compound systems
|
||||
if (ds.system[0]==DIV_SYSTEM_GENESIS) {
|
||||
ds.systemLen=2;
|
||||
ds.system[0]=DIV_SYSTEM_YM2612;
|
||||
ds.system[1]=DIV_SYSTEM_SMS;
|
||||
ds.systemVol[1]=24;
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_GENESIS_EXT) {
|
||||
ds.systemLen=2;
|
||||
ds.system[0]=DIV_SYSTEM_YM2612_EXT;
|
||||
ds.system[1]=DIV_SYSTEM_SMS;
|
||||
ds.systemVol[1]=24;
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_ARCADE) {
|
||||
ds.systemLen=2;
|
||||
ds.system[0]=DIV_SYSTEM_YM2151;
|
||||
ds.system[1]=DIV_SYSTEM_SEGAPCM_COMPAT;
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) {
|
||||
ds.systemLen=2;
|
||||
ds.system[0]=DIV_SYSTEM_SMS;
|
||||
|
@ -789,6 +806,42 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.systemFlags[i]=reader.readI();
|
||||
}
|
||||
|
||||
// handle compound systems
|
||||
for (int i=0; i<32; i++) {
|
||||
if (ds.system[i]==DIV_SYSTEM_GENESIS ||
|
||||
ds.system[i]==DIV_SYSTEM_GENESIS_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_ARCADE) {
|
||||
for (int j=31; j>i; j--) {
|
||||
ds.system[j]=ds.system[j-1];
|
||||
ds.systemVol[j]=ds.systemVol[j-1];
|
||||
ds.systemPan[j]=ds.systemPan[j-1];
|
||||
}
|
||||
if (++ds.systemLen>32) ds.systemLen=32;
|
||||
|
||||
if (ds.system[i]==DIV_SYSTEM_GENESIS) {
|
||||
ds.system[i]=DIV_SYSTEM_YM2612;
|
||||
if (i<31) {
|
||||
ds.system[i+1]=DIV_SYSTEM_SMS;
|
||||
ds.systemVol[i+1]=(((ds.systemVol[i]&127)*3)>>3)|(ds.systemVol[i]&128);
|
||||
}
|
||||
}
|
||||
if (ds.system[i]==DIV_SYSTEM_GENESIS_EXT) {
|
||||
ds.system[i]=DIV_SYSTEM_YM2612_EXT;
|
||||
if (i<31) {
|
||||
ds.system[i+1]=DIV_SYSTEM_SMS;
|
||||
ds.systemVol[i+1]=(((ds.systemVol[i]&127)*3)>>3)|(ds.systemVol[i]&128);
|
||||
}
|
||||
}
|
||||
if (ds.system[i]==DIV_SYSTEM_ARCADE) {
|
||||
ds.system[i]=DIV_SYSTEM_YM2151;
|
||||
if (i<31) {
|
||||
ds.system[i+1]=DIV_SYSTEM_SEGAPCM_COMPAT;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
ds.name=reader.readString();
|
||||
ds.author=reader.readString();
|
||||
logI("%s by %s\n",ds.name.c_str(),ds.author.c_str());
|
||||
|
|
|
@ -130,9 +130,6 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) {
|
|||
case 0x1f:
|
||||
return "1Fxx: Set PM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x20:
|
||||
return "20xx: Set PCM frequency";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -159,43 +156,6 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si
|
|||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,o,NULL,NULL,NULL);
|
||||
|
||||
pcmCycles+=31250;
|
||||
if (pcmCycles>=rate) {
|
||||
pcmCycles-=rate;
|
||||
|
||||
// do a PCM cycle
|
||||
pcmL=0; pcmR=0;
|
||||
for (int i=8; i<13; i++) {
|
||||
if (chan[i].pcm.sample>=0) {
|
||||
DivSample* s=parent->song.sample[chan[i].pcm.sample];
|
||||
if (s->rendLength<=0) {
|
||||
chan[i].pcm.sample=-1;
|
||||
continue;
|
||||
}
|
||||
if (!isMuted[i]) {
|
||||
if (s->depth==8) {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL);
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
||||
} else {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL)>>8;
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR)>>8;
|
||||
}
|
||||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (chan[i].pcm.pos>=(s->rendLength<<8)) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->rendLength) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
o[0]+=pcmL;
|
||||
o[1]+=pcmR;
|
||||
|
||||
if (o[0]<-32768) o[0]=-32768;
|
||||
if (o[0]>32767) o[0]=32767;
|
||||
|
||||
|
@ -225,45 +185,11 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz
|
|||
|
||||
fm_ymfm->generate(&out_ymfm);
|
||||
|
||||
pcmCycles+=31250;
|
||||
if (pcmCycles>=rate) {
|
||||
pcmCycles-=rate;
|
||||
|
||||
// do a PCM cycle
|
||||
pcmL=0; pcmR=0;
|
||||
for (int i=8; i<13; i++) {
|
||||
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->song.sample[chan[i].pcm.sample];
|
||||
if (s->rendLength<=0) {
|
||||
chan[i].pcm.sample=-1;
|
||||
continue;
|
||||
}
|
||||
if (!isMuted[i]) {
|
||||
if (s->depth==8) {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL);
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
||||
} else {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL)>>8;
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR)>>8;
|
||||
}
|
||||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (chan[i].pcm.pos>=(s->rendLength<<8)) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->rendLength) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os[0]=out_ymfm.data[0]+pcmL;
|
||||
os[0]=out_ymfm.data[0];
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=out_ymfm.data[1]+pcmR;
|
||||
os[1]=out_ymfm.data[1];
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
@ -464,106 +390,21 @@ void DivPlatformArcade::tick() {
|
|||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=8; i<13; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64;
|
||||
if (chan[i].furnacePCM) {
|
||||
double off=1.0;
|
||||
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->song.sample[chan[i].pcm.sample];
|
||||
off=(double)s->centerRate/8363.0;
|
||||
}
|
||||
chan[i].pcm.freq=MIN(255,((off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250);
|
||||
if (dumpWrites && i>=8) {
|
||||
addWrite(0x10007+((i-8)<<3),chan[i].pcm.freq);
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformArcade::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch<8) {
|
||||
if (isMuted[ch]) {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
|
||||
} else {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)|((chan[ch].chVolL&1)<<6)|((chan[ch].chVolR&1)<<7));
|
||||
}
|
||||
if (isMuted[ch]) {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
|
||||
} else {
|
||||
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)|((chan[ch].chVolL&1)<<6)|((chan[ch].chVolR&1)<<7));
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformArcade::dispatch(DivCommand c) {
|
||||
int pcmChan=c.chan-8;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (c.chan>7) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].pcm.sample=ins->amiga.initSample;
|
||||
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(pcmChan<<3),3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
chan[c.chan].baseFreq=(c.value<<6);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].furnacePCM=true;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->song.sample[chan[c.chan].pcm.sample];
|
||||
addWrite(0x10086+(pcmChan<<3),3+((s->rendOffP>>16)<<3));
|
||||
addWrite(0x10084+(pcmChan<<3),(s->rendOffP)&0xff);
|
||||
addWrite(0x10085+(pcmChan<<3),(s->rendOffP>>8)&0xff);
|
||||
addWrite(0x10006+(pcmChan<<3),MIN(255,((s->rendOffP&0xffff)+s->rendLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=(int)s->rendLength) {
|
||||
addWrite(0x10086+(pcmChan<<3),2+((s->rendOffP>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->rendOffP&0xffff)+s->loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(pcmChan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(pcmChan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(pcmChan<<3),((s->rendOffP>>16)<<3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].pcm.sample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(pcmChan<<3),3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
chan[c.chan].pcm.freq=MIN(255,(parent->song.sample[chan[c.chan].pcm.sample]->rate*255)/31250);
|
||||
chan[c.chan].furnacePCM=false;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->song.sample[chan[c.chan].pcm.sample];
|
||||
addWrite(0x10086+(pcmChan<<3),3+((s->rendOffP>>16)<<3));
|
||||
addWrite(0x10084+(pcmChan<<3),(s->rendOffP)&0xff);
|
||||
addWrite(0x10085+(pcmChan<<3),(s->rendOffP>>8)&0xff);
|
||||
addWrite(0x10006+(pcmChan<<3),MIN(255,((s->rendOffP&0xffff)+s->rendLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=(int)s->rendLength) {
|
||||
addWrite(0x10086+(pcmChan<<3),2+((s->rendOffP>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->rendOffP&0xffff)+s->loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(pcmChan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(pcmChan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(pcmChan<<3),((s->rendOffP>>16)<<3));
|
||||
}
|
||||
addWrite(0x10007+(pcmChan<<3),chan[c.chan].pcm.freq);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
@ -614,12 +455,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>7) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(pcmChan<<3),3);
|
||||
}
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
|
@ -638,15 +473,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.hasVol) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>7) {
|
||||
chan[c.chan].chVolL=c.value;
|
||||
chan[c.chan].chVolR=c.value;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(pcmChan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(pcmChan<<3),chan[c.chan].chVolR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -669,22 +495,12 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
// TODO
|
||||
if (c.chan>7) {
|
||||
chan[c.chan].chVolL=(c.value>>4)|(((c.value>>4)>>1)<<4);
|
||||
chan[c.chan].chVolR=(c.value&15)|(((c.value&15)>>1)<<4);
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(pcmChan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(pcmChan<<3),chan[c.chan].chVolR);
|
||||
}
|
||||
chan[c.chan].chVolL=((c.value>>4)==1);
|
||||
chan[c.chan].chVolR=((c.value&15)==1);
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
} else {
|
||||
chan[c.chan].chVolL=((c.value>>4)==1);
|
||||
chan[c.chan].chVolR=((c.value&15)==1);
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
} else {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)|((chan[c.chan].chVolL&1)<<6)|((chan[c.chan].chVolR&1)<<7));
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)|((chan[c.chan].chVolL&1)<<6)|((chan[c.chan].chVolR&1)<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -724,17 +540,14 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_LFO: {
|
||||
if (c.chan>7) break;
|
||||
rWrite(0x18,c.value);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_LFO_WAVE: {
|
||||
if (c.chan>7) break;
|
||||
rWrite(0x1b,c.value&3);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>7) break;
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
|
@ -744,7 +557,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>7) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.mult=c.value2&15;
|
||||
|
@ -752,7 +564,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>7) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
|
@ -764,7 +575,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>7) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -803,12 +613,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -820,12 +624,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PRE_NOTE:
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
chan[c.chan].pcm.freq=c.value;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10007+(pcmChan<<3),chan[c.chan].pcm.freq);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//printf("WARNING: unimplemented command %d\n",c.cmd);
|
||||
break;
|
||||
|
@ -860,9 +658,6 @@ void DivPlatformArcade::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=8; i<13; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
immWrite(0x19,amDepth);
|
||||
immWrite(0x19,0x80|pmDepth);
|
||||
}
|
||||
|
@ -907,7 +702,7 @@ void DivPlatformArcade::reset() {
|
|||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
for (int i=0; i<13; i++) {
|
||||
for (int i=0; i<8; i++) {
|
||||
chan[i]=DivPlatformArcade::Channel();
|
||||
chan[i].vol=0x7f;
|
||||
chan[i].outVol=0x7f;
|
||||
|
@ -922,7 +717,6 @@ void DivPlatformArcade::reset() {
|
|||
pcmCycles=0;
|
||||
pcmL=0;
|
||||
pcmR=0;
|
||||
sampleBank=0;
|
||||
delay=0;
|
||||
amDepth=0x7f;
|
||||
pmDepth=0x7f;
|
||||
|
@ -931,13 +725,6 @@ void DivPlatformArcade::reset() {
|
|||
immWrite(0x19,amDepth);
|
||||
immWrite(0x19,0x80|pmDepth);
|
||||
//rWrite(0x1b,0x00);
|
||||
if (dumpWrites) {
|
||||
for (int i=0; i<5; i++) {
|
||||
addWrite(0x10086+(i<<3),3);
|
||||
addWrite(0x10002+(i<<3),0x7f);
|
||||
addWrite(0x10003+(i<<3),0x7f);
|
||||
}
|
||||
}
|
||||
|
||||
extMode=false;
|
||||
}
|
||||
|
@ -972,14 +759,14 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<13; i++) {
|
||||
for (int i=0; i<8; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
setFlags(flags);
|
||||
if (useYMFM) fm_ymfm=new ymfm::ym2151(iface);
|
||||
reset();
|
||||
|
||||
return 13;
|
||||
return 8;
|
||||
}
|
||||
|
||||
void DivPlatformArcade::quit() {
|
||||
|
|
|
@ -42,17 +42,9 @@ class DivPlatformArcade: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
|
||||
int vol, outVol;
|
||||
unsigned char chVolL, chVolR;
|
||||
|
||||
struct PCMChannel {
|
||||
int sample;
|
||||
unsigned int pos; // <<8
|
||||
unsigned short len;
|
||||
unsigned char freq;
|
||||
PCMChannel(): sample(-1), pos(0), len(0), freq(0) {}
|
||||
} pcm;
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(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 chan[13];
|
||||
Channel chan[8];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
|
@ -63,7 +55,6 @@ class DivPlatformArcade: public DivDispatch {
|
|||
opm_t fm;
|
||||
int delay, baseFreqOff;
|
||||
int pcmL, pcmR, pcmCycles;
|
||||
unsigned char sampleBank;
|
||||
unsigned char lastBusy;
|
||||
unsigned char amDepth, pmDepth;
|
||||
|
||||
|
@ -75,7 +66,7 @@ class DivPlatformArcade: public DivDispatch {
|
|||
|
||||
bool extMode, useYMFM;
|
||||
|
||||
bool isMuted[13];
|
||||
bool isMuted[8];
|
||||
|
||||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
|
406
src/engine/platform/segapcm.cpp
Normal file
406
src/engine/platform/segapcm.cpp
Normal file
|
@ -0,0 +1,406 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "segapcm.h"
|
||||
#include "../engine.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
|
||||
//#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
const char* DivPlatformSegaPCM::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set PCM frequency";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
os[0]=0; os[1]=0;
|
||||
// do a PCM cycle
|
||||
pcmL=0; pcmR=0;
|
||||
for (int i=0; i<16; i++) {
|
||||
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->song.sample[chan[i].pcm.sample];
|
||||
if (s->rendLength<=0) {
|
||||
chan[i].pcm.sample=-1;
|
||||
continue;
|
||||
}
|
||||
if (!isMuted[i]) {
|
||||
if (s->depth==8) {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL);
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
||||
} else {
|
||||
pcmL+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolL)>>8;
|
||||
pcmR+=(s->rendData[chan[i].pcm.pos>>8]*chan[i].chVolR)>>8;
|
||||
}
|
||||
}
|
||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||
if (chan[i].pcm.pos>=(s->rendLength<<8)) {
|
||||
if (s->loopStart>=0 && s->loopStart<=(int)s->rendLength) {
|
||||
chan[i].pcm.pos=s->loopStart<<8;
|
||||
} else {
|
||||
chan[i].pcm.sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os[0]=pcmL;
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=pcmR;
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
bufL[h]=os[0];
|
||||
bufR[h]=os[1];
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::tick() {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.hadVol) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
|
||||
}
|
||||
|
||||
if (chan[i].std.hadArp) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arpMode) {
|
||||
chan[i].baseFreq=(chan[i].std.arp<<6)+baseFreqOff;
|
||||
} else {
|
||||
chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp)<<6)+baseFreqOff;
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
|
||||
chan[i].baseFreq=(chan[i].note<<6)+baseFreqOff;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
/*if (chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].keyOff=false;
|
||||
}*/
|
||||
}
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64;
|
||||
if (chan[i].furnacePCM) {
|
||||
double off=1.0;
|
||||
if (chan[i].pcm.sample>=0 && chan[i].pcm.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->song.sample[chan[i].pcm.sample];
|
||||
off=(double)s->centerRate/8363.0;
|
||||
}
|
||||
chan[i].pcm.freq=MIN(255,((off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250);
|
||||
if (dumpWrites && i>=8) {
|
||||
addWrite(0x10007+((i-8)<<3),chan[i].pcm.freq);
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
}
|
||||
|
||||
int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].pcm.sample=ins->amiga.initSample;
|
||||
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(c.chan<<3),3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
chan[c.chan].baseFreq=(c.value<<6);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].furnacePCM=true;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->song.sample[chan[c.chan].pcm.sample];
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->rendOffP>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->rendOffP)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->rendOffP>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->rendOffP&0xffff)+s->rendLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=(int)s->rendLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->rendOffP>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->rendOffP&0xffff)+s->loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->rendOffP>>16)<<3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].pcm.sample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(c.chan<<3),3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
chan[c.chan].pcm.freq=MIN(255,(parent->song.sample[chan[c.chan].pcm.sample]->rate*255)/31250);
|
||||
chan[c.chan].furnacePCM=false;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->song.sample[chan[c.chan].pcm.sample];
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->rendOffP>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->rendOffP)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->rendOffP>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->rendOffP&0xffff)+s->rendLength-1)>>8));
|
||||
if (s->loopStart<0 || s->loopStart>=(int)s->rendLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->rendOffP>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->rendOffP&0xffff)+s->loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->rendOffP>>16)<<3));
|
||||
}
|
||||
addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(c.chan<<3),3);
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.hasVol) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLUME: {
|
||||
return chan[c.chan].vol;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
chan[c.chan].insChanged=true;
|
||||
}
|
||||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].chVolL=(c.value>>4)|(((c.value>>4)>>1)<<4);
|
||||
chan[c.chan].chVolR=(c.value&15)|(((c.value&15)>>1)<<4);
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=(c.value2<<6)+baseFreqOff;
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
newFreq=chan[c.chan].baseFreq+c.value;
|
||||
if (newFreq>=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
newFreq=chan[c.chan].baseFreq-c.value;
|
||||
if (newFreq<=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=newFreq;
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=(c.value<<6)+baseFreqOff;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_NOTE:
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
chan[c.chan].pcm.freq=c.value;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//printf("WARNING: unimplemented command %d\n",c.cmd);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::forceIns() {
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::notifyInsChange(int ins) {
|
||||
for (int i=0; i<16; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformSegaPCM::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformSegaPCM::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformSegaPCM::getRegisterPoolSize() {
|
||||
return 256;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::poke(unsigned int addr, unsigned short val) {
|
||||
//immWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::poke(std::vector<DivRegWrite>& wlist) {
|
||||
//for (DivRegWrite& i: wlist) immWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
memset(regPool,0,256);
|
||||
for (int i=0; i<16; i++) {
|
||||
chan[i]=DivPlatformSegaPCM::Channel();
|
||||
chan[i].vol=0x7f;
|
||||
chan[i].outVol=0x7f;
|
||||
}
|
||||
|
||||
lastBusy=60;
|
||||
pcmCycles=0;
|
||||
pcmL=0;
|
||||
pcmR=0;
|
||||
sampleBank=0;
|
||||
delay=0;
|
||||
amDepth=0x7f;
|
||||
pmDepth=0x7f;
|
||||
|
||||
if (dumpWrites) {
|
||||
for (int i=0; i<16; i++) {
|
||||
addWrite(0x10086+(i<<3),3);
|
||||
addWrite(0x10002+(i<<3),0x7f);
|
||||
addWrite(0x10003+(i<<3),0x7f);
|
||||
}
|
||||
}
|
||||
|
||||
extMode=false;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::setFlags(unsigned int flags) {
|
||||
chipClock=8000000.0;
|
||||
rate=31250;
|
||||
}
|
||||
|
||||
bool DivPlatformSegaPCM::isStereo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int DivPlatformSegaPCM::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<16; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
setFlags(flags);
|
||||
reset();
|
||||
|
||||
return 16;
|
||||
}
|
||||
|
||||
void DivPlatformSegaPCM::quit() {
|
||||
}
|
||||
|
||||
DivPlatformSegaPCM::~DivPlatformSegaPCM() {
|
||||
}
|
93
src/engine/platform/segapcm.h
Normal file
93
src/engine/platform/segapcm.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _SEGAPCM_H
|
||||
#define _SEGAPCM_H
|
||||
#include "../dispatch.h"
|
||||
#include "../instrument.h"
|
||||
#include <queue>
|
||||
#include "../macroInt.h"
|
||||
|
||||
class DivPlatformSegaPCM: public DivDispatch {
|
||||
protected:
|
||||
struct Channel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, note;
|
||||
unsigned char ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
|
||||
int vol, outVol;
|
||||
unsigned char chVolL, chVolR;
|
||||
|
||||
struct PCMChannel {
|
||||
int sample;
|
||||
unsigned int pos; // <<8
|
||||
unsigned short len;
|
||||
unsigned char freq;
|
||||
PCMChannel(): sample(-1), pos(0), len(0), freq(0) {}
|
||||
} pcm;
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(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 chan[16];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
bool addrOrVal;
|
||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
int delay, baseFreqOff;
|
||||
int pcmL, pcmR, pcmCycles;
|
||||
unsigned char sampleBank;
|
||||
unsigned char lastBusy;
|
||||
unsigned char amDepth, pmDepth;
|
||||
|
||||
unsigned char regPool[256];
|
||||
|
||||
bool extMode, useYMFM;
|
||||
|
||||
bool isMuted[16];
|
||||
|
||||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void muteChannel(int ch, bool mute);
|
||||
void notifyInsChange(int ins);
|
||||
void setFlags(unsigned int flags);
|
||||
bool isStereo();
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformSegaPCM();
|
||||
};
|
||||
#endif
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "blip_buf.h"
|
||||
#include "song.h"
|
||||
#include "wavetable.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "dispatch.h"
|
||||
|
@ -147,9 +148,8 @@ int DivEngine::dispatchCmd(DivCommand c) {
|
|||
|
||||
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
switch (sysOfChan[ch]) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
switch (effect) {
|
||||
case 0x17: // DAC enable
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0)));
|
||||
|
@ -257,16 +257,14 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
|
||||
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
switch (sysOfChan[ch]) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2151:
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
switch (effect) {
|
||||
case 0x10: // LFO or noise mode
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_ARCADE || sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
|
||||
} else {
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
|
||||
|
@ -293,12 +291,12 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
}
|
||||
break;
|
||||
case 0x17: // arcade LFO
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_ARCADE || sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
case 0x18: // EXT or LFO waveform
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_ARCADE || sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal));
|
||||
} else {
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal));
|
||||
|
@ -325,10 +323,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case 0x1f: // UNOFFICIAL: Arcade PM depth
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127));
|
||||
break;
|
||||
case 0x20: // PCM frequency or Neo Geo PSG mode
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_ARCADE || sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
|
||||
} else if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
|
||||
case 0x20: // Neo Geo PSG mode
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
|
@ -453,6 +449,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case 0x29: // auto-envelope
|
||||
dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_SAA1099:
|
||||
|
@ -466,6 +464,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case 0x12: // setup envelope
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_TIA:
|
||||
|
@ -473,6 +473,18 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case 0x10: // select waveform
|
||||
dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
switch (effect) {
|
||||
case 0x20: // PCM frequency
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -755,7 +767,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xe5: // pitch
|
||||
chan[i].pitch=effectVal-0x80;
|
||||
if (sysOfChan[i]==DIV_SYSTEM_ARCADE || sysOfChan[i]==DIV_SYSTEM_YM2151) { // YM2151 pitch oddity
|
||||
if (sysOfChan[i]==DIV_SYSTEM_YM2151) { // YM2151 pitch oddity
|
||||
chan[i].pitch*=2;
|
||||
if (chan[i].pitch<-128) chan[i].pitch=-128;
|
||||
if (chan[i].pitch>127) chan[i].pitch=127;
|
||||
|
|
|
@ -34,16 +34,16 @@
|
|||
enum DivSystem {
|
||||
DIV_SYSTEM_NULL=0,
|
||||
DIV_SYSTEM_YMU759,
|
||||
DIV_SYSTEM_GENESIS,
|
||||
DIV_SYSTEM_GENESIS_EXT,
|
||||
DIV_SYSTEM_GENESIS, // ** COMPOUND SYSTEM - DO NOT USE! **
|
||||
DIV_SYSTEM_GENESIS_EXT, // ** COMPOUND SYSTEM - DO NOT USE! **
|
||||
DIV_SYSTEM_SMS,
|
||||
DIV_SYSTEM_SMS_OPLL,
|
||||
DIV_SYSTEM_SMS_OPLL, // ** COMPOUND SYSTEM - DO NOT USE! **
|
||||
DIV_SYSTEM_GB,
|
||||
DIV_SYSTEM_PCE,
|
||||
DIV_SYSTEM_NES,
|
||||
DIV_SYSTEM_C64_6581,
|
||||
DIV_SYSTEM_C64_8580,
|
||||
DIV_SYSTEM_ARCADE,
|
||||
DIV_SYSTEM_ARCADE, // ** COMPOUND SYSTEM - DO NOT USE! **
|
||||
DIV_SYSTEM_YM2610,
|
||||
DIV_SYSTEM_YM2610_EXT,
|
||||
|
||||
|
@ -88,7 +88,8 @@ enum DivSystem {
|
|||
DIV_SYSTEM_YM2610_FULL_EXT,
|
||||
DIV_SYSTEM_OPLL_DRUMS,
|
||||
DIV_SYSTEM_LYNX,
|
||||
DIV_SYSTEM_QSOUND
|
||||
DIV_SYSTEM_QSOUND,
|
||||
DIV_SYSTEM_SEGAPCM_COMPAT
|
||||
};
|
||||
|
||||
struct DivSong {
|
||||
|
@ -278,7 +279,7 @@ struct DivSong {
|
|||
DivSong():
|
||||
version(0),
|
||||
isDMF(false),
|
||||
systemLen(1),
|
||||
systemLen(2),
|
||||
name(""),
|
||||
author(""),
|
||||
carrier(""),
|
||||
|
@ -331,7 +332,8 @@ struct DivSong {
|
|||
chanShow[i]=true;
|
||||
chanCollapse[i]=false;
|
||||
}
|
||||
system[0]=DIV_SYSTEM_GENESIS;
|
||||
system[0]=DIV_SYSTEM_YM2612;
|
||||
system[1]=DIV_SYSTEM_SMS;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ DivSystem DivEngine::systemFromFile(unsigned char val) {
|
|||
return DIV_SYSTEM_OPLL_DRUMS;
|
||||
case 0xa8:
|
||||
return DIV_SYSTEM_LYNX;
|
||||
case 0xa9:
|
||||
return DIV_SYSTEM_SEGAPCM_COMPAT;
|
||||
case 0xe0:
|
||||
return DIV_SYSTEM_QSOUND;
|
||||
}
|
||||
|
@ -248,6 +250,8 @@ unsigned char DivEngine::systemToFile(DivSystem val) {
|
|||
return 0xa7;
|
||||
case DIV_SYSTEM_LYNX:
|
||||
return 0xa8;
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return 0xa9;
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return 0xe0;
|
||||
|
||||
|
@ -364,6 +368,8 @@ int DivEngine::getChannelCount(DivSystem sys) {
|
|||
return 11;
|
||||
case DIV_SYSTEM_LYNX:
|
||||
return 4;
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return 5;
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return 19;
|
||||
}
|
||||
|
@ -488,6 +494,8 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
return "Yamaha OPLL with drums";
|
||||
case DIV_SYSTEM_LYNX:
|
||||
return "Atari Lynx";
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return "SegaPCM (compatible 5-channel mode)";
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return "Capcom QSound";
|
||||
}
|
||||
|
@ -607,6 +615,8 @@ const char* DivEngine::getSystemChips(DivSystem sys) {
|
|||
return "Yamaha YM2413 with drums";
|
||||
case DIV_SYSTEM_LYNX:
|
||||
return "Mikey";
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return "SegaPCM (compatible 5-channel mode)";
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return "Capcom DL-1425";
|
||||
}
|
||||
|
@ -954,6 +964,7 @@ const char* DivEngine::getChannelName(int chan) {
|
|||
break;
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return chanNames[28][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_PCSPKR:
|
||||
|
@ -1088,6 +1099,7 @@ const char* DivEngine::getChannelShortName(int chan) {
|
|||
break;
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return chanShortNames[28][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_PCSPKR:
|
||||
|
@ -1219,6 +1231,7 @@ int DivEngine::getChannelType(int chan) {
|
|||
break;
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return chanTypes[28][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
|
@ -1346,6 +1359,7 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
|
|||
break;
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return chanPrefType[28][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
|
@ -1401,21 +1415,21 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
|
|||
|
||||
bool DivEngine::isVGMExportable(DivSystem which) {
|
||||
switch (which) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_SMS:
|
||||
case DIV_SYSTEM_GB:
|
||||
case DIV_SYSTEM_PCE:
|
||||
case DIV_SYSTEM_NES:
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2151:
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_AY8910:
|
||||
case DIV_SYSTEM_AY8930:
|
||||
case DIV_SYSTEM_SAA1099:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -220,12 +220,6 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- chVolL: %.2x",ch->chVolL);
|
||||
ImGui::Text("- chVolR: %.2x",ch->chVolR);
|
||||
ImGui::Text("* PCM:");
|
||||
ImGui::Text(" - sample: %d",ch->pcm.sample);
|
||||
ImGui::Text(" - pos: %d",ch->pcm.pos>>8);
|
||||
ImGui::Text(" - subPos: %d",ch->pcm.pos&0xff);
|
||||
ImGui::Text(" - len: %d",ch->pcm.len);
|
||||
ImGui::Text(" - freq: %.2x",ch->pcm.freq);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
|
|
|
@ -4478,23 +4478,23 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginMenu("add system...")) {
|
||||
sysAddOption(DIV_SYSTEM_GENESIS);
|
||||
sysAddOption(DIV_SYSTEM_GENESIS_EXT);
|
||||
sysAddOption(DIV_SYSTEM_YM2612);
|
||||
sysAddOption(DIV_SYSTEM_YM2612_EXT);
|
||||
sysAddOption(DIV_SYSTEM_SMS);
|
||||
sysAddOption(DIV_SYSTEM_GB);
|
||||
sysAddOption(DIV_SYSTEM_PCE);
|
||||
sysAddOption(DIV_SYSTEM_NES);
|
||||
sysAddOption(DIV_SYSTEM_C64_8580);
|
||||
sysAddOption(DIV_SYSTEM_C64_6581);
|
||||
sysAddOption(DIV_SYSTEM_ARCADE);
|
||||
sysAddOption(DIV_SYSTEM_YM2151);
|
||||
sysAddOption(DIV_SYSTEM_SEGAPCM);
|
||||
sysAddOption(DIV_SYSTEM_SEGAPCM_COMPAT);
|
||||
sysAddOption(DIV_SYSTEM_YM2610);
|
||||
sysAddOption(DIV_SYSTEM_YM2610_EXT);
|
||||
sysAddOption(DIV_SYSTEM_YM2610_FULL);
|
||||
sysAddOption(DIV_SYSTEM_YM2610_FULL_EXT);
|
||||
sysAddOption(DIV_SYSTEM_AY8910);
|
||||
sysAddOption(DIV_SYSTEM_AMIGA);
|
||||
sysAddOption(DIV_SYSTEM_YM2151);
|
||||
sysAddOption(DIV_SYSTEM_YM2612);
|
||||
sysAddOption(DIV_SYSTEM_TIA);
|
||||
sysAddOption(DIV_SYSTEM_SAA1099);
|
||||
sysAddOption(DIV_SYSTEM_AY8930);
|
||||
|
@ -4509,8 +4509,8 @@ bool FurnaceGUI::loop() {
|
|||
bool restart=settings.restartOnFlagChange;
|
||||
bool sysPal=flags&1;
|
||||
switch (e->song.system[i]) {
|
||||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_GENESIS_EXT: {
|
||||
case DIV_SYSTEM_YM2612:
|
||||
case DIV_SYSTEM_YM2612_EXT: {
|
||||
if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&3)==0)) {
|
||||
e->setSysFlags(i,(flags&0x80000000)|0,restart);
|
||||
}
|
||||
|
@ -4560,7 +4560,6 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2151:
|
||||
if (ImGui::RadioButton("NTSC (3.58MHz)",flags==0)) {
|
||||
e->setSysFlags(i,0,restart);
|
||||
|
@ -4704,23 +4703,23 @@ bool FurnaceGUI::loop() {
|
|||
if (ImGui::BeginMenu("change system...")) {
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
||||
sysChangeOption(i,DIV_SYSTEM_GENESIS);
|
||||
sysChangeOption(i,DIV_SYSTEM_GENESIS_EXT);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2612);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2612_EXT);
|
||||
sysChangeOption(i,DIV_SYSTEM_SMS);
|
||||
sysChangeOption(i,DIV_SYSTEM_GB);
|
||||
sysChangeOption(i,DIV_SYSTEM_PCE);
|
||||
sysChangeOption(i,DIV_SYSTEM_NES);
|
||||
sysChangeOption(i,DIV_SYSTEM_C64_8580);
|
||||
sysChangeOption(i,DIV_SYSTEM_C64_6581);
|
||||
sysChangeOption(i,DIV_SYSTEM_ARCADE);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2151);
|
||||
sysChangeOption(i,DIV_SYSTEM_SEGAPCM);
|
||||
sysChangeOption(i,DIV_SYSTEM_SEGAPCM_COMPAT);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2610);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2610_EXT);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2610_FULL);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2610_FULL_EXT);
|
||||
sysChangeOption(i,DIV_SYSTEM_AY8910);
|
||||
sysChangeOption(i,DIV_SYSTEM_AMIGA);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2151);
|
||||
sysChangeOption(i,DIV_SYSTEM_YM2612);
|
||||
sysChangeOption(i,DIV_SYSTEM_TIA);
|
||||
sysChangeOption(i,DIV_SYSTEM_SAA1099);
|
||||
sysChangeOption(i,DIV_SYSTEM_AY8930);
|
||||
|
|
Loading…
Reference in a new issue