force update

This commit is contained in:
BlastBrothers 2022-02-23 11:51:02 -05:00
parent 9237a0f6fa
commit 1c33fe0edb
23 changed files with 1286 additions and 646 deletions

View File

@ -310,6 +310,7 @@ src/engine/platform/ay8930.cpp
src/engine/platform/tia.cpp src/engine/platform/tia.cpp
src/engine/platform/saa.cpp src/engine/platform/saa.cpp
src/engine/platform/amiga.cpp src/engine/platform/amiga.cpp
src/engine/platform/segapcm.cpp
src/engine/platform/qsound.cpp src/engine/platform/qsound.cpp
src/engine/platform/dummy.cpp src/engine/platform/dummy.cpp
src/engine/platform/lynx.cpp src/engine/platform/lynx.cpp

BIN
demos/m7 vibe.fur Normal file

Binary file not shown.

View File

@ -1105,7 +1105,7 @@ namespace IGFD
bool needToApllyNewFilter = false; bool needToApllyNewFilter = false;
ImGui::PushItemWidth(FILTER_COMBO_WIDTH); ImGui::PushItemWidth(FILTER_COMBO_WIDTH*FileDialog::Instance()->DpiScale);
if (ImGui::BeginCombo("##Filters", prSelectedFilter.filter.c_str(), ImGuiComboFlags_None)) if (ImGui::BeginCombo("##Filters", prSelectedFilter.filter.c_str(), ImGuiComboFlags_None))
{ {
intptr_t i = 0; intptr_t i = 0;
@ -3279,7 +3279,7 @@ namespace IGFD
//// FILE DIALOG CONSTRUCTOR / DESTRUCTOR /////////////////////////////////////////// //// FILE DIALOG CONSTRUCTOR / DESTRUCTOR ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {} IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {DpiScale=1.0f;}
IGFD::FileDialog::~FileDialog() = default; IGFD::FileDialog::~FileDialog() = default;
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
@ -3827,8 +3827,9 @@ namespace IGFD
// Input file fields // Input file fields
float width = ImGui::GetContentRegionAvail().x; float width = ImGui::GetContentRegionAvail().x;
// fix this! fix this! fix this!
if (!fdFile.puDLGDirectoryMode) if (!fdFile.puDLGDirectoryMode)
width -= FILTER_COMBO_WIDTH; width -= FILTER_COMBO_WIDTH*DpiScale;
ImGui::PushItemWidth(width); ImGui::PushItemWidth(width);
ImGui::InputText("##FileName", fdFile.puFileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER); ImGui::InputText("##FileName", fdFile.puFileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
if (ImGui::GetItemID() == ImGui::GetActiveID()) if (ImGui::GetItemID() == ImGui::GetActiveID())

View File

@ -1133,6 +1133,7 @@ namespace IGFD
public: public:
bool puAnyWindowsHovered = false; // not remember why haha :) todo : to check if we can remove bool puAnyWindowsHovered = false; // not remember why haha :) todo : to check if we can remove
double DpiScale;
public: public:
static FileDialog* Instance() // Singleton for easier accces form anywhere but only one dialog at a time static FileDialog* Instance() // Singleton for easier accces form anywhere but only one dialog at a time

View File

@ -225,7 +225,7 @@ class DivDispatch {
/** /**
* get the bit depth of the register pool of this dispatch. * get the bit depth of the register pool of this dispatch.
* If the result is 16, it should be casted to unsigned short * If the result is 16, it should be casted to unsigned short.
* @return the depth. Default value is 8 * @return the depth. Default value is 8
*/ */
virtual int getRegisterPoolDepth(); virtual int getRegisterPoolDepth();

View File

@ -34,6 +34,7 @@
#include "platform/tia.h" #include "platform/tia.h"
#include "platform/saa.h" #include "platform/saa.h"
#include "platform/amiga.h" #include "platform/amiga.h"
#include "platform/segapcm.h"
#include "platform/qsound.h" #include "platform/qsound.h"
#include "platform/dummy.h" #include "platform/dummy.h"
#include "platform/lynx.h" #include "platform/lynx.h"
@ -140,12 +141,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
bbInLen=32768; bbInLen=32768;
switch (sys) { switch (sys) {
case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612:
dispatch=new DivPlatformGenesis; dispatch=new DivPlatformGenesis;
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
break; break;
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_YM2612_EXT:
dispatch=new DivPlatformGenesisExt; dispatch=new DivPlatformGenesisExt;
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
break; break;
@ -169,7 +169,6 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
dispatch=new DivPlatformC64; dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setChipModel(false); ((DivPlatformC64*)dispatch)->setChipModel(false);
break; break;
case DIV_SYSTEM_ARCADE:
case DIV_SYSTEM_YM2151: case DIV_SYSTEM_YM2151:
dispatch=new DivPlatformArcade; dispatch=new DivPlatformArcade;
((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0); ((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: case DIV_SYSTEM_QSOUND:
dispatch=new DivPlatformQSound; dispatch=new DivPlatformQSound;
break; break;
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
dispatch=new DivPlatformSegaPCM;
break;
default: default:
logW("this system is not supported yet! using dummy platform.\n"); logW("this system is not supported yet! using dummy platform.\n");
dispatch=new DivPlatformDummy; dispatch=new DivPlatformDummy;

View File

@ -607,8 +607,9 @@ void DivEngine::renderSamples() {
for (int i=0; i<song.sampleLen; i++) { for (int i=0; i<song.sampleLen; i++) {
DivSample* s=song.sample[i]; DivSample* s=song.sample[i];
int length = s->rendLength; int length = s->rendLength;
if(length > 65536-16) if (length > 65536-16) {
length = 65536-16; length = 65536-16;
}
if ((memPos&0xff0000)!=((memPos+length)&0xff0000)) { if ((memPos&0xff0000)!=((memPos+length)&0xff0000)) {
memPos=(memPos+0xffff)&0xff0000; memPos=(memPos+0xffff)&0xff0000;
} }
@ -617,14 +618,12 @@ void DivEngine::renderSamples() {
break; break;
} }
if (memPos+length>=16777216) { if (memPos+length>=16777216) {
for(unsigned int i=0; i<16777216-(memPos+length); i++) for (unsigned int i=0; i<16777216-(memPos+length); i++) {
{
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0); qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
} }
logW("out of QSound PCM memory for sample %d!\n",i); logW("out of QSound PCM memory for sample %d!\n",i);
} else { } else {
for(int i=0; i<length; i++) for (int i=0; i<length; i++) {
{
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0); qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
} }
} }
@ -1024,11 +1023,11 @@ int DivEngine::getEffectiveSampleRate(int rate) {
switch (song.system[0]) { switch (song.system[0]) {
case DIV_SYSTEM_YMU759: case DIV_SYSTEM_YMU759:
return 8000; return 8000;
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612_EXT:
return 1278409/(1280000/rate); return 1278409/(1280000/rate);
case DIV_SYSTEM_PCE: case DIV_SYSTEM_PCE:
return 1789773/(1789773/rate); 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; 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: case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL: case DIV_SYSTEM_YM2610_FULL_EXT:
return 18518; return 18518;

View File

@ -365,6 +365,9 @@ class DivEngine {
// get preferred instrument type // get preferred instrument type
DivInstrumentType getPreferInsType(int ch); DivInstrumentType getPreferInsType(int ch);
// get song system name
const char* getSongSystemName();
// get sys name // get sys name
const char* getSystemName(DivSystem sys); const char* getSystemName(DivSystem sys);

View File

@ -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) { if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) {
ds.systemLen=2; ds.systemLen=2;
ds.system[0]=DIV_SYSTEM_SMS; ds.system[0]=DIV_SYSTEM_SMS;
@ -789,6 +806,42 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
ds.systemFlags[i]=reader.readI(); 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.name=reader.readString();
ds.author=reader.readString(); ds.author=reader.readString();
logI("%s by %s\n",ds.name.c_str(),ds.author.c_str()); logI("%s by %s\n",ds.name.c_str(),ds.author.c_str());
@ -1394,15 +1447,28 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
lastError="invalid version to save in! this is a bug!"; lastError="invalid version to save in! this is a bug!";
return NULL; return NULL;
} }
// check whether system is compound
bool isFlat=false;
if (song.systemLen==2) {
if (song.system[0]==DIV_SYSTEM_YM2612 && song.system[1]==DIV_SYSTEM_SMS) {
isFlat=true;
}
if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) {
isFlat=true;
}
if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) {
isFlat=true;
}
if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
isFlat=true;
}
}
// fail if more than one system // fail if more than one system
// TODO: fix this mess for the flattening in 0.6 if (!isFlat && song.systemLen!=1) {
if (!(song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL)) {
if (song.systemLen!=1) {
logE("cannot save multiple systems in this format!\n"); logE("cannot save multiple systems in this format!\n");
lastError="multiple systems not possible on .dmf"; lastError="multiple systems not possible on .dmf";
return NULL; return NULL;
} }
}
// fail if this is an YMU759 song // fail if this is an YMU759 song
if (song.system[0]==DIV_SYSTEM_YMU759) { if (song.system[0]==DIV_SYSTEM_YMU759) {
logE("cannot save YMU759 song!\n"); logE("cannot save YMU759 song!\n");
@ -1416,7 +1482,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
return NULL; return NULL;
} }
// fail if the system is Furnace-exclusive // fail if the system is Furnace-exclusive
if (systemToFile(song.system[0])&0x80) { if (!isFlat && systemToFile(song.system[0])&0x80) {
logE("cannot save Furnace-exclusive system song!\n"); logE("cannot save Furnace-exclusive system song!\n");
lastError="this system is not possible on .dmf"; lastError="this system is not possible on .dmf";
return NULL; return NULL;
@ -1432,7 +1498,16 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
// version // version
w->writeC(version); w->writeC(version);
DivSystem sys=DIV_SYSTEM_NULL; DivSystem sys=DIV_SYSTEM_NULL;
if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) { if (song.system[0]==DIV_SYSTEM_YM2612 && song.system[1]==DIV_SYSTEM_SMS) {
w->writeC(systemToFile(DIV_SYSTEM_GENESIS));
sys=DIV_SYSTEM_GENESIS;
} else if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) {
w->writeC(systemToFile(DIV_SYSTEM_GENESIS_EXT));
sys=DIV_SYSTEM_GENESIS_EXT;
} else if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) {
w->writeC(systemToFile(DIV_SYSTEM_ARCADE));
sys=DIV_SYSTEM_ARCADE;
} else if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
w->writeC(systemToFile(DIV_SYSTEM_SMS_OPLL)); w->writeC(systemToFile(DIV_SYSTEM_SMS_OPLL));
sys=DIV_SYSTEM_SMS_OPLL; sys=DIV_SYSTEM_SMS_OPLL;
} else { } else {

View File

@ -130,9 +130,6 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) {
case 0x1f: case 0x1f:
return "1Fxx: Set PM depth (0 to 7F)"; return "1Fxx: Set PM depth (0 to 7F)";
break; break;
case 0x20:
return "20xx: Set PCM frequency";
break;
} }
return NULL; 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,NULL,NULL,NULL,NULL);
OPM_Clock(&fm,o,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]<-32768) o[0]=-32768;
if (o[0]>32767) o[0]=32767; 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); fm_ymfm->generate(&out_ymfm);
pcmCycles+=31250; os[0]=out_ymfm.data[0];
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;
if (os[0]<-32768) os[0]=-32768; if (os[0]<-32768) os[0]=-32768;
if (os[0]>32767) os[0]=32767; 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]<-32768) os[1]=-32768;
if (os[1]>32767) os[1]=32767; if (os[1]>32767) os[1]=32767;
@ -464,106 +390,21 @@ void DivPlatformArcade::tick() {
chan[i].keyOn=false; 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) { void DivPlatformArcade::muteChannel(int ch, bool mute) {
isMuted[ch]=mute; isMuted[ch]=mute;
if (ch<8) {
if (isMuted[ch]) { if (isMuted[ch]) {
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)); rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
} else { } 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)); 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 DivPlatformArcade::dispatch(DivCommand c) {
int pcmChan=c.chan-8;
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); 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) { if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm; chan[c.chan].state=ins->fm;
@ -614,12 +455,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_NOTE_OFF: 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].keyOff=true;
chan[c.chan].keyOn=false; chan[c.chan].keyOn=false;
chan[c.chan].active=false; chan[c.chan].active=false;
@ -638,15 +473,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
if (!chan[c.chan].std.hasVol) { if (!chan[c.chan].std.hasVol) {
chan[c.chan].outVol=c.value; 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++) { for (int i=0; i<4; i++) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
@ -669,15 +495,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
chan[c.chan].ins=c.value; chan[c.chan].ins=c.value;
break; break;
case DIV_CMD_PANNING: { 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);
}
} else {
chan[c.chan].chVolL=((c.value>>4)==1); chan[c.chan].chVolL=((c.value>>4)==1);
chan[c.chan].chVolR=((c.value&15)==1); chan[c.chan].chVolR=((c.value&15)==1);
if (isMuted[c.chan]) { if (isMuted[c.chan]) {
@ -685,7 +502,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
} else { } 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; break;
} }
case DIV_CMD_PITCH: { case DIV_CMD_PITCH: {
@ -724,17 +540,14 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_FM_LFO: { case DIV_CMD_FM_LFO: {
if (c.chan>7) break;
rWrite(0x18,c.value); rWrite(0x18,c.value);
break; break;
} }
case DIV_CMD_FM_LFO_WAVE: { case DIV_CMD_FM_LFO_WAVE: {
if (c.chan>7) break;
rWrite(0x1b,c.value&3); rWrite(0x1b,c.value&3);
break; break;
} }
case DIV_CMD_FM_FB: { case DIV_CMD_FM_FB: {
if (c.chan>7) break;
chan[c.chan].state.fb=c.value&7; chan[c.chan].state.fb=c.value&7;
if (isMuted[c.chan]) { if (isMuted[c.chan]) {
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); 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; break;
} }
case DIV_CMD_FM_MULT: { case DIV_CMD_FM_MULT: {
if (c.chan>7) break;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.mult=c.value2&15; op.mult=c.value2&15;
@ -752,7 +564,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_FM_TL: { case DIV_CMD_FM_TL: {
if (c.chan>7) break;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.tl=c.value2; op.tl=c.value2;
@ -764,7 +575,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_FM_AR: { case DIV_CMD_FM_AR: {
if (c.chan>7) break;
if (c.value<0) { if (c.value<0) {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
@ -803,12 +613,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
} }
break; 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: case DIV_ALWAYS_SET_VOLUME:
return 0; return 0;
break; break;
@ -820,12 +624,6 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
case DIV_CMD_PRE_NOTE: case DIV_CMD_PRE_NOTE:
break; 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: default:
//printf("WARNING: unimplemented command %d\n",c.cmd); //printf("WARNING: unimplemented command %d\n",c.cmd);
break; break;
@ -860,9 +658,6 @@ void DivPlatformArcade::forceIns() {
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
for (int i=8; i<13; i++) {
chan[i].insChanged=true;
}
immWrite(0x19,amDepth); immWrite(0x19,amDepth);
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
} }
@ -907,7 +702,7 @@ void DivPlatformArcade::reset() {
if (dumpWrites) { if (dumpWrites) {
addWrite(0xffffffff,0); addWrite(0xffffffff,0);
} }
for (int i=0; i<13; i++) { for (int i=0; i<8; i++) {
chan[i]=DivPlatformArcade::Channel(); chan[i]=DivPlatformArcade::Channel();
chan[i].vol=0x7f; chan[i].vol=0x7f;
chan[i].outVol=0x7f; chan[i].outVol=0x7f;
@ -922,7 +717,6 @@ void DivPlatformArcade::reset() {
pcmCycles=0; pcmCycles=0;
pcmL=0; pcmL=0;
pcmR=0; pcmR=0;
sampleBank=0;
delay=0; delay=0;
amDepth=0x7f; amDepth=0x7f;
pmDepth=0x7f; pmDepth=0x7f;
@ -931,13 +725,6 @@ void DivPlatformArcade::reset() {
immWrite(0x19,amDepth); immWrite(0x19,amDepth);
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
//rWrite(0x1b,0x00); //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; extMode=false;
} }
@ -972,14 +759,14 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in
parent=p; parent=p;
dumpWrites=false; dumpWrites=false;
skipRegisterWrites=false; skipRegisterWrites=false;
for (int i=0; i<13; i++) { for (int i=0; i<8; i++) {
isMuted[i]=false; isMuted[i]=false;
} }
setFlags(flags); setFlags(flags);
if (useYMFM) fm_ymfm=new ymfm::ym2151(iface); if (useYMFM) fm_ymfm=new ymfm::ym2151(iface);
reset(); reset();
return 13; return 8;
} }
void DivPlatformArcade::quit() { void DivPlatformArcade::quit() {

View File

@ -42,17 +42,9 @@ class DivPlatformArcade: public DivDispatch {
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
int vol, outVol; int vol, outVol;
unsigned char chVolL, chVolR; 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(): 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 { struct QueuedWrite {
unsigned short addr; unsigned short addr;
unsigned char val; unsigned char val;
@ -63,7 +55,6 @@ class DivPlatformArcade: public DivDispatch {
opm_t fm; opm_t fm;
int delay, baseFreqOff; int delay, baseFreqOff;
int pcmL, pcmR, pcmCycles; int pcmL, pcmR, pcmCycles;
unsigned char sampleBank;
unsigned char lastBusy; unsigned char lastBusy;
unsigned char amDepth, pmDepth; unsigned char amDepth, pmDepth;
@ -75,7 +66,7 @@ class DivPlatformArcade: public DivDispatch {
bool extMode, useYMFM; bool extMode, useYMFM;
bool isMuted[13]; bool isMuted[8];
short oldWrites[256]; short oldWrites[256];
short pendingWrites[256]; short pendingWrites[256];

View File

@ -1,3 +1,22 @@
/**
* 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 _LYNX_H #ifndef _LYNX_H
#define _LYNX_H #define _LYNX_H

View File

@ -258,9 +258,10 @@ const char* DivPlatformQSound::getEffectName(unsigned char effect) {
return "11xx: Set channel echo level (00 to FF)"; return "11xx: Set channel echo level (00 to FF)";
break; break;
default: default:
if((effect & 0xf0) == 0x30) if ((effect & 0xf0) == 0x30) {
return "3xxx: Set echo delay buffer length (000 to AA5)"; return "3xxx: Set echo delay buffer length (000 to AA5)";
} }
}
return NULL; return NULL;
} }
void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t len) { void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t len) {
@ -277,12 +278,10 @@ void DivPlatformQSound::tick() {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.hadVol) {
chan[i].outVol=((chan[i].vol%256)*MIN(255,chan[i].std.vol << 2))>>8; chan[i].outVol=((chan[i].vol&0xff)*MIN(255,chan[i].std.vol<<2))>>8;
// Check if enabled and write volume // Check if enabled and write volume
if(chan[i].active) if (chan[i].active) {
{ rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4);
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 5);
//logW("ch %d vol=%04x (hadVol)!\n",i,chan[i].outVol << 5);
} }
} }
uint16_t qsound_bank = 0; uint16_t qsound_bank = 0;
@ -301,15 +300,13 @@ void DivPlatformQSound::tick() {
qsound_addr = s->rendOffQsound & 0xffff; qsound_addr = s->rendOffQsound & 0xffff;
int length = s->length; int length = s->length;
if(length > 65536 - 16) if (length > 65536 - 16) {
length = 65536 - 16; length = 65536 - 16;
if(s->loopStart == -1 || s->loopStart >= length) }
{ if (s->loopStart == -1 || s->loopStart >= length) {
qsound_end = s->rendOffQsound + length + 15; qsound_end = s->rendOffQsound + length + 15;
qsound_loop = 15; qsound_loop = 15;
} } else {
else
{
qsound_end = s->rendOffQsound + length; qsound_end = s->rendOffQsound + length;
qsound_loop = length - s->loopStart; qsound_loop = length - s->loopStart;
} }
@ -333,7 +330,6 @@ void DivPlatformQSound::tick() {
//DivInstrument* ins=parent->getIns(chan[i].ins); //DivInstrument* ins=parent->getIns(chan[i].ins);
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false);
if (chan[i].freq>0xffff) chan[i].freq=0xffff; if (chan[i].freq>0xffff) chan[i].freq=0xffff;
//if (chan[i].note>0x5d) chan[i].freq=0x01; //????
if (chan[i].keyOn) { if (chan[i].keyOn) {
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
rWrite(q1_reg_map[Q1V_END][i], qsound_end); rWrite(q1_reg_map[Q1V_END][i], qsound_end);
@ -343,16 +339,14 @@ void DivPlatformQSound::tick() {
//logW("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!\n",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); //logW("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!\n",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
// Write sample address. Enable volume // Write sample address. Enable volume
if (!chan[i].std.hadVol) { if (!chan[i].std.hadVol) {
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 5); rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4);
//logW("ch %d vol=%04x (!hadVol)!\n",i,chan[i].vol << 5);
} }
} }
if (chan[i].keyOff) { if (chan[i].keyOff) {
// Disable volume
rWrite(q1_reg_map[Q1V_VOL][i], 0); rWrite(q1_reg_map[Q1V_VOL][i], 0);
rWrite(q1_reg_map[Q1V_FREQ][i], 0); rWrite(q1_reg_map[Q1V_FREQ][i], 0);
// Disable volume } else if (chan[i].active) {
}
else if (chan[i].active) {
//logW("ch %d frequency set to %04x, off=%f, note=%d, %04x!\n",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); //logW("ch %d frequency set to %04x, off=%f, note=%d, %04x!\n",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note));
rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq); rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq);
} }
@ -413,10 +407,8 @@ int DivPlatformQSound::dispatch(DivCommand c) {
if (!chan[c.chan].std.hasVol) { if (!chan[c.chan].std.hasVol) {
// Check if enabled and write volume // Check if enabled and write volume
chan[c.chan].outVol=c.value; chan[c.chan].outVol=c.value;
if(chan[c.chan].active && c.chan < 16) if (chan[c.chan].active && c.chan < 16) {
{ rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4);
rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 5);
//logW("ch %d vol=%04x (cmd vol)!\n",c.chan,chan[c.chan].outVol << 5);
} }
} }
} }
@ -509,10 +501,11 @@ int DivPlatformQSound::dispatch(DivCommand c) {
} }
void DivPlatformQSound::muteChannel(int ch, bool mute) { void DivPlatformQSound::muteChannel(int ch, bool mute) {
if(mute) if (mute) {
chip.mute_mask |= (1 << ch); chip.mute_mask|=(1<<ch);
else } else {
chip.mute_mask &= ~(1 << ch); chip.mute_mask&=~(1<<ch);
}
} }
void DivPlatformQSound::forceIns() { void DivPlatformQSound::forceIns() {
@ -532,8 +525,9 @@ void DivPlatformQSound::reset() {
chan[i]=DivPlatformQSound::Channel(); chan[i]=DivPlatformQSound::Channel();
} }
qsound_reset(&chip); qsound_reset(&chip);
while(!chip.ready_flag) while(!chip.ready_flag) {
qsound_update(&chip); qsound_update(&chip);
}
immWrite(Q1_ECHO_LENGTH, 0xfff - (2725 - echoDelay)); immWrite(Q1_ECHO_LENGTH, 0xfff - (2725 - echoDelay));
immWrite(Q1_ECHO_FEEDBACK, echoFeedback << 6); immWrite(Q1_ECHO_FEEDBACK, echoFeedback << 6);
@ -557,6 +551,7 @@ void DivPlatformQSound::notifyInsChange(int ins) {
void DivPlatformQSound::notifyWaveChange(int wave) { void DivPlatformQSound::notifyWaveChange(int wave) {
// TODO when wavetables are added // TODO when wavetables are added
// TODO they probably won't be added unless the samples reside in RAM
} }
void DivPlatformQSound::notifyInsDeletion(void* ins) { void DivPlatformQSound::notifyInsDeletion(void* ins) {
@ -569,10 +564,12 @@ void DivPlatformQSound::setFlags(unsigned int flags) {
echoDelay = 2725 - (flags & 0xfff); echoDelay = 2725 - (flags & 0xfff);
echoFeedback = (flags >> 12) & 255; echoFeedback = (flags >> 12) & 255;
if(echoDelay < 0) if(echoDelay < 0) {
echoDelay = 0; echoDelay = 0;
if(echoDelay > 2725) }
if(echoDelay > 2725) {
echoDelay = 2725; echoDelay = 2725;
}
//rate=chipClock/CHIP_DIVIDER; //rate=chipClock/CHIP_DIVIDER;
} }
@ -608,9 +605,9 @@ int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, unsigned in
dumpWrites=false; dumpWrites=false;
skipRegisterWrites=false; skipRegisterWrites=false;
// for (int i=0; i<16; i++) { //for (int i=0; i<16; i++) {
// isMuted[i]=false; // isMuted[i]=false;
// } //}
setFlags(flags); setFlags(flags);
chipClock=60000000; chipClock=60000000;

View 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() {
}

View 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

View File

@ -18,6 +18,7 @@
*/ */
#include "blip_buf.h" #include "blip_buf.h"
#include "song.h"
#include "wavetable.h" #include "wavetable.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "dispatch.h" #include "dispatch.h"
@ -147,9 +148,8 @@ int DivEngine::dispatchCmd(DivCommand c) {
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
switch (sysOfChan[ch]) { switch (sysOfChan[ch]) {
case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_GENESIS_EXT:
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_YM2612_EXT:
switch (effect) { switch (effect) {
case 0x17: // DAC enable case 0x17: // DAC enable
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0)));
@ -241,7 +241,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal));
break; break;
default: default:
if ((effect & 0xf0)==0x30) { if ((effect&0xf0)==0x30) {
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal));
} else { } else {
return false; return false;
@ -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) { bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
switch (sysOfChan[ch]) { switch (sysOfChan[ch]) {
case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_GENESIS_EXT:
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2151: case DIV_SYSTEM_YM2151:
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
switch (effect) { switch (effect) {
case 0x10: // LFO or noise mode 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)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
} else { } else {
dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
@ -293,12 +291,12 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
} }
break; break;
case 0x17: // arcade LFO 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)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
} }
break; break;
case 0x18: // EXT or LFO waveform 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)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal));
} else { } else {
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); 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 case 0x1f: // UNOFFICIAL: Arcade PM depth
dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127)); dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127));
break; break;
case 0x20: // PCM frequency or Neo Geo PSG mode case 0x20: // Neo Geo PSG mode
if (sysOfChan[ch]==DIV_SYSTEM_ARCADE || sysOfChan[ch]==DIV_SYSTEM_YM2151) { if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
} else if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
} }
break; break;
@ -453,6 +449,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
case 0x29: // auto-envelope case 0x29: // auto-envelope
dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal));
break; break;
default:
return false;
} }
break; break;
case DIV_SYSTEM_SAA1099: case DIV_SYSTEM_SAA1099:
@ -466,6 +464,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
case 0x12: // setup envelope case 0x12: // setup envelope
dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal));
break; break;
default:
return false;
} }
break; break;
case DIV_SYSTEM_TIA: case DIV_SYSTEM_TIA:
@ -473,6 +473,18 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
case 0x10: // select waveform case 0x10: // select waveform
dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal));
break; 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; break;
default: default:
@ -755,7 +767,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
break; break;
case 0xe5: // pitch case 0xe5: // pitch
chan[i].pitch=effectVal-0x80; 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; chan[i].pitch*=2;
if (chan[i].pitch<-128) chan[i].pitch=-128; if (chan[i].pitch<-128) chan[i].pitch=-128;
if (chan[i].pitch>127) chan[i].pitch=127; if (chan[i].pitch>127) chan[i].pitch=127;

View File

@ -34,16 +34,16 @@
enum DivSystem { enum DivSystem {
DIV_SYSTEM_NULL=0, DIV_SYSTEM_NULL=0,
DIV_SYSTEM_YMU759, DIV_SYSTEM_YMU759,
DIV_SYSTEM_GENESIS, DIV_SYSTEM_GENESIS, // ** COMPOUND SYSTEM - DO NOT USE! **
DIV_SYSTEM_GENESIS_EXT, DIV_SYSTEM_GENESIS_EXT, // ** COMPOUND SYSTEM - DO NOT USE! **
DIV_SYSTEM_SMS, DIV_SYSTEM_SMS,
DIV_SYSTEM_SMS_OPLL, DIV_SYSTEM_SMS_OPLL, // ** COMPOUND SYSTEM - DO NOT USE! **
DIV_SYSTEM_GB, DIV_SYSTEM_GB,
DIV_SYSTEM_PCE, DIV_SYSTEM_PCE,
DIV_SYSTEM_NES, DIV_SYSTEM_NES,
DIV_SYSTEM_C64_6581, DIV_SYSTEM_C64_6581,
DIV_SYSTEM_C64_8580, DIV_SYSTEM_C64_8580,
DIV_SYSTEM_ARCADE, DIV_SYSTEM_ARCADE, // ** COMPOUND SYSTEM - DO NOT USE! **
DIV_SYSTEM_YM2610, DIV_SYSTEM_YM2610,
DIV_SYSTEM_YM2610_EXT, DIV_SYSTEM_YM2610_EXT,
@ -88,7 +88,8 @@ enum DivSystem {
DIV_SYSTEM_YM2610_FULL_EXT, DIV_SYSTEM_YM2610_FULL_EXT,
DIV_SYSTEM_OPLL_DRUMS, DIV_SYSTEM_OPLL_DRUMS,
DIV_SYSTEM_LYNX, DIV_SYSTEM_LYNX,
DIV_SYSTEM_QSOUND DIV_SYSTEM_QSOUND,
DIV_SYSTEM_SEGAPCM_COMPAT
}; };
struct DivSong { struct DivSong {
@ -278,7 +279,7 @@ struct DivSong {
DivSong(): DivSong():
version(0), version(0),
isDMF(false), isDMF(false),
systemLen(1), systemLen(2),
name(""), name(""),
author(""), author(""),
carrier(""), carrier(""),
@ -331,7 +332,8 @@ struct DivSong {
chanShow[i]=true; chanShow[i]=true;
chanCollapse[i]=false; chanCollapse[i]=false;
} }
system[0]=DIV_SYSTEM_GENESIS; system[0]=DIV_SYSTEM_YM2612;
system[1]=DIV_SYSTEM_SMS;
} }
}; };

View File

@ -131,6 +131,8 @@ DivSystem DivEngine::systemFromFile(unsigned char val) {
return DIV_SYSTEM_OPLL_DRUMS; return DIV_SYSTEM_OPLL_DRUMS;
case 0xa8: case 0xa8:
return DIV_SYSTEM_LYNX; return DIV_SYSTEM_LYNX;
case 0xa9:
return DIV_SYSTEM_SEGAPCM_COMPAT;
case 0xe0: case 0xe0:
return DIV_SYSTEM_QSOUND; return DIV_SYSTEM_QSOUND;
} }
@ -248,6 +250,8 @@ unsigned char DivEngine::systemToFile(DivSystem val) {
return 0xa7; return 0xa7;
case DIV_SYSTEM_LYNX: case DIV_SYSTEM_LYNX:
return 0xa8; return 0xa8;
case DIV_SYSTEM_SEGAPCM_COMPAT:
return 0xa9;
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return 0xe0; return 0xe0;
@ -364,6 +368,8 @@ int DivEngine::getChannelCount(DivSystem sys) {
return 11; return 11;
case DIV_SYSTEM_LYNX: case DIV_SYSTEM_LYNX:
return 4; return 4;
case DIV_SYSTEM_SEGAPCM_COMPAT:
return 5;
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return 19; return 19;
} }
@ -374,7 +380,132 @@ int DivEngine::getTotalChannelCount() {
return chans; return chans;
} }
// TODO: replace with a better strategy to determine name const char* DivEngine::getSongSystemName() {
switch (song.systemLen) {
case 0:
return "help! what's going on!";
case 1:
if (song.system[0]==DIV_SYSTEM_AY8910) {
switch (song.systemFlags[0]&0x3f) {
case 0: // AY-3-8910, 1.79MHz
case 1: // AY-3-8910, 1.77MHz
case 2: // AY-3-8910, 1.75MHz
return "ZX Spectrum";
case 3: // AY-3-8910, 2MHz
return "Fujitsu Micro-7";
case 4: // AY-3-8910, 1.5MHz
return "Vectrex";
case 5: // AY-3-8910, 1MHz
return "Amstrad CPC";
case 6: // AY-3-8910, 0.somethingMhz
return "Intellivision";
case 8: // AY-3-8910, 0.somethingMhz
return "Intellivision (PAL)";
case 0x10: // YM2149, 1.79MHz
return "MSX";
case 0x13: // YM2149, 2MHz
return "Atari ST";
case 0x26: // 5B NTSC
return "Sunsoft 5B standalone";
case 0x28: // 5B PAL
return "Sunsoft 5B standalone (PAL)";
default:
if ((song.systemFlags[0]&0x30)==0x00) {
return "AY-3-8910";
} else if ((song.systemFlags[0]&0x30)==0x10) {
return "Yamaha YM2149";
} else if ((song.systemFlags[0]&0x30)==0x20) {
return "Overclocked Sunsoft 5B";
}
}
} else if (song.system[0]==DIV_SYSTEM_SMS) {
switch (song.systemFlags[0]&0x0f) {
case 0: case 1:
return "Sega Master System";
case 6:
return "BBC Micro";
}
} else if (song.system[0]==DIV_SYSTEM_YM2612) {
switch (song.systemFlags[0]&3) {
case 2:
return "FM Towns";
}
} else if (song.system[0]==DIV_SYSTEM_YM2151) {
switch (song.systemFlags[0]&3) {
case 2:
return "Sharp X68000";
}
} else if (song.system[0]==DIV_SYSTEM_SAA1099) {
switch (song.systemFlags[0]&3) {
case 0:
return "SAM Coupé";
}
}
return getSystemName(song.system[0]);
case 2:
if (song.system[0]==DIV_SYSTEM_YM2612 && song.system[1]==DIV_SYSTEM_SMS) {
return "Sega Genesis/Mega Drive";
}
if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) {
return "Sega Genesis Extended Channel 3";
}
if (song.system[0]==DIV_SYSTEM_C64_6581 && song.system[1]==DIV_SYSTEM_C64_6581) {
return "Commodore 64 with dual 6581";
}
if (song.system[0]==DIV_SYSTEM_C64_8580 && song.system[1]==DIV_SYSTEM_C64_8580) {
return "Commodore 64 with dual 8580";
}
if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) {
return "YM2151 + SegaPCM Arcade (compatibility)";
}
if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM) {
return "YM2151 + SegaPCM Arcade";
}
if (song.system[0]==DIV_SYSTEM_SAA1099 && song.system[1]==DIV_SYSTEM_SAA1099) {
return "Creative Music System";
}
if (song.system[0]==DIV_SYSTEM_GB && song.system[1]==DIV_SYSTEM_AY8910) {
return "Game Boy with AY expansion";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC6) {
return "NES + Konami VRC6";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) {
return "NES + Konami VRC7";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_OPLL) {
return "NES + Yamaha OPLL";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) {
return "Famicom Disk System";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) {
return "NES + Namco 163";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) {
return "NES + MMC5";
}
if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_AY8910) {
return "NES + Sunsoft 5B";
}
if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910) {
return "Bally Midway MCR";
}
break;
case 3:
break;
}
return "multi-system";
}
const char* DivEngine::getSystemName(DivSystem sys) { const char* DivEngine::getSystemName(DivSystem sys) {
switch (sys) { switch (sys) {
case DIV_SYSTEM_NULL: case DIV_SYSTEM_NULL:
@ -384,7 +515,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
return "Sega Genesis/Mega Drive"; return "Sega Genesis/Mega Drive";
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
return "Sega Master System"; return "TI SN76489";
case DIV_SYSTEM_SMS_OPLL: case DIV_SYSTEM_SMS_OPLL:
return "Sega Master System + FM Expansion"; return "Sega Master System + FM Expansion";
case DIV_SYSTEM_GB: case DIV_SYSTEM_GB:
@ -431,7 +562,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL:
return "Yamaha OPLL"; return "Yamaha OPLL";
case DIV_SYSTEM_FDS: case DIV_SYSTEM_FDS:
return "Famicom Disk System"; return "Famicom Disk System (chip)";
case DIV_SYSTEM_MMC5: case DIV_SYSTEM_MMC5:
return "MMC5"; return "MMC5";
case DIV_SYSTEM_N163: case DIV_SYSTEM_N163:
@ -443,7 +574,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL:
return "Yamaha OPL"; return "Yamaha OPL";
case DIV_SYSTEM_OPL2: case DIV_SYSTEM_OPL2:
return "Adlib Music Synthesizer Card"; return "Yamaha OPL2";
case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3:
return "Yamaha OPL3"; return "Yamaha OPL3";
case DIV_SYSTEM_MULTIPCM: case DIV_SYSTEM_MULTIPCM:
@ -457,7 +588,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
case DIV_SYSTEM_SWAN: case DIV_SYSTEM_SWAN:
return "WonderSwan"; return "WonderSwan";
case DIV_SYSTEM_SAA1099: case DIV_SYSTEM_SAA1099:
return "SAM Coupé"; return "Philips SAA1099";
case DIV_SYSTEM_OPZ: case DIV_SYSTEM_OPZ:
return "Yamaha TX81Z/YS200"; return "Yamaha TX81Z/YS200";
case DIV_SYSTEM_POKEMINI: case DIV_SYSTEM_POKEMINI:
@ -488,6 +619,8 @@ const char* DivEngine::getSystemName(DivSystem sys) {
return "Yamaha OPLL with drums"; return "Yamaha OPLL with drums";
case DIV_SYSTEM_LYNX: case DIV_SYSTEM_LYNX:
return "Atari Lynx"; return "Atari Lynx";
case DIV_SYSTEM_SEGAPCM_COMPAT:
return "SegaPCM (compatible 5-channel mode)";
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return "Capcom QSound"; return "Capcom QSound";
} }
@ -607,6 +740,8 @@ const char* DivEngine::getSystemChips(DivSystem sys) {
return "Yamaha YM2413 with drums"; return "Yamaha YM2413 with drums";
case DIV_SYSTEM_LYNX: case DIV_SYSTEM_LYNX:
return "Mikey"; return "Mikey";
case DIV_SYSTEM_SEGAPCM_COMPAT:
return "SegaPCM (compatible 5-channel mode)";
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return "Capcom DL-1425"; return "Capcom DL-1425";
} }
@ -954,6 +1089,7 @@ const char* DivEngine::getChannelName(int chan) {
break; break;
case DIV_SYSTEM_MULTIPCM: case DIV_SYSTEM_MULTIPCM:
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
return chanNames[28][dispatchChanOfChan[chan]]; return chanNames[28][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_PCSPKR: case DIV_SYSTEM_PCSPKR:
@ -1088,6 +1224,7 @@ const char* DivEngine::getChannelShortName(int chan) {
break; break;
case DIV_SYSTEM_MULTIPCM: case DIV_SYSTEM_MULTIPCM:
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
return chanShortNames[28][dispatchChanOfChan[chan]]; return chanShortNames[28][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_PCSPKR: case DIV_SYSTEM_PCSPKR:
@ -1219,6 +1356,7 @@ int DivEngine::getChannelType(int chan) {
break; break;
case DIV_SYSTEM_MULTIPCM: case DIV_SYSTEM_MULTIPCM:
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return chanTypes[28][dispatchChanOfChan[chan]]; return chanTypes[28][dispatchChanOfChan[chan]];
break; break;
@ -1346,6 +1484,7 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
break; break;
case DIV_SYSTEM_MULTIPCM: case DIV_SYSTEM_MULTIPCM:
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
return chanPrefType[28][dispatchChanOfChan[chan]]; return chanPrefType[28][dispatchChanOfChan[chan]];
break; break;
@ -1401,21 +1540,21 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
bool DivEngine::isVGMExportable(DivSystem which) { bool DivEngine::isVGMExportable(DivSystem which) {
switch (which) { switch (which) {
case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_GENESIS_EXT:
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
case DIV_SYSTEM_GB: case DIV_SYSTEM_GB:
case DIV_SYSTEM_PCE: case DIV_SYSTEM_PCE:
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
case DIV_SYSTEM_ARCADE:
case DIV_SYSTEM_YM2151: case DIV_SYSTEM_YM2151:
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_AY8910: case DIV_SYSTEM_AY8910:
case DIV_SYSTEM_AY8930: case DIV_SYSTEM_AY8930:
case DIV_SYSTEM_SAA1099: case DIV_SYSTEM_SAA1099:
case DIV_SYSTEM_QSOUND: case DIV_SYSTEM_QSOUND:
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
return true; return true;
default: default:
return false; return false;

View File

@ -976,9 +976,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
if (writeQSound && qsoundMemLen>0) { if (writeQSound && qsoundMemLen>0) {
// always write a whole bank // always write a whole bank
unsigned int blockSize=(qsoundMemLen + 0xffff) & ~0xffff; unsigned int blockSize=(qsoundMemLen+0xffff)&(~0xffff);
if(blockSize > 0x1000000) if (blockSize > 0x1000000) {
blockSize = 0x1000000; blockSize = 0x1000000;
}
w->writeC(0x67); w->writeC(0x67);
w->writeC(0x66); w->writeC(0x66);
w->writeC(0x8F); w->writeC(0x8F);

View File

@ -220,12 +220,6 @@ void putDispatchChan(void* data, int chanNum, int type) {
ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- outVol: %.2x",ch->outVol);
ImGui::Text("- chVolL: %.2x",ch->chVolL); ImGui::Text("- chVolL: %.2x",ch->chVolL);
ImGui::Text("- chVolR: %.2x",ch->chVolR); 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->active?colorOn:colorOff,">> Active");
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");

View File

@ -422,12 +422,10 @@ void FurnaceGUI::setFileName(String name) {
} }
void FurnaceGUI::updateWindowTitle() { void FurnaceGUI::updateWindowTitle() {
String type=getSystemName(e->song.system[0]);
if (e->song.systemLen>1) type="multi-system";
if (e->song.name.empty()) { if (e->song.name.empty()) {
SDL_SetWindowTitle(sdlWin,fmt::sprintf("Furnace (%s)",type).c_str()); SDL_SetWindowTitle(sdlWin,fmt::sprintf("Furnace (%s)",e->getSongSystemName()).c_str());
} else { } else {
SDL_SetWindowTitle(sdlWin,fmt::sprintf("%s - Furnace (%s)",e->song.name,type).c_str()); SDL_SetWindowTitle(sdlWin,fmt::sprintf("%s - Furnace (%s)",e->song.name,e->getSongSystemName()).c_str());
} }
} }
@ -1507,9 +1505,12 @@ const char* aboutLine[]={
"", "",
"-- program --", "-- program --",
"tildearrow", "tildearrow",
"laoo",
"superctr",
"", "",
"-- graphics --", "-- graphics/UI design --",
"tildearrow", "tildearrow",
"BlastBrothers",
"", "",
"-- documentation --", "-- documentation --",
"tildearrow", "tildearrow",
@ -2098,7 +2099,7 @@ void FurnaceGUI::drawRegView() {
int size=0; int size=0;
int depth=8; int depth=8;
unsigned char* regPool=e->getRegisterPool(i,size,depth); unsigned char* regPool=e->getRegisterPool(i,size,depth);
unsigned short* regPoolW=(unsigned short*) regPool; unsigned short* regPoolW=(unsigned short*)regPool;
if (regPool==NULL) { if (regPool==NULL) {
ImGui::Text("- no register pool available"); ImGui::Text("- no register pool available");
} else { } else {
@ -2117,14 +2118,15 @@ void FurnaceGUI::drawRegView() {
for (int j=0; j<16; j++) { for (int j=0; j<16; j++) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (i*16+j>=size) continue; if (i*16+j>=size) continue;
if(depth == 8) if (depth == 8) {
ImGui::Text("%.2x",regPool[i*16+j]); ImGui::Text("%.2x",regPool[i*16+j]);
else if(depth == 16) } else if (depth == 16) {
ImGui::Text("%.4x",regPoolW[i*16+j]); ImGui::Text("%.4x",regPoolW[i*16+j]);
else } else {
ImGui::Text("??"); ImGui::Text("??");
} }
} }
}
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::PopFont(); ImGui::PopFont();
@ -3912,6 +3914,7 @@ bool dirExists(String what) {
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
if (!dirExists(workingDir)) workingDir=getHomeDir(); if (!dirExists(workingDir)) workingDir=getHomeDir();
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
switch (type) { switch (type) {
case GUI_FILE_OPEN: case GUI_FILE_OPEN:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","compatible files{.fur,.dmf},.*",workingDir); ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","compatible files{.fur,.dmf},.*",workingDir);
@ -4473,23 +4476,23 @@ bool FurnaceGUI::loop() {
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::BeginMenu("add system...")) { if (ImGui::BeginMenu("add system...")) {
sysAddOption(DIV_SYSTEM_GENESIS); sysAddOption(DIV_SYSTEM_YM2612);
sysAddOption(DIV_SYSTEM_GENESIS_EXT); sysAddOption(DIV_SYSTEM_YM2612_EXT);
sysAddOption(DIV_SYSTEM_SMS); sysAddOption(DIV_SYSTEM_SMS);
sysAddOption(DIV_SYSTEM_GB); sysAddOption(DIV_SYSTEM_GB);
sysAddOption(DIV_SYSTEM_PCE); sysAddOption(DIV_SYSTEM_PCE);
sysAddOption(DIV_SYSTEM_NES); sysAddOption(DIV_SYSTEM_NES);
sysAddOption(DIV_SYSTEM_C64_8580); sysAddOption(DIV_SYSTEM_C64_8580);
sysAddOption(DIV_SYSTEM_C64_6581); 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);
sysAddOption(DIV_SYSTEM_YM2610_EXT); sysAddOption(DIV_SYSTEM_YM2610_EXT);
sysAddOption(DIV_SYSTEM_YM2610_FULL); sysAddOption(DIV_SYSTEM_YM2610_FULL);
sysAddOption(DIV_SYSTEM_YM2610_FULL_EXT); sysAddOption(DIV_SYSTEM_YM2610_FULL_EXT);
sysAddOption(DIV_SYSTEM_AY8910); sysAddOption(DIV_SYSTEM_AY8910);
sysAddOption(DIV_SYSTEM_AMIGA); sysAddOption(DIV_SYSTEM_AMIGA);
sysAddOption(DIV_SYSTEM_YM2151);
sysAddOption(DIV_SYSTEM_YM2612);
sysAddOption(DIV_SYSTEM_TIA); sysAddOption(DIV_SYSTEM_TIA);
sysAddOption(DIV_SYSTEM_SAA1099); sysAddOption(DIV_SYSTEM_SAA1099);
sysAddOption(DIV_SYSTEM_AY8930); sysAddOption(DIV_SYSTEM_AY8930);
@ -4504,23 +4507,28 @@ bool FurnaceGUI::loop() {
bool restart=settings.restartOnFlagChange; bool restart=settings.restartOnFlagChange;
bool sysPal=flags&1; bool sysPal=flags&1;
switch (e->song.system[i]) { switch (e->song.system[i]) {
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_GENESIS_EXT: { case DIV_SYSTEM_YM2612_EXT: {
if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&3)==0)) { if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&3)==0)) {
e->setSysFlags(i,(flags&0x80000000)|0,restart); e->setSysFlags(i,(flags&0x80000000)|0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("PAL (7.61MHz)",(flags&3)==1)) { if (ImGui::RadioButton("PAL (7.61MHz)",(flags&3)==1)) {
e->setSysFlags(i,(flags&0x80000000)|1,restart); e->setSysFlags(i,(flags&0x80000000)|1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("FM Towns (8MHz)",(flags&3)==2)) { if (ImGui::RadioButton("FM Towns (8MHz)",(flags&3)==2)) {
e->setSysFlags(i,(flags&0x80000000)|2,restart); e->setSysFlags(i,(flags&0x80000000)|2,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&3)==3)) { if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&3)==3)) {
e->setSysFlags(i,(flags&0x80000000)|3,restart); e->setSysFlags(i,(flags&0x80000000)|3,restart);
updateWindowTitle();
} }
bool ladder=flags&0x80000000; bool ladder=flags&0x80000000;
if (ImGui::Checkbox("Enable DAC distortion",&ladder)) { if (ImGui::Checkbox("Enable DAC distortion",&ladder)) {
e->setSysFlags(i,(flags&(~0x80000000))|(ladder?0x80000000:0),restart); e->setSysFlags(i,(flags&(~0x80000000))|(ladder?0x80000000:0),restart);
updateWindowTitle();
} }
break; break;
} }
@ -4528,22 +4536,28 @@ bool FurnaceGUI::loop() {
ImGui::Text("Clock rate:"); ImGui::Text("Clock rate:");
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) { if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) {
e->setSysFlags(i,(flags&(~3))|0,restart); e->setSysFlags(i,(flags&(~3))|0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) { if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) {
e->setSysFlags(i,(flags&(~3))|1,restart); e->setSysFlags(i,(flags&(~3))|1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) { if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) {
e->setSysFlags(i,(flags&(~3))|2,restart); e->setSysFlags(i,(flags&(~3))|2,restart);
updateWindowTitle();
} }
ImGui::Text("Chip type:"); ImGui::Text("Chip type:");
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) { if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
e->setSysFlags(i,(flags&(~12))|0,restart); e->setSysFlags(i,(flags&(~12))|0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) { if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) {
e->setSysFlags(i,(flags&(~12))|4,restart); e->setSysFlags(i,(flags&(~12))|4,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) { if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) {
e->setSysFlags(i,(flags&(~12))|8,restart); e->setSysFlags(i,(flags&(~12))|8,restart);
updateWindowTitle();
} }
/*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) { /*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) {
e->setSysFlags(i,(flags&3)|12); e->setSysFlags(i,(flags&3)|12);
@ -4552,30 +4566,36 @@ bool FurnaceGUI::loop() {
bool noPhaseReset=flags&16; bool noPhaseReset=flags&16;
if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) { if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) {
e->setSysFlags(i,(flags&(~16))|(noPhaseReset<<4),restart); e->setSysFlags(i,(flags&(~16))|(noPhaseReset<<4),restart);
updateWindowTitle();
} }
break; break;
} }
case DIV_SYSTEM_ARCADE:
case DIV_SYSTEM_YM2151: case DIV_SYSTEM_YM2151:
if (ImGui::RadioButton("NTSC (3.58MHz)",flags==0)) { if (ImGui::RadioButton("NTSC (3.58MHz)",flags==0)) {
e->setSysFlags(i,0,restart); e->setSysFlags(i,0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) { if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) {
e->setSysFlags(i,1,restart); e->setSysFlags(i,1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("X68000 (4MHz)",flags==2)) { if (ImGui::RadioButton("X68000 (4MHz)",flags==2)) {
e->setSysFlags(i,2,restart); e->setSysFlags(i,2,restart);
updateWindowTitle();
} }
break; break;
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) { if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) {
e->setSysFlags(i,0,restart); e->setSysFlags(i,0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) { if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) {
e->setSysFlags(i,1,restart); e->setSysFlags(i,1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) { if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) {
e->setSysFlags(i,2,restart); e->setSysFlags(i,2,restart);
updateWindowTitle();
} }
break; break;
case DIV_SYSTEM_AY8910: case DIV_SYSTEM_AY8910:
@ -4583,47 +4603,60 @@ bool FurnaceGUI::loop() {
ImGui::Text("Clock rate:"); ImGui::Text("Clock rate:");
if (ImGui::RadioButton("1.79MHz (ZX Spectrum/MSX NTSC)",(flags&15)==0)) { if (ImGui::RadioButton("1.79MHz (ZX Spectrum/MSX NTSC)",(flags&15)==0)) {
e->setSysFlags(i,(flags&(~15))|0,restart); e->setSysFlags(i,(flags&(~15))|0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("1.77MHz (ZX Spectrum/MSX PAL)",(flags&15)==1)) { if (ImGui::RadioButton("1.77MHz (ZX Spectrum/MSX PAL)",(flags&15)==1)) {
e->setSysFlags(i,(flags&(~15))|1,restart); e->setSysFlags(i,(flags&(~15))|1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) { if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) {
e->setSysFlags(i,(flags&(~15))|2,restart); e->setSysFlags(i,(flags&(~15))|2,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("2MHz (Atari ST)",(flags&15)==3)) { if (ImGui::RadioButton("2MHz (Atari ST)",(flags&15)==3)) {
e->setSysFlags(i,(flags&(~15))|3,restart); e->setSysFlags(i,(flags&(~15))|3,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) { if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) {
e->setSysFlags(i,(flags&(~15))|4,restart); e->setSysFlags(i,(flags&(~15))|4,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) { if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) {
e->setSysFlags(i,(flags&(~15))|5,restart); e->setSysFlags(i,(flags&(~15))|5,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("0.89MHz (Sunsoft 5B)",(flags&15)==6)) { if (ImGui::RadioButton("0.89MHz (Sunsoft 5B)",(flags&15)==6)) {
e->setSysFlags(i,(flags&(~15))|6,restart); e->setSysFlags(i,(flags&(~15))|6,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) { if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) {
e->setSysFlags(i,(flags&(~15))|7,restart); e->setSysFlags(i,(flags&(~15))|7,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("0.83MHz (Sunsoft 5B on PAL)",(flags&15)==8)) { if (ImGui::RadioButton("0.83MHz (Sunsoft 5B on PAL)",(flags&15)==8)) {
e->setSysFlags(i,(flags&(~15))|8,restart); e->setSysFlags(i,(flags&(~15))|8,restart);
updateWindowTitle();
} }
if (e->song.system[i]==DIV_SYSTEM_AY8910) { if (e->song.system[i]==DIV_SYSTEM_AY8910) {
ImGui::Text("Chip type:"); ImGui::Text("Chip type:");
if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) { if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) {
e->setSysFlags(i,(flags&(~0x30))|0,restart); e->setSysFlags(i,(flags&(~0x30))|0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) { if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) {
e->setSysFlags(i,(flags&(~0x30))|16,restart); e->setSysFlags(i,(flags&(~0x30))|16,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) { if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) {
e->setSysFlags(i,(flags&(~0x30))|32,restart); e->setSysFlags(i,(flags&(~0x30))|32,restart);
updateWindowTitle();
} }
} }
bool stereo=flags&0x40; bool stereo=flags&0x40;
ImGui::BeginDisabled((flags&0x30)==32); ImGui::BeginDisabled((flags&0x30)==32);
if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) { if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) {
e->setSysFlags(i,(flags&(~0x40))|(stereo?0x40:0),restart); e->setSysFlags(i,(flags&(~0x40))|(stereo?0x40:0),restart);
updateWindowTitle();
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
break; break;
@ -4631,12 +4664,15 @@ bool FurnaceGUI::loop() {
case DIV_SYSTEM_SAA1099: case DIV_SYSTEM_SAA1099:
if (ImGui::RadioButton("SAM Coupé (8MHz)",flags==0)) { if (ImGui::RadioButton("SAM Coupé (8MHz)",flags==0)) {
e->setSysFlags(i,0,restart); e->setSysFlags(i,0,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("NTSC (7.15MHz)",flags==1)) { if (ImGui::RadioButton("NTSC (7.15MHz)",flags==1)) {
e->setSysFlags(i,1,restart); e->setSysFlags(i,1,restart);
updateWindowTitle();
} }
if (ImGui::RadioButton("PAL (7.09MHz)",flags==2)) { if (ImGui::RadioButton("PAL (7.09MHz)",flags==2)) {
e->setSysFlags(i,2,restart); e->setSysFlags(i,2,restart);
updateWindowTitle();
} }
break; break;
case DIV_SYSTEM_AMIGA: { case DIV_SYSTEM_AMIGA: {
@ -4646,6 +4682,7 @@ bool FurnaceGUI::loop() {
if (stereoSep<0) stereoSep=0; if (stereoSep<0) stereoSep=0;
if (stereoSep>127) stereoSep=127; if (stereoSep>127) stereoSep=127;
e->setSysFlags(i,(flags&1)|((stereoSep&127)<<8),restart); e->setSysFlags(i,(flags&1)|((stereoSep&127)<<8),restart);
updateWindowTitle();
} }
/* TODO LATER: I want 0.5 out already /* TODO LATER: I want 0.5 out already
if (ImGui::RadioButton("Amiga 500 (OCS)",(flags&2)==0)) { if (ImGui::RadioButton("Amiga 500 (OCS)",(flags&2)==0)) {
@ -4657,6 +4694,7 @@ bool FurnaceGUI::loop() {
sysPal=flags&1; sysPal=flags&1;
if (ImGui::Checkbox("PAL",&sysPal)) { if (ImGui::Checkbox("PAL",&sysPal)) {
e->setSysFlags(i,(flags&2)|sysPal,restart); e->setSysFlags(i,(flags&2)|sysPal,restart);
updateWindowTitle();
} }
break; break;
} }
@ -4667,6 +4705,7 @@ bool FurnaceGUI::loop() {
if (echoBufSize<0) echoBufSize=0; if (echoBufSize<0) echoBufSize=0;
if (echoBufSize>2725) echoBufSize=2725; if (echoBufSize>2725) echoBufSize=2725;
e->setSysFlags(i,(flags & ~4095) | ((2725 - echoBufSize) & 4095),restart); e->setSysFlags(i,(flags & ~4095) | ((2725 - echoBufSize) & 4095),restart);
updateWindowTitle();
} }
ImGui::Text("Echo feedback:"); ImGui::Text("Echo feedback:");
int echoFeedback=(flags>>12)&255; int echoFeedback=(flags>>12)&255;
@ -4674,6 +4713,7 @@ bool FurnaceGUI::loop() {
if (echoFeedback<0) echoFeedback=0; if (echoFeedback<0) echoFeedback=0;
if (echoFeedback>255) echoFeedback=255; if (echoFeedback>255) echoFeedback=255;
e->setSysFlags(i,(flags & ~(255 << 12)) | ((echoFeedback & 255) << 12),restart); e->setSysFlags(i,(flags & ~(255 << 12)) | ((echoFeedback & 255) << 12),restart);
updateWindowTitle();
} }
break; break;
} }
@ -4688,6 +4728,7 @@ bool FurnaceGUI::loop() {
default: default:
if (ImGui::Checkbox("PAL",&sysPal)) { if (ImGui::Checkbox("PAL",&sysPal)) {
e->setSysFlags(i,sysPal,restart); e->setSysFlags(i,sysPal,restart);
updateWindowTitle();
} }
break; break;
} }
@ -4699,23 +4740,23 @@ bool FurnaceGUI::loop() {
if (ImGui::BeginMenu("change system...")) { if (ImGui::BeginMenu("change system...")) {
for (int i=0; i<e->song.systemLen; i++) { 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())) { 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_YM2612);
sysChangeOption(i,DIV_SYSTEM_GENESIS_EXT); sysChangeOption(i,DIV_SYSTEM_YM2612_EXT);
sysChangeOption(i,DIV_SYSTEM_SMS); sysChangeOption(i,DIV_SYSTEM_SMS);
sysChangeOption(i,DIV_SYSTEM_GB); sysChangeOption(i,DIV_SYSTEM_GB);
sysChangeOption(i,DIV_SYSTEM_PCE); sysChangeOption(i,DIV_SYSTEM_PCE);
sysChangeOption(i,DIV_SYSTEM_NES); sysChangeOption(i,DIV_SYSTEM_NES);
sysChangeOption(i,DIV_SYSTEM_C64_8580); sysChangeOption(i,DIV_SYSTEM_C64_8580);
sysChangeOption(i,DIV_SYSTEM_C64_6581); 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);
sysChangeOption(i,DIV_SYSTEM_YM2610_EXT); sysChangeOption(i,DIV_SYSTEM_YM2610_EXT);
sysChangeOption(i,DIV_SYSTEM_YM2610_FULL); sysChangeOption(i,DIV_SYSTEM_YM2610_FULL);
sysChangeOption(i,DIV_SYSTEM_YM2610_FULL_EXT); sysChangeOption(i,DIV_SYSTEM_YM2610_FULL_EXT);
sysChangeOption(i,DIV_SYSTEM_AY8910); sysChangeOption(i,DIV_SYSTEM_AY8910);
sysChangeOption(i,DIV_SYSTEM_AMIGA); sysChangeOption(i,DIV_SYSTEM_AMIGA);
sysChangeOption(i,DIV_SYSTEM_YM2151);
sysChangeOption(i,DIV_SYSTEM_YM2612);
sysChangeOption(i,DIV_SYSTEM_TIA); sysChangeOption(i,DIV_SYSTEM_TIA);
sysChangeOption(i,DIV_SYSTEM_SAA1099); sysChangeOption(i,DIV_SYSTEM_SAA1099);
sysChangeOption(i,DIV_SYSTEM_AY8930); sysChangeOption(i,DIV_SYSTEM_AY8930);

View File

@ -24,6 +24,7 @@
#include "guiConst.h" #include "guiConst.h"
#include "intConst.h" #include "intConst.h"
#include <fmt/printf.h> #include <fmt/printf.h>
#include <imgui.h>
#include "plot_nolerp.h" #include "plot_nolerp.h"
const char* insTypes[24]={ const char* insTypes[24]={
@ -786,29 +787,103 @@ void FurnaceGUI::drawInsEdit() {
//56.0 controls vert scaling; default 96 //56.0 controls vert scaling; default 96
drawFMEnv(op.tl,op.ar,op.dr,op.d2r,op.rr,op.sl,ImVec2(ImGui::GetContentRegionAvail().x,56.0*dpiScale)); drawFMEnv(op.tl,op.ar,op.dr,op.d2r,op.rr,op.sl,ImVec2(ImGui::GetContentRegionAvail().x,56.0*dpiScale));
//P(ImGui::SliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); //P(ImGui::SliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE));
P(ImGui::SliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_THIRTY_ONE,&_ZERO)); if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) {
P(ImGui::SliderScalar(FM_NAME(FM_DR),ImGuiDataType_U8,&op.dr,&_THIRTY_ONE,&_ZERO)); ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \
P(ImGui::SliderScalar(FM_NAME(FM_SL),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \
P(ImGui::SliderScalar(FM_NAME(FM_D2R),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
P(ImGui::SliderScalar(FM_NAME(FM_RR),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
P(ImGui::SliderScalar(FM_NAME(FM_TL),ImGuiDataType_U8,&op.tl,&_ONE_HUNDRED_TWENTY_SEVEN,&_ZERO));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##AR",ImGuiDataType_U8,&op.ar,&_THIRTY_ONE,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_AR));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##DR",ImGuiDataType_U8,&op.dr,&_THIRTY_ONE,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DR));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SL));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_D2R));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_RR));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##TL",ImGuiDataType_U8,&op.tl,&_ONE_HUNDRED_TWENTY_SEVEN,&_ZERO));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_TL));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Separator();
ImGui::TableNextColumn();
ImGui::Separator(); ImGui::Separator();
P(ImGui::SliderScalar(FM_NAME(FM_RS),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_RS));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); P(ImGui::SliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_MULT));
int detune=(op.dt&7)-3; int detune=(op.dt&7)-3;
if (ImGui::SliderInt(FM_NAME(FM_DT),&detune,-3,3)) { PARAMETER ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::SliderInt("##DT",&detune,-3,3)) { PARAMETER
op.dt=detune+3; op.dt=detune+3;
} }
P(ImGui::SliderScalar(FM_NAME(FM_DT2),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE));
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only for Arcade system"); ImGui::SetTooltip("Only for Arcade system");
} }
if (ImGui::SliderScalar(FM_NAME(FM_SSG),ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT2));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::SliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
} }
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
ImGui::EndTable();
}
ImGui::PopID(); ImGui::PopID();
} }
ImGui::EndTable(); ImGui::EndTable();