mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 17:25:06 +00:00
force update
This commit is contained in:
parent
9237a0f6fa
commit
1c33fe0edb
23 changed files with 1286 additions and 646 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
|
||||
|
|
BIN
demos/m7 vibe.fur
Normal file
BIN
demos/m7 vibe.fur
Normal file
Binary file not shown.
7
extern/igfd/ImGuiFileDialog.cpp
vendored
7
extern/igfd/ImGuiFileDialog.cpp
vendored
|
@ -1105,7 +1105,7 @@ namespace IGFD
|
|||
|
||||
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))
|
||||
{
|
||||
intptr_t i = 0;
|
||||
|
@ -3279,7 +3279,7 @@ namespace IGFD
|
|||
//// FILE DIALOG CONSTRUCTOR / DESTRUCTOR ///////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {}
|
||||
IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {DpiScale=1.0f;}
|
||||
IGFD::FileDialog::~FileDialog() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3827,8 +3827,9 @@ namespace IGFD
|
|||
|
||||
// Input file fields
|
||||
float width = ImGui::GetContentRegionAvail().x;
|
||||
// fix this! fix this! fix this!
|
||||
if (!fdFile.puDLGDirectoryMode)
|
||||
width -= FILTER_COMBO_WIDTH;
|
||||
width -= FILTER_COMBO_WIDTH*DpiScale;
|
||||
ImGui::PushItemWidth(width);
|
||||
ImGui::InputText("##FileName", fdFile.puFileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
|
||||
if (ImGui::GetItemID() == ImGui::GetActiveID())
|
||||
|
|
1
extern/igfd/ImGuiFileDialog.h
vendored
1
extern/igfd/ImGuiFileDialog.h
vendored
|
@ -1133,6 +1133,7 @@ namespace IGFD
|
|||
|
||||
public:
|
||||
bool puAnyWindowsHovered = false; // not remember why haha :) todo : to check if we can remove
|
||||
double DpiScale;
|
||||
|
||||
public:
|
||||
static FileDialog* Instance() // Singleton for easier accces form anywhere but only one dialog at a time
|
||||
|
|
|
@ -225,7 +225,7 @@ class DivDispatch {
|
|||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
virtual int getRegisterPoolDepth();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -437,11 +437,11 @@ void DivEngine::notifyWaveChange(int wave) {
|
|||
// ADPCM code attribution: https://wiki.neogeodev.org/index.php?title=ADPCM_codecs
|
||||
|
||||
static short adSteps[49]={
|
||||
16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
|
||||
41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
|
||||
107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
|
||||
279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
||||
16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
|
||||
41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
|
||||
107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
|
||||
279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
||||
};
|
||||
|
||||
static int adStepSeek[16]={
|
||||
|
@ -606,9 +606,10 @@ void DivEngine::renderSamples() {
|
|||
memPos=0;
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* s=song.sample[i];
|
||||
int length = s->rendLength;
|
||||
if(length > 65536-16)
|
||||
length = 65536-16;
|
||||
int length = s->rendLength;
|
||||
if (length > 65536-16) {
|
||||
length = 65536-16;
|
||||
}
|
||||
if ((memPos&0xff0000)!=((memPos+length)&0xff0000)) {
|
||||
memPos=(memPos+0xffff)&0xff0000;
|
||||
}
|
||||
|
@ -617,16 +618,14 @@ void DivEngine::renderSamples() {
|
|||
break;
|
||||
}
|
||||
if (memPos+length>=16777216) {
|
||||
for(unsigned int i=0; i<16777216-(memPos+length); i++)
|
||||
{
|
||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
||||
}
|
||||
for (unsigned int i=0; i<16777216-(memPos+length); i++) {
|
||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
||||
}
|
||||
logW("out of QSound PCM memory for sample %d!\n",i);
|
||||
} else {
|
||||
for(int i=0; i<length; i++)
|
||||
{
|
||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
||||
}
|
||||
for (int i=0; i<length; i++) {
|
||||
qsoundMem[(memPos + i) ^ 0x8000] = s->rendData[i] >> ((s->depth == 16) ? 8 : 0);
|
||||
}
|
||||
}
|
||||
s->rendOffQsound=memPos ^ 0x8000;
|
||||
memPos+=length+16;
|
||||
|
@ -1024,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;
|
||||
|
|
|
@ -365,6 +365,9 @@ class DivEngine {
|
|||
// get preferred instrument type
|
||||
DivInstrumentType getPreferInsType(int ch);
|
||||
|
||||
// get song system name
|
||||
const char* getSongSystemName();
|
||||
|
||||
// get sys name
|
||||
const char* getSystemName(DivSystem sys);
|
||||
|
||||
|
@ -684,7 +687,7 @@ class DivEngine {
|
|||
adpcmMemLen(0),
|
||||
adpcmBMem(NULL),
|
||||
adpcmBMemLen(0),
|
||||
qsoundMem(NULL),
|
||||
qsoundMemLen(0) {}
|
||||
qsoundMem(NULL),
|
||||
qsoundMemLen(0) {}
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -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());
|
||||
|
@ -1394,15 +1447,28 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
lastError="invalid version to save in! this is a bug!";
|
||||
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
|
||||
// TODO: fix this mess for the flattening in 0.6
|
||||
if (!(song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL)) {
|
||||
if (song.systemLen!=1) {
|
||||
if (!isFlat && song.systemLen!=1) {
|
||||
logE("cannot save multiple systems in this format!\n");
|
||||
lastError="multiple systems not possible on .dmf";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// fail if this is an YMU759 song
|
||||
if (song.system[0]==DIV_SYSTEM_YMU759) {
|
||||
logE("cannot save YMU759 song!\n");
|
||||
|
@ -1416,7 +1482,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
return NULL;
|
||||
}
|
||||
// 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");
|
||||
lastError="this system is not possible on .dmf";
|
||||
return NULL;
|
||||
|
@ -1432,7 +1498,16 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
// version
|
||||
w->writeC(version);
|
||||
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));
|
||||
sys=DIV_SYSTEM_SMS_OPLL;
|
||||
} else {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
#define _LYNX_H
|
||||
|
||||
|
|
|
@ -30,219 +30,219 @@
|
|||
#define immWrite(a,v) {qsound_write_data(&chip,a,v); if(dumpWrites) addWrite(a,v);}
|
||||
|
||||
const char* regCheatSheetQSound[]={
|
||||
"Ch15_Bank", "00",
|
||||
"Ch00_Start", "01",
|
||||
"Ch00_Freq", "02",
|
||||
"Ch00_Phase", "03",
|
||||
"Ch00_Loop", "04",
|
||||
"Ch00_End", "05",
|
||||
"Ch00_Volume", "06",
|
||||
"Ch00_Bank", "08",
|
||||
"Ch01_Start", "09",
|
||||
"Ch01_Freq", "0A",
|
||||
"Ch01_Phase", "0B",
|
||||
"Ch01_Loop", "0C",
|
||||
"Ch01_End", "0D",
|
||||
"Ch01_Volume", "0E",
|
||||
"Ch01_Bank", "10",
|
||||
"Ch02_Start", "11",
|
||||
"Ch02_Freq", "12",
|
||||
"Ch02_Phase", "13",
|
||||
"Ch02_Loop", "14",
|
||||
"Ch02_End", "15",
|
||||
"Ch02_Volume", "16",
|
||||
"Ch02_Bank", "18",
|
||||
"Ch03_Start", "19",
|
||||
"Ch03_Freq", "1A",
|
||||
"Ch03_Phase", "1B",
|
||||
"Ch03_Loop", "1C",
|
||||
"Ch03_End", "1D",
|
||||
"Ch03_Volume", "1E",
|
||||
"Ch03_Bank", "20",
|
||||
"Ch04_Start", "21",
|
||||
"Ch04_Freq", "22",
|
||||
"Ch04_Phase", "23",
|
||||
"Ch04_Loop", "24",
|
||||
"Ch04_End", "25",
|
||||
"Ch04_Volume", "26",
|
||||
"Ch04_Bank", "28",
|
||||
"Ch05_Start", "29",
|
||||
"Ch05_Freq", "2A",
|
||||
"Ch05_Phase", "2B",
|
||||
"Ch05_Loop", "2C",
|
||||
"Ch05_End", "2D",
|
||||
"Ch05_Volume", "2E",
|
||||
"Ch05_Bank", "30",
|
||||
"Ch06_Start", "31",
|
||||
"Ch06_Freq", "32",
|
||||
"Ch06_Phase", "33",
|
||||
"Ch06_Loop", "34",
|
||||
"Ch06_End", "35",
|
||||
"Ch06_Volume", "36",
|
||||
"Ch06_Bank", "38",
|
||||
"Ch07_Start", "39",
|
||||
"Ch07_Freq", "3A",
|
||||
"Ch07_Phase", "3B",
|
||||
"Ch07_Loop", "3C",
|
||||
"Ch07_End", "3D",
|
||||
"Ch07_Volume", "3E",
|
||||
"Ch07_Bank", "40",
|
||||
"Ch08_Start", "41",
|
||||
"Ch08_Freq", "42",
|
||||
"Ch08_Phase", "43",
|
||||
"Ch08_Loop", "44",
|
||||
"Ch08_End", "45",
|
||||
"Ch08_Volume", "46",
|
||||
"Ch08_Bank", "48",
|
||||
"Ch09_Start", "49",
|
||||
"Ch09_Freq", "4A",
|
||||
"Ch09_Phase", "4B",
|
||||
"Ch09_Loop", "4C",
|
||||
"Ch09_End", "4D",
|
||||
"Ch09_Volume", "4E",
|
||||
"Ch09_Bank", "50",
|
||||
"Ch10_Start", "51",
|
||||
"Ch10_Freq", "52",
|
||||
"Ch10_Phase", "53",
|
||||
"Ch10_Loop", "54",
|
||||
"Ch10_End", "55",
|
||||
"Ch10_Volume", "56",
|
||||
"Ch10_Bank", "58",
|
||||
"Ch11_Start", "59",
|
||||
"Ch11_Freq", "5A",
|
||||
"Ch11_Phase", "5B",
|
||||
"Ch11_Loop", "5C",
|
||||
"Ch11_End", "5D",
|
||||
"Ch11_Volume", "5E",
|
||||
"Ch11_Bank", "60",
|
||||
"Ch12_Start", "61",
|
||||
"Ch12_Freq", "62",
|
||||
"Ch12_Phase", "63",
|
||||
"Ch12_Loop", "64",
|
||||
"Ch12_End", "65",
|
||||
"Ch12_Volume", "66",
|
||||
"Ch12_Bank", "68",
|
||||
"Ch13_Start", "69",
|
||||
"Ch13_Freq", "6A",
|
||||
"Ch13_Phase", "6B",
|
||||
"Ch13_Loop", "6C",
|
||||
"Ch13_End", "6D",
|
||||
"Ch13_Volume", "6E",
|
||||
"Ch13_Bank", "70",
|
||||
"Ch14_Start", "71",
|
||||
"Ch14_Freq", "72",
|
||||
"Ch14_Phase", "73",
|
||||
"Ch14_Loop", "74",
|
||||
"Ch14_End", "75",
|
||||
"Ch14_Volume", "76",
|
||||
"Ch14_Bank", "78",
|
||||
"Ch15_Start", "79",
|
||||
"Ch15_Freq", "7A",
|
||||
"Ch15_Phase", "7B",
|
||||
"Ch15_Loop", "7C",
|
||||
"Ch15_End", "7D",
|
||||
"Ch15_Volume", "7E",
|
||||
"Ch00_Panning", "80",
|
||||
"Ch01_Panning", "81",
|
||||
"Ch02_Panning", "82",
|
||||
"Ch03_Panning", "83",
|
||||
"Ch04_Panning", "84",
|
||||
"Ch05_Panning", "85",
|
||||
"Ch06_Panning", "86",
|
||||
"Ch07_Panning", "87",
|
||||
"Ch08_Panning", "88",
|
||||
"Ch09_Panning", "89",
|
||||
"Ch10_Panning", "8A",
|
||||
"Ch11_Panning", "8B",
|
||||
"Ch12_Panning", "8C",
|
||||
"Ch13_Panning", "8D",
|
||||
"Ch14_Panning", "8E",
|
||||
"Ch15_Panning", "8F",
|
||||
"Adpcm0_Panning","90",
|
||||
"Adpcm1_Panning","91",
|
||||
"Adpcm2_Panning","92",
|
||||
"Echo_Feedback","93",
|
||||
"Ch00_Echo", "BA",
|
||||
"Ch01_Echo", "BB",
|
||||
"Ch02_Echo", "BC",
|
||||
"Ch03_Echo", "BD",
|
||||
"Ch04_Echo", "BE",
|
||||
"Ch05_Echo", "BF",
|
||||
"Ch06_Echo", "C0",
|
||||
"Ch07_Echo", "C1",
|
||||
"Ch08_Echo", "C2",
|
||||
"Ch09_Echo", "C3",
|
||||
"Ch10_Echo", "C4",
|
||||
"Ch11_Echo", "C5",
|
||||
"Ch12_Echo", "C6",
|
||||
"Ch13_Echo", "C7",
|
||||
"Ch14_Echo", "C8",
|
||||
"Ch15_Echo", "C9",
|
||||
"Adpcm0_Start", "CA",
|
||||
"Adpcm0_End", "CB",
|
||||
"Adpcm0_Bank", "CC",
|
||||
"Adpcm0_Volume","CD",
|
||||
"Adpcm1_Start", "CE",
|
||||
"Adpcm1_End", "CF",
|
||||
"Adpcm1_Bank", "D0",
|
||||
"Adpcm1_Volume","D1",
|
||||
"Adpcm2_Start", "D2",
|
||||
"Adpcm2_End", "D3",
|
||||
"Adpcm2_Bank", "D4",
|
||||
"Adpcm2_Volume","D5",
|
||||
"Adpcm0_KeyOn", "D6",
|
||||
"Adpcm1_KeyOn", "D7",
|
||||
"Adpcm2_KeyOn", "D8",
|
||||
"Echo_Delay", "D9",
|
||||
"L_Wet_Filter", "DA",
|
||||
"L_Dry_Filter", "DB",
|
||||
"R_Wet_Filter", "DC",
|
||||
"R_Dry_Filter", "DD",
|
||||
"L_Wet_Delay", "DE",
|
||||
"L_Dry_Delay", "DF",
|
||||
"R_Wet_Delay", "E0",
|
||||
"R_Dry_Delay", "E1",
|
||||
"Delay_Flag", "E2",
|
||||
"Mode_Select", "E3", //valid: 0000,0288,0039,061A,004F
|
||||
"L_Wet_Volume", "E4",
|
||||
"L_Dry_Volume", "E5",
|
||||
"R_Wet_Volume", "E6",
|
||||
"R_Dry_Volume", "E7",
|
||||
NULL
|
||||
"Ch15_Bank", "00",
|
||||
"Ch00_Start", "01",
|
||||
"Ch00_Freq", "02",
|
||||
"Ch00_Phase", "03",
|
||||
"Ch00_Loop", "04",
|
||||
"Ch00_End", "05",
|
||||
"Ch00_Volume", "06",
|
||||
"Ch00_Bank", "08",
|
||||
"Ch01_Start", "09",
|
||||
"Ch01_Freq", "0A",
|
||||
"Ch01_Phase", "0B",
|
||||
"Ch01_Loop", "0C",
|
||||
"Ch01_End", "0D",
|
||||
"Ch01_Volume", "0E",
|
||||
"Ch01_Bank", "10",
|
||||
"Ch02_Start", "11",
|
||||
"Ch02_Freq", "12",
|
||||
"Ch02_Phase", "13",
|
||||
"Ch02_Loop", "14",
|
||||
"Ch02_End", "15",
|
||||
"Ch02_Volume", "16",
|
||||
"Ch02_Bank", "18",
|
||||
"Ch03_Start", "19",
|
||||
"Ch03_Freq", "1A",
|
||||
"Ch03_Phase", "1B",
|
||||
"Ch03_Loop", "1C",
|
||||
"Ch03_End", "1D",
|
||||
"Ch03_Volume", "1E",
|
||||
"Ch03_Bank", "20",
|
||||
"Ch04_Start", "21",
|
||||
"Ch04_Freq", "22",
|
||||
"Ch04_Phase", "23",
|
||||
"Ch04_Loop", "24",
|
||||
"Ch04_End", "25",
|
||||
"Ch04_Volume", "26",
|
||||
"Ch04_Bank", "28",
|
||||
"Ch05_Start", "29",
|
||||
"Ch05_Freq", "2A",
|
||||
"Ch05_Phase", "2B",
|
||||
"Ch05_Loop", "2C",
|
||||
"Ch05_End", "2D",
|
||||
"Ch05_Volume", "2E",
|
||||
"Ch05_Bank", "30",
|
||||
"Ch06_Start", "31",
|
||||
"Ch06_Freq", "32",
|
||||
"Ch06_Phase", "33",
|
||||
"Ch06_Loop", "34",
|
||||
"Ch06_End", "35",
|
||||
"Ch06_Volume", "36",
|
||||
"Ch06_Bank", "38",
|
||||
"Ch07_Start", "39",
|
||||
"Ch07_Freq", "3A",
|
||||
"Ch07_Phase", "3B",
|
||||
"Ch07_Loop", "3C",
|
||||
"Ch07_End", "3D",
|
||||
"Ch07_Volume", "3E",
|
||||
"Ch07_Bank", "40",
|
||||
"Ch08_Start", "41",
|
||||
"Ch08_Freq", "42",
|
||||
"Ch08_Phase", "43",
|
||||
"Ch08_Loop", "44",
|
||||
"Ch08_End", "45",
|
||||
"Ch08_Volume", "46",
|
||||
"Ch08_Bank", "48",
|
||||
"Ch09_Start", "49",
|
||||
"Ch09_Freq", "4A",
|
||||
"Ch09_Phase", "4B",
|
||||
"Ch09_Loop", "4C",
|
||||
"Ch09_End", "4D",
|
||||
"Ch09_Volume", "4E",
|
||||
"Ch09_Bank", "50",
|
||||
"Ch10_Start", "51",
|
||||
"Ch10_Freq", "52",
|
||||
"Ch10_Phase", "53",
|
||||
"Ch10_Loop", "54",
|
||||
"Ch10_End", "55",
|
||||
"Ch10_Volume", "56",
|
||||
"Ch10_Bank", "58",
|
||||
"Ch11_Start", "59",
|
||||
"Ch11_Freq", "5A",
|
||||
"Ch11_Phase", "5B",
|
||||
"Ch11_Loop", "5C",
|
||||
"Ch11_End", "5D",
|
||||
"Ch11_Volume", "5E",
|
||||
"Ch11_Bank", "60",
|
||||
"Ch12_Start", "61",
|
||||
"Ch12_Freq", "62",
|
||||
"Ch12_Phase", "63",
|
||||
"Ch12_Loop", "64",
|
||||
"Ch12_End", "65",
|
||||
"Ch12_Volume", "66",
|
||||
"Ch12_Bank", "68",
|
||||
"Ch13_Start", "69",
|
||||
"Ch13_Freq", "6A",
|
||||
"Ch13_Phase", "6B",
|
||||
"Ch13_Loop", "6C",
|
||||
"Ch13_End", "6D",
|
||||
"Ch13_Volume", "6E",
|
||||
"Ch13_Bank", "70",
|
||||
"Ch14_Start", "71",
|
||||
"Ch14_Freq", "72",
|
||||
"Ch14_Phase", "73",
|
||||
"Ch14_Loop", "74",
|
||||
"Ch14_End", "75",
|
||||
"Ch14_Volume", "76",
|
||||
"Ch14_Bank", "78",
|
||||
"Ch15_Start", "79",
|
||||
"Ch15_Freq", "7A",
|
||||
"Ch15_Phase", "7B",
|
||||
"Ch15_Loop", "7C",
|
||||
"Ch15_End", "7D",
|
||||
"Ch15_Volume", "7E",
|
||||
"Ch00_Panning", "80",
|
||||
"Ch01_Panning", "81",
|
||||
"Ch02_Panning", "82",
|
||||
"Ch03_Panning", "83",
|
||||
"Ch04_Panning", "84",
|
||||
"Ch05_Panning", "85",
|
||||
"Ch06_Panning", "86",
|
||||
"Ch07_Panning", "87",
|
||||
"Ch08_Panning", "88",
|
||||
"Ch09_Panning", "89",
|
||||
"Ch10_Panning", "8A",
|
||||
"Ch11_Panning", "8B",
|
||||
"Ch12_Panning", "8C",
|
||||
"Ch13_Panning", "8D",
|
||||
"Ch14_Panning", "8E",
|
||||
"Ch15_Panning", "8F",
|
||||
"Adpcm0_Panning","90",
|
||||
"Adpcm1_Panning","91",
|
||||
"Adpcm2_Panning","92",
|
||||
"Echo_Feedback","93",
|
||||
"Ch00_Echo", "BA",
|
||||
"Ch01_Echo", "BB",
|
||||
"Ch02_Echo", "BC",
|
||||
"Ch03_Echo", "BD",
|
||||
"Ch04_Echo", "BE",
|
||||
"Ch05_Echo", "BF",
|
||||
"Ch06_Echo", "C0",
|
||||
"Ch07_Echo", "C1",
|
||||
"Ch08_Echo", "C2",
|
||||
"Ch09_Echo", "C3",
|
||||
"Ch10_Echo", "C4",
|
||||
"Ch11_Echo", "C5",
|
||||
"Ch12_Echo", "C6",
|
||||
"Ch13_Echo", "C7",
|
||||
"Ch14_Echo", "C8",
|
||||
"Ch15_Echo", "C9",
|
||||
"Adpcm0_Start", "CA",
|
||||
"Adpcm0_End", "CB",
|
||||
"Adpcm0_Bank", "CC",
|
||||
"Adpcm0_Volume","CD",
|
||||
"Adpcm1_Start", "CE",
|
||||
"Adpcm1_End", "CF",
|
||||
"Adpcm1_Bank", "D0",
|
||||
"Adpcm1_Volume","D1",
|
||||
"Adpcm2_Start", "D2",
|
||||
"Adpcm2_End", "D3",
|
||||
"Adpcm2_Bank", "D4",
|
||||
"Adpcm2_Volume","D5",
|
||||
"Adpcm0_KeyOn", "D6",
|
||||
"Adpcm1_KeyOn", "D7",
|
||||
"Adpcm2_KeyOn", "D8",
|
||||
"Echo_Delay", "D9",
|
||||
"L_Wet_Filter", "DA",
|
||||
"L_Dry_Filter", "DB",
|
||||
"R_Wet_Filter", "DC",
|
||||
"R_Dry_Filter", "DD",
|
||||
"L_Wet_Delay", "DE",
|
||||
"L_Dry_Delay", "DF",
|
||||
"R_Wet_Delay", "E0",
|
||||
"R_Dry_Delay", "E1",
|
||||
"Delay_Flag", "E2",
|
||||
"Mode_Select", "E3", //valid: 0000,0288,0039,061A,004F
|
||||
"L_Wet_Volume", "E4",
|
||||
"L_Dry_Volume", "E5",
|
||||
"R_Wet_Volume", "E6",
|
||||
"R_Dry_Volume", "E7",
|
||||
NULL
|
||||
};
|
||||
enum q1_register_name {
|
||||
Q1V_BANK = 0,
|
||||
Q1V_START = 1,
|
||||
Q1V_FREQ = 2,
|
||||
Q1V_PHASE = 3,
|
||||
Q1V_LOOP = 4,
|
||||
Q1V_END = 5,
|
||||
Q1V_VOL = 6,
|
||||
Q1V_REG_COUNT = 7,
|
||||
Q1V_BANK = 0,
|
||||
Q1V_START = 1,
|
||||
Q1V_FREQ = 2,
|
||||
Q1V_PHASE = 3,
|
||||
Q1V_LOOP = 4,
|
||||
Q1V_END = 5,
|
||||
Q1V_VOL = 6,
|
||||
Q1V_REG_COUNT = 7,
|
||||
|
||||
Q1_PAN = 0x80,
|
||||
Q1_ECHO = 0xba,
|
||||
Q1_PAN = 0x80,
|
||||
Q1_ECHO = 0xba,
|
||||
|
||||
Q1A_PAN = 0x90,
|
||||
Q1A_START = 0xca,
|
||||
Q1A_END = 0xcb,
|
||||
Q1A_BANK = 0xcc,
|
||||
Q1A_VOL = 0xcd,
|
||||
Q1A_PAN = 0x90,
|
||||
Q1A_START = 0xca,
|
||||
Q1A_END = 0xcb,
|
||||
Q1A_BANK = 0xcc,
|
||||
Q1A_VOL = 0xcd,
|
||||
|
||||
Q1A_KEYON = 0xd6,
|
||||
Q1A_KEYON = 0xd6,
|
||||
|
||||
Q1_ECHO_FEEDBACK = 0x93,
|
||||
Q1_ECHO_LENGTH = 0xd9,
|
||||
Q1_ECHO_FEEDBACK = 0x93,
|
||||
Q1_ECHO_LENGTH = 0xd9,
|
||||
};
|
||||
|
||||
const unsigned char q1_reg_map[Q1V_REG_COUNT][16] = {
|
||||
{0x78,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70},
|
||||
{0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39,0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79},
|
||||
{0x02,0x0a,0x12,0x1a,0x22,0x2a,0x32,0x3a,0x42,0x4a,0x52,0x5a,0x62,0x6a,0x72,0x7a},
|
||||
{0x03,0x0b,0x13,0x1b,0x23,0x2b,0x33,0x3b,0x43,0x4b,0x53,0x5b,0x63,0x6b,0x73,0x7b},
|
||||
{0x04,0x0c,0x14,0x1c,0x24,0x2c,0x34,0x3c,0x44,0x4c,0x54,0x5c,0x64,0x6c,0x74,0x7c},
|
||||
{0x05,0x0d,0x15,0x1d,0x25,0x2d,0x35,0x3d,0x45,0x4d,0x55,0x5d,0x65,0x6d,0x75,0x7d},
|
||||
{0x06,0x0e,0x16,0x1e,0x26,0x2e,0x36,0x3e,0x46,0x4e,0x56,0x5e,0x66,0x6e,0x76,0x7e},
|
||||
{0x78,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70},
|
||||
{0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39,0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79},
|
||||
{0x02,0x0a,0x12,0x1a,0x22,0x2a,0x32,0x3a,0x42,0x4a,0x52,0x5a,0x62,0x6a,0x72,0x7a},
|
||||
{0x03,0x0b,0x13,0x1b,0x23,0x2b,0x33,0x3b,0x43,0x4b,0x53,0x5b,0x63,0x6b,0x73,0x7b},
|
||||
{0x04,0x0c,0x14,0x1c,0x24,0x2c,0x34,0x3c,0x44,0x4c,0x54,0x5c,0x64,0x6c,0x74,0x7c},
|
||||
{0x05,0x0d,0x15,0x1d,0x25,0x2d,0x35,0x3d,0x45,0x4d,0x55,0x5d,0x65,0x6d,0x75,0x7d},
|
||||
{0x06,0x0e,0x16,0x1e,0x26,0x2e,0x36,0x3e,0x46,0x4e,0x56,0x5e,0x66,0x6e,0x76,0x7e},
|
||||
};
|
||||
|
||||
const char** DivPlatformQSound::getRegisterSheet() {
|
||||
|
@ -258,8 +258,9 @@ const char* DivPlatformQSound::getEffectName(unsigned char effect) {
|
|||
return "11xx: Set channel echo level (00 to FF)";
|
||||
break;
|
||||
default:
|
||||
if((effect & 0xf0) == 0x30)
|
||||
return "3xxx: Set echo delay buffer length (000 to AA5)";
|
||||
if ((effect & 0xf0) == 0x30) {
|
||||
return "3xxx: Set echo delay buffer length (000 to AA5)";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -267,7 +268,7 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
chip.rom_data = parent->qsoundMem;
|
||||
chip.rom_mask = 0xffffff;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
qsound_update(&chip);
|
||||
qsound_update(&chip);
|
||||
bufL[h]=chip.out[0];
|
||||
bufR[h]=chip.out[1];
|
||||
}
|
||||
|
@ -277,18 +278,16 @@ void DivPlatformQSound::tick() {
|
|||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.hadVol) {
|
||||
chan[i].outVol=((chan[i].vol%256)*MIN(255,chan[i].std.vol << 2))>>8;
|
||||
// Check if enabled and write volume
|
||||
if(chan[i].active)
|
||||
{
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 5);
|
||||
//logW("ch %d vol=%04x (hadVol)!\n",i,chan[i].outVol << 5);
|
||||
}
|
||||
chan[i].outVol=((chan[i].vol&0xff)*MIN(255,chan[i].std.vol<<2))>>8;
|
||||
// Check if enabled and write volume
|
||||
if (chan[i].active) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4);
|
||||
}
|
||||
}
|
||||
uint16_t qsound_bank = 0;
|
||||
uint16_t qsound_addr = 0;
|
||||
uint16_t qsound_loop = 0;
|
||||
uint16_t qsound_end = 0;
|
||||
uint16_t qsound_bank = 0;
|
||||
uint16_t qsound_addr = 0;
|
||||
uint16_t qsound_loop = 0;
|
||||
uint16_t qsound_end = 0;
|
||||
double off=1.0;
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->song.sample[chan[i].sample];
|
||||
|
@ -297,22 +296,20 @@ void DivPlatformQSound::tick() {
|
|||
} else {
|
||||
off=(double)s->centerRate/24038.0/16.0;
|
||||
}
|
||||
qsound_bank = 0x8000 | (s->rendOffQsound >> 16);
|
||||
qsound_addr = s->rendOffQsound & 0xffff;
|
||||
qsound_bank = 0x8000 | (s->rendOffQsound >> 16);
|
||||
qsound_addr = s->rendOffQsound & 0xffff;
|
||||
|
||||
int length = s->length;
|
||||
if(length > 65536 - 16)
|
||||
length = 65536 - 16;
|
||||
if(s->loopStart == -1 || s->loopStart >= length)
|
||||
{
|
||||
qsound_end = s->rendOffQsound + length + 15;
|
||||
qsound_loop = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
qsound_end = s->rendOffQsound + length;
|
||||
qsound_loop = length - s->loopStart;
|
||||
}
|
||||
int length = s->length;
|
||||
if (length > 65536 - 16) {
|
||||
length = 65536 - 16;
|
||||
}
|
||||
if (s->loopStart == -1 || s->loopStart >= length) {
|
||||
qsound_end = s->rendOffQsound + length + 15;
|
||||
qsound_loop = 15;
|
||||
} else {
|
||||
qsound_end = s->rendOffQsound + length;
|
||||
qsound_loop = length - s->loopStart;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.hadArp) {
|
||||
if (!chan[i].inPorta) {
|
||||
|
@ -333,29 +330,26 @@ void DivPlatformQSound::tick() {
|
|||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false);
|
||||
if (chan[i].freq>0xffff) chan[i].freq=0xffff;
|
||||
//if (chan[i].note>0x5d) chan[i].freq=0x01; //????
|
||||
if (chan[i].keyOn) {
|
||||
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
|
||||
rWrite(q1_reg_map[Q1V_END][i], qsound_end);
|
||||
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop);
|
||||
rWrite(q1_reg_map[Q1V_START][i], qsound_addr);
|
||||
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
|
||||
//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
|
||||
if (!chan[i].std.hadVol) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 5);
|
||||
//logW("ch %d vol=%04x (!hadVol)!\n",i,chan[i].vol << 5);
|
||||
}
|
||||
rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
|
||||
rWrite(q1_reg_map[Q1V_END][i], qsound_end);
|
||||
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop);
|
||||
rWrite(q1_reg_map[Q1V_START][i], qsound_addr);
|
||||
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
|
||||
//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
|
||||
if (!chan[i].std.hadVol) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4);
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], 0);
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], 0);
|
||||
// Disable volume
|
||||
// Disable volume
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], 0);
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], 0);
|
||||
} 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));
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq);
|
||||
}
|
||||
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));
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq);
|
||||
}
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
|
@ -411,13 +405,11 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
if (chan[c.chan].vol!=c.value) {
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.hasVol) {
|
||||
// Check if enabled and write volume
|
||||
// Check if enabled and write volume
|
||||
chan[c.chan].outVol=c.value;
|
||||
if(chan[c.chan].active && c.chan < 16)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (chan[c.chan].active && c.chan < 16) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -428,16 +420,16 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
return chan[c.chan].outVol;
|
||||
break;
|
||||
case DIV_CMD_PANNING:
|
||||
immWrite(Q1_PAN+c.chan, c.value + 0x110);
|
||||
immWrite(Q1_PAN+c.chan, c.value + 0x110);
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_LEVEL:
|
||||
immWrite(Q1_ECHO+c.chan, c.value << 7);
|
||||
immWrite(Q1_ECHO+c.chan, c.value << 7);
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
|
||||
immWrite(Q1_ECHO_FEEDBACK, c.value << 6);
|
||||
immWrite(Q1_ECHO_FEEDBACK, c.value << 6);
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_DELAY:
|
||||
immWrite(Q1_ECHO_LENGTH, (c.value > 2725 ? 0xfff : 0xfff - (2725 - c.value)));
|
||||
case DIV_CMD_QSOUND_ECHO_DELAY:
|
||||
immWrite(Q1_ECHO_LENGTH, (c.value > 2725 ? 0xfff : 0xfff - (2725 - c.value)));
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan[c.chan].pitch=c.value;
|
||||
|
@ -509,10 +501,11 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
}
|
||||
|
||||
void DivPlatformQSound::muteChannel(int ch, bool mute) {
|
||||
if(mute)
|
||||
chip.mute_mask |= (1 << ch);
|
||||
else
|
||||
chip.mute_mask &= ~(1 << ch);
|
||||
if (mute) {
|
||||
chip.mute_mask|=(1<<ch);
|
||||
} else {
|
||||
chip.mute_mask&=~(1<<ch);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformQSound::forceIns() {
|
||||
|
@ -532,8 +525,9 @@ void DivPlatformQSound::reset() {
|
|||
chan[i]=DivPlatformQSound::Channel();
|
||||
}
|
||||
qsound_reset(&chip);
|
||||
while(!chip.ready_flag)
|
||||
qsound_update(&chip);
|
||||
while(!chip.ready_flag) {
|
||||
qsound_update(&chip);
|
||||
}
|
||||
|
||||
immWrite(Q1_ECHO_LENGTH, 0xfff - (2725 - echoDelay));
|
||||
immWrite(Q1_ECHO_FEEDBACK, echoFeedback << 6);
|
||||
|
@ -557,6 +551,7 @@ void DivPlatformQSound::notifyInsChange(int ins) {
|
|||
|
||||
void DivPlatformQSound::notifyWaveChange(int wave) {
|
||||
// TODO when wavetables are added
|
||||
// TODO they probably won't be added unless the samples reside in RAM
|
||||
}
|
||||
|
||||
void DivPlatformQSound::notifyInsDeletion(void* ins) {
|
||||
|
@ -569,10 +564,12 @@ void DivPlatformQSound::setFlags(unsigned int flags) {
|
|||
echoDelay = 2725 - (flags & 0xfff);
|
||||
echoFeedback = (flags >> 12) & 255;
|
||||
|
||||
if(echoDelay < 0)
|
||||
echoDelay = 0;
|
||||
if(echoDelay > 2725)
|
||||
echoDelay = 2725;
|
||||
if(echoDelay < 0) {
|
||||
echoDelay = 0;
|
||||
}
|
||||
if(echoDelay > 2725) {
|
||||
echoDelay = 2725;
|
||||
}
|
||||
//rate=chipClock/CHIP_DIVIDER;
|
||||
}
|
||||
|
||||
|
@ -586,21 +583,21 @@ void DivPlatformQSound::poke(std::vector<DivRegWrite>& wlist) {
|
|||
}
|
||||
|
||||
unsigned char* DivPlatformQSound::getRegisterPool() {
|
||||
unsigned short* regPoolPtr = regPool;
|
||||
for(int i=0; i<256; i++)
|
||||
{
|
||||
uint16_t data = qsound_read_data(&chip, i);
|
||||
*regPoolPtr++ = data;
|
||||
}
|
||||
return (unsigned char*)regPool;
|
||||
unsigned short* regPoolPtr = regPool;
|
||||
for(int i=0; i<256; i++)
|
||||
{
|
||||
uint16_t data = qsound_read_data(&chip, i);
|
||||
*regPoolPtr++ = data;
|
||||
}
|
||||
return (unsigned char*)regPool;
|
||||
}
|
||||
|
||||
int DivPlatformQSound::getRegisterPoolSize() {
|
||||
return 256;
|
||||
return 256;
|
||||
}
|
||||
|
||||
int DivPlatformQSound::getRegisterPoolDepth() {
|
||||
return 16;
|
||||
return 16;
|
||||
}
|
||||
|
||||
int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
|
@ -608,9 +605,9 @@ int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
|
||||
// for (int i=0; i<16; i++) {
|
||||
// isMuted[i]=false;
|
||||
// }
|
||||
//for (int i=0; i<16; i++) {
|
||||
// isMuted[i]=false;
|
||||
//}
|
||||
setFlags(flags);
|
||||
|
||||
chipClock=60000000;
|
||||
|
|
|
@ -33,7 +33,7 @@ class DivPlatformQSound: public DivDispatch {
|
|||
int sample, wave;
|
||||
unsigned char ins;
|
||||
int note;
|
||||
int panning;
|
||||
int panning;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave;
|
||||
int vol, outVol;
|
||||
DivMacroInt std;
|
||||
|
@ -46,7 +46,7 @@ class DivPlatformQSound: public DivDispatch {
|
|||
sample(-1),
|
||||
ins(-1),
|
||||
note(0),
|
||||
panning(0x10),
|
||||
panning(0x10),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
|
|
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)));
|
||||
|
@ -241,10 +241,10 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
if ((effect & 0xf0)==0x30) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal));
|
||||
if ((effect&0xf0)==0x30) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal));
|
||||
} else {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -374,7 +380,132 @@ int DivEngine::getTotalChannelCount() {
|
|||
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) {
|
||||
switch (sys) {
|
||||
case DIV_SYSTEM_NULL:
|
||||
|
@ -384,7 +515,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
case DIV_SYSTEM_GENESIS:
|
||||
return "Sega Genesis/Mega Drive";
|
||||
case DIV_SYSTEM_SMS:
|
||||
return "Sega Master System";
|
||||
return "TI SN76489";
|
||||
case DIV_SYSTEM_SMS_OPLL:
|
||||
return "Sega Master System + FM Expansion";
|
||||
case DIV_SYSTEM_GB:
|
||||
|
@ -431,7 +562,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
case DIV_SYSTEM_OPLL:
|
||||
return "Yamaha OPLL";
|
||||
case DIV_SYSTEM_FDS:
|
||||
return "Famicom Disk System";
|
||||
return "Famicom Disk System (chip)";
|
||||
case DIV_SYSTEM_MMC5:
|
||||
return "MMC5";
|
||||
case DIV_SYSTEM_N163:
|
||||
|
@ -443,7 +574,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
case DIV_SYSTEM_OPL:
|
||||
return "Yamaha OPL";
|
||||
case DIV_SYSTEM_OPL2:
|
||||
return "Adlib Music Synthesizer Card";
|
||||
return "Yamaha OPL2";
|
||||
case DIV_SYSTEM_OPL3:
|
||||
return "Yamaha OPL3";
|
||||
case DIV_SYSTEM_MULTIPCM:
|
||||
|
@ -457,7 +588,7 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
case DIV_SYSTEM_SWAN:
|
||||
return "WonderSwan";
|
||||
case DIV_SYSTEM_SAA1099:
|
||||
return "SAM Coupé";
|
||||
return "Philips SAA1099";
|
||||
case DIV_SYSTEM_OPZ:
|
||||
return "Yamaha TX81Z/YS200";
|
||||
case DIV_SYSTEM_POKEMINI:
|
||||
|
@ -488,6 +619,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 +740,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 +1089,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 +1224,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 +1356,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 +1484,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 +1540,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;
|
||||
|
|
|
@ -975,10 +975,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
|||
}
|
||||
|
||||
if (writeQSound && qsoundMemLen>0) {
|
||||
// always write a whole bank
|
||||
unsigned int blockSize=(qsoundMemLen + 0xffff) & ~0xffff;
|
||||
if(blockSize > 0x1000000)
|
||||
blockSize = 0x1000000;
|
||||
// always write a whole bank
|
||||
unsigned int blockSize=(qsoundMemLen+0xffff)&(~0xffff);
|
||||
if (blockSize > 0x1000000) {
|
||||
blockSize = 0x1000000;
|
||||
}
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x8F);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -422,12 +422,10 @@ void FurnaceGUI::setFileName(String name) {
|
|||
}
|
||||
|
||||
void FurnaceGUI::updateWindowTitle() {
|
||||
String type=getSystemName(e->song.system[0]);
|
||||
if (e->song.systemLen>1) type="multi-system";
|
||||
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 {
|
||||
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 --",
|
||||
"tildearrow",
|
||||
"laoo",
|
||||
"superctr",
|
||||
"",
|
||||
"-- graphics --",
|
||||
"-- graphics/UI design --",
|
||||
"tildearrow",
|
||||
"BlastBrothers",
|
||||
"",
|
||||
"-- documentation --",
|
||||
"tildearrow",
|
||||
|
@ -2096,9 +2097,9 @@ void FurnaceGUI::drawRegView() {
|
|||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i]));
|
||||
int size=0;
|
||||
int depth=8;
|
||||
int depth=8;
|
||||
unsigned char* regPool=e->getRegisterPool(i,size,depth);
|
||||
unsigned short* regPoolW=(unsigned short*) regPool;
|
||||
unsigned short* regPoolW=(unsigned short*)regPool;
|
||||
if (regPool==NULL) {
|
||||
ImGui::Text("- no register pool available");
|
||||
} else {
|
||||
|
@ -2117,12 +2118,13 @@ void FurnaceGUI::drawRegView() {
|
|||
for (int j=0; j<16; j++) {
|
||||
ImGui::TableNextColumn();
|
||||
if (i*16+j>=size) continue;
|
||||
if(depth == 8)
|
||||
ImGui::Text("%.2x",regPool[i*16+j]);
|
||||
else if(depth == 16)
|
||||
ImGui::Text("%.4x",regPoolW[i*16+j]);
|
||||
else
|
||||
ImGui::Text("??");
|
||||
if (depth == 8) {
|
||||
ImGui::Text("%.2x",regPool[i*16+j]);
|
||||
} else if (depth == 16) {
|
||||
ImGui::Text("%.4x",regPoolW[i*16+j]);
|
||||
} else {
|
||||
ImGui::Text("??");
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
@ -3912,6 +3914,7 @@ bool dirExists(String what) {
|
|||
|
||||
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||
if (!dirExists(workingDir)) workingDir=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
switch (type) {
|
||||
case GUI_FILE_OPEN:
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","compatible files{.fur,.dmf},.*",workingDir);
|
||||
|
@ -4473,23 +4476,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);
|
||||
|
@ -4504,23 +4507,28 @@ 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);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("PAL (7.61MHz)",(flags&3)==1)) {
|
||||
e->setSysFlags(i,(flags&0x80000000)|1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("FM Towns (8MHz)",(flags&3)==2)) {
|
||||
e->setSysFlags(i,(flags&0x80000000)|2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&3)==3)) {
|
||||
e->setSysFlags(i,(flags&0x80000000)|3,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
bool ladder=flags&0x80000000;
|
||||
if (ImGui::Checkbox("Enable DAC distortion",&ladder)) {
|
||||
e->setSysFlags(i,(flags&(~0x80000000))|(ladder?0x80000000:0),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4528,22 +4536,28 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::Text("Clock rate:");
|
||||
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) {
|
||||
e->setSysFlags(i,(flags&(~3))|0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) {
|
||||
e->setSysFlags(i,(flags&(~3))|1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) {
|
||||
e->setSysFlags(i,(flags&(~3))|2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::Text("Chip type:");
|
||||
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
|
||||
e->setSysFlags(i,(flags&(~12))|0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) {
|
||||
e->setSysFlags(i,(flags&(~12))|4,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) {
|
||||
e->setSysFlags(i,(flags&(~12))|8,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
/*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) {
|
||||
e->setSysFlags(i,(flags&3)|12);
|
||||
|
@ -4552,30 +4566,36 @@ bool FurnaceGUI::loop() {
|
|||
bool noPhaseReset=flags&16;
|
||||
if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) {
|
||||
e->setSysFlags(i,(flags&(~16))|(noPhaseReset<<4),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2151:
|
||||
if (ImGui::RadioButton("NTSC (3.58MHz)",flags==0)) {
|
||||
e->setSysFlags(i,0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) {
|
||||
e->setSysFlags(i,1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("X68000 (4MHz)",flags==2)) {
|
||||
e->setSysFlags(i,2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_NES:
|
||||
if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) {
|
||||
e->setSysFlags(i,0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) {
|
||||
e->setSysFlags(i,1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) {
|
||||
e->setSysFlags(i,2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_AY8910:
|
||||
|
@ -4583,47 +4603,60 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::Text("Clock rate:");
|
||||
if (ImGui::RadioButton("1.79MHz (ZX Spectrum/MSX NTSC)",(flags&15)==0)) {
|
||||
e->setSysFlags(i,(flags&(~15))|0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("1.77MHz (ZX Spectrum/MSX PAL)",(flags&15)==1)) {
|
||||
e->setSysFlags(i,(flags&(~15))|1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) {
|
||||
e->setSysFlags(i,(flags&(~15))|2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("2MHz (Atari ST)",(flags&15)==3)) {
|
||||
e->setSysFlags(i,(flags&(~15))|3,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) {
|
||||
e->setSysFlags(i,(flags&(~15))|4,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) {
|
||||
e->setSysFlags(i,(flags&(~15))|5,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("0.89MHz (Sunsoft 5B)",(flags&15)==6)) {
|
||||
e->setSysFlags(i,(flags&(~15))|6,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) {
|
||||
e->setSysFlags(i,(flags&(~15))|7,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("0.83MHz (Sunsoft 5B on PAL)",(flags&15)==8)) {
|
||||
e->setSysFlags(i,(flags&(~15))|8,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (e->song.system[i]==DIV_SYSTEM_AY8910) {
|
||||
ImGui::Text("Chip type:");
|
||||
if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) {
|
||||
e->setSysFlags(i,(flags&(~0x30))|0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) {
|
||||
e->setSysFlags(i,(flags&(~0x30))|16,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) {
|
||||
e->setSysFlags(i,(flags&(~0x30))|32,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
}
|
||||
bool stereo=flags&0x40;
|
||||
ImGui::BeginDisabled((flags&0x30)==32);
|
||||
if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) {
|
||||
e->setSysFlags(i,(flags&(~0x40))|(stereo?0x40:0),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
break;
|
||||
|
@ -4631,12 +4664,15 @@ bool FurnaceGUI::loop() {
|
|||
case DIV_SYSTEM_SAA1099:
|
||||
if (ImGui::RadioButton("SAM Coupé (8MHz)",flags==0)) {
|
||||
e->setSysFlags(i,0,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("NTSC (7.15MHz)",flags==1)) {
|
||||
e->setSysFlags(i,1,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("PAL (7.09MHz)",flags==2)) {
|
||||
e->setSysFlags(i,2,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_AMIGA: {
|
||||
|
@ -4646,6 +4682,7 @@ bool FurnaceGUI::loop() {
|
|||
if (stereoSep<0) stereoSep=0;
|
||||
if (stereoSep>127) stereoSep=127;
|
||||
e->setSysFlags(i,(flags&1)|((stereoSep&127)<<8),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
/* TODO LATER: I want 0.5 out already
|
||||
if (ImGui::RadioButton("Amiga 500 (OCS)",(flags&2)==0)) {
|
||||
|
@ -4657,6 +4694,7 @@ bool FurnaceGUI::loop() {
|
|||
sysPal=flags&1;
|
||||
if (ImGui::Checkbox("PAL",&sysPal)) {
|
||||
e->setSysFlags(i,(flags&2)|sysPal,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4667,6 +4705,7 @@ bool FurnaceGUI::loop() {
|
|||
if (echoBufSize<0) echoBufSize=0;
|
||||
if (echoBufSize>2725) echoBufSize=2725;
|
||||
e->setSysFlags(i,(flags & ~4095) | ((2725 - echoBufSize) & 4095),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::Text("Echo feedback:");
|
||||
int echoFeedback=(flags>>12)&255;
|
||||
|
@ -4674,6 +4713,7 @@ bool FurnaceGUI::loop() {
|
|||
if (echoFeedback<0) echoFeedback=0;
|
||||
if (echoFeedback>255) echoFeedback=255;
|
||||
e->setSysFlags(i,(flags & ~(255 << 12)) | ((echoFeedback & 255) << 12),restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4688,6 +4728,7 @@ bool FurnaceGUI::loop() {
|
|||
default:
|
||||
if (ImGui::Checkbox("PAL",&sysPal)) {
|
||||
e->setSysFlags(i,sysPal,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4699,23 +4740,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);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "guiConst.h"
|
||||
#include "intConst.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <imgui.h>
|
||||
#include "plot_nolerp.h"
|
||||
|
||||
const char* insTypes[24]={
|
||||
|
@ -786,28 +787,102 @@ void FurnaceGUI::drawInsEdit() {
|
|||
//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));
|
||||
//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));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_DR),ImGuiDataType_U8,&op.dr,&_THIRTY_ONE,&_ZERO));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_SL),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
|
||||
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));
|
||||
if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \
|
||||
|
||||
ImGui::Separator();
|
||||
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));
|
||||
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_RS),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN));
|
||||
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));
|
||||
|
||||
int detune=(op.dt&7)-3;
|
||||
if (ImGui::SliderInt(FM_NAME(FM_DT),&detune,-3,3)) { PARAMETER
|
||||
op.dt=detune+3;
|
||||
}
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_DT2),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE));
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Only for Arcade system");
|
||||
}
|
||||
if (ImGui::SliderScalar(FM_NAME(FM_SSG),ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
|
||||
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
|
||||
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::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));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_MULT));
|
||||
|
||||
int detune=(op.dt&7)-3;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderInt("##DT",&detune,-3,3)) { PARAMETER
|
||||
op.dt=detune+3;
|
||||
}
|
||||
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()) {
|
||||
ImGui::SetTooltip("Only for Arcade system");
|
||||
}
|
||||
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);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_SSG));
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue