Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: (53 commits) prepare for better backward writing VGM export: fix oops GUI: drag-and-drop ins/wave/sample loading GUI: add "set loop" to sample editor MSM6295: VGM export! oops MSM6295: add rate select effect (20xx) update meteor shower MSVC is better than GCC right? update to-do list door into summer GUI: implement input for touch events GUI: update SDL hints fix Termux build add another demo song add demos/ecolove.fur update to-do list update demos/README.md add new demo songs dev99 - major Fractal system change ... # Conflicts: # src/engine/dispatch.h # src/engine/platform/genesis.cpp # src/engine/playback.cpp # src/engine/song.h # src/engine/vgmOps.cpp
This commit is contained in:
commit
32152fd89b
72 changed files with 967 additions and 304 deletions
|
|
@ -59,6 +59,7 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
||||
DIV_CMD_SAMPLE_BANK, // (bank)
|
||||
DIV_CMD_SAMPLE_POS, // (pos)
|
||||
DIV_CMD_SAMPLE_DIR, // (direction)
|
||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, // (enabled)
|
||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, // (slice)
|
||||
|
||||
|
|
@ -236,6 +237,8 @@ struct DivRegWrite {
|
|||
* - data is the sample rate
|
||||
* - 0xffffxx02: stop sample playback
|
||||
* - xx is the instance ID
|
||||
* - 0xffffxx03: set sample playback direction
|
||||
* - x is the instance ID
|
||||
* - 0xffffffff: reset
|
||||
*/
|
||||
unsigned int addr;
|
||||
|
|
|
|||
|
|
@ -185,10 +185,22 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_YM2612:
|
||||
dispatch=new DivPlatformGenesis;
|
||||
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
((DivPlatformGenesis*)dispatch)->setSoftPCM(false);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
dispatch=new DivPlatformGenesisExt;
|
||||
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
((DivPlatformGenesisExt*)dispatch)->setSoftPCM(false);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2612_FRAC:
|
||||
dispatch=new DivPlatformGenesis;
|
||||
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
((DivPlatformGenesis*)dispatch)->setSoftPCM(true);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2612_FRAC_EXT:
|
||||
dispatch=new DivPlatformGenesisExt;
|
||||
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
((DivPlatformGenesisExt*)dispatch)->setSoftPCM(true);
|
||||
break;
|
||||
case DIV_SYSTEM_SMS:
|
||||
dispatch=new DivPlatformSMS;
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ void DivEngine::initSongWithDesc(const int* description) {
|
|||
song.systemFlags[index]=description[i+3];
|
||||
index++;
|
||||
chanCount+=getChannelCount(song.system[index]);
|
||||
if (chanCount>=63) break;
|
||||
if (chanCount>=DIV_MAX_CHANS) break;
|
||||
if (index>=32) break;
|
||||
}
|
||||
song.systemLen=index;
|
||||
|
|
@ -887,9 +887,8 @@ bool DivEngine::addSystem(DivSystem which) {
|
|||
lastError="max number of systems is 32";
|
||||
return false;
|
||||
}
|
||||
// this was DIV_MAX_CHANS but I am setting it to 63 for now due to an ImGui limitation
|
||||
if (chans+getChannelCount(which)>63) {
|
||||
lastError="max number of total channels is 63";
|
||||
if (chans+getChannelCount(which)>DIV_MAX_CHANS) {
|
||||
lastError=fmt::sprintf("max number of total channels is %d",DIV_MAX_CHANS);
|
||||
return false;
|
||||
}
|
||||
quitDispatch();
|
||||
|
|
@ -1773,7 +1772,7 @@ int DivEngine::addWave() {
|
|||
return waveCount;
|
||||
}
|
||||
|
||||
bool DivEngine::addWaveFromFile(const char* path) {
|
||||
bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return false;
|
||||
|
|
@ -1869,8 +1868,27 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
}
|
||||
} else {
|
||||
// read as binary
|
||||
logI("reading binary...");
|
||||
if (addRaw) {
|
||||
logI("reading binary...");
|
||||
len=reader.size();
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
if (addRaw) {
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
|
|
@ -1878,18 +1896,11 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev97"
|
||||
#define DIV_ENGINE_VERSION 97
|
||||
#define DIV_VERSION "dev99"
|
||||
#define DIV_ENGINE_VERSION 99
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
@ -377,7 +377,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond);
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
@ -676,7 +676,7 @@ class DivEngine {
|
|||
int addWave();
|
||||
|
||||
// add wavetable from file
|
||||
bool addWaveFromFile(const char* path);
|
||||
bool addWaveFromFile(const char* path, bool loadRaw=true);
|
||||
|
||||
// delete wavetable
|
||||
void delWave(int index);
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.fbPortaPause=true;
|
||||
ds.snDutyReset=true;
|
||||
ds.oldOctaveBoundary=false;
|
||||
ds.noOPN2Vol=true;
|
||||
ds.newVolumeScaling=false;
|
||||
ds.volMacroLinger=false;
|
||||
ds.brokenOutVol=true; // ???
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
|
@ -1031,6 +1035,14 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<97) {
|
||||
ds.oldOctaveBoundary=true;
|
||||
}
|
||||
if (ds.version<97) { // actually should be 98 but yky uses this feature ahead of time
|
||||
ds.noOPN2Vol=true;
|
||||
}
|
||||
if (ds.version<99) {
|
||||
ds.newVolumeScaling=false;
|
||||
ds.volMacroLinger=false;
|
||||
ds.brokenOutVol=true;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
|
@ -1413,7 +1425,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<13; i++) {
|
||||
if (ds.version>=98) {
|
||||
ds.noOPN2Vol=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
if (ds.version>=99) {
|
||||
ds.newVolumeScaling=reader.readC();
|
||||
ds.volMacroLinger=reader.readC();
|
||||
ds.brokenOutVol=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<9; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
|
@ -2894,7 +2920,11 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.pitchMacroIsLinear);
|
||||
w->writeC(song.pitchSlideSpeed);
|
||||
w->writeC(song.oldOctaveBoundary);
|
||||
for (int i=0; i<13; i++) {
|
||||
w->writeC(song.noOPN2Vol);
|
||||
w->writeC(song.newVolumeScaling);
|
||||
w->writeC(song.volMacroLinger);
|
||||
w->writeC(song.brokenOutVol);
|
||||
for (int i=0; i<9; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,51 +125,109 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
|||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0xdf:
|
||||
return "DFxx: Set sample playback direction (0: normal; 1: reverse)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::processDAC() {
|
||||
if (softPCM) {
|
||||
softPCMTimer+=chipClock/576;
|
||||
if (softPCMTimer>rate) {
|
||||
softPCMTimer-=rate;
|
||||
|
||||
int sample=0;
|
||||
for (int i=5; i<7; i++) {
|
||||
if (chan[i].dacSample!=-1) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (!isMuted[i] && s->samples>0) {
|
||||
if (parent->song.noOPN2Vol) {
|
||||
sample+=s->data8[chan[i].getDacDirection()?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
|
||||
} else {
|
||||
sample+=(s->data8[chan[i].getDacDirection()?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
|
||||
}
|
||||
}
|
||||
chan[i].dacPeriod+=chan[i].dacRate;
|
||||
if (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
if (s->samples>0) {
|
||||
while (chan[i].dacPeriod>=(chipClock/576)) {
|
||||
chan[i].dacPos++;
|
||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].dacPos>=s->loopEnd) || (chan[i].dacPos>=s->samples)) {
|
||||
if (s->isLoopable() && !chan[i].getDacDirection()) {
|
||||
chan[i].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
chan[i].dacPeriod=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
chan[i].dacPeriod-=(chipClock/576);
|
||||
}
|
||||
} else {
|
||||
chan[i].dacSample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//sample>>=1;
|
||||
if (sample<-128) sample=-128;
|
||||
if (sample>127) sample=127;
|
||||
urgentWrite(0x2a,(unsigned char)sample+0x80);
|
||||
}
|
||||
} else {
|
||||
if (!chan[5].dacReady) {
|
||||
chan[5].dacDelay+=32000;
|
||||
if (chan[5].dacDelay>=rate) {
|
||||
chan[5].dacDelay-=rate;
|
||||
chan[5].dacReady=true;
|
||||
}
|
||||
}
|
||||
if (chan[5].dacMode && chan[5].dacSample!=-1) {
|
||||
chan[5].dacPeriod+=chan[5].dacRate;
|
||||
if (chan[5].dacPeriod>=rate) {
|
||||
DivSample* s=parent->getSample(chan[5].dacSample);
|
||||
if (s->samples>0) {
|
||||
if (!isMuted[5]) {
|
||||
if (chan[5].dacReady && writes.size()<16) {
|
||||
int sample;
|
||||
if (parent->song.noOPN2Vol) {
|
||||
sample=s->data8[chan[5].getDacDirection()?(s->samples-chan[5].dacPos-1):chan[5].dacPos];
|
||||
} else {
|
||||
sample=(s->data8[chan[5].getDacDirection()?(s->samples-chan[5].dacPos-1):chan[5].dacPos]*dacVolTable[chan[5].outVol])>>7;
|
||||
}
|
||||
urgentWrite(0x2a,(unsigned char)sample+0x80);
|
||||
chan[5].dacReady=false;
|
||||
}
|
||||
}
|
||||
chan[5].dacPos++;
|
||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[5].dacPos>=s->loopEnd) || (chan[5].dacPos>=s->samples)) {
|
||||
if (s->isLoopable() && !chan[5].getDacDirection()) {
|
||||
chan[5].dacPos=s->loopStart;
|
||||
} else {
|
||||
chan[5].dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate;
|
||||
} else {
|
||||
chan[5].dacSample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static short o[2];
|
||||
static int os[2];
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!dacReady) {
|
||||
dacDelay+=32000;
|
||||
if (dacDelay>=rate) {
|
||||
dacDelay-=rate;
|
||||
dacReady=true;
|
||||
}
|
||||
}
|
||||
if (dacMode && dacSample!=-1) {
|
||||
dacPeriod+=dacRate;
|
||||
if (dacPeriod>=rate) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (s->samples>0) {
|
||||
if (!isMuted[5]) {
|
||||
if (dacReady && writes.size()<16) {
|
||||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
||||
dacReady=false;
|
||||
}
|
||||
}
|
||||
dacPos++;
|
||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) {
|
||||
if (s->isLoopable()) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (dacPeriod>=rate) dacPeriod-=rate;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processDAC();
|
||||
|
||||
os[0]=0; os[1]=0;
|
||||
for (int i=0; i<6; i++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
|
|
@ -215,41 +273,7 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
|
|||
ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine();
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!dacReady) {
|
||||
dacDelay+=32000;
|
||||
if (dacDelay>=rate) {
|
||||
dacDelay-=rate;
|
||||
dacReady=true;
|
||||
}
|
||||
}
|
||||
if (dacMode && dacSample!=-1) {
|
||||
dacPeriod+=dacRate;
|
||||
if (dacPeriod>=rate) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (s->samples>0) {
|
||||
if (!isMuted[5]) {
|
||||
if (dacReady && writes.size()<16) {
|
||||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
||||
dacReady=false;
|
||||
}
|
||||
}
|
||||
dacPos++;
|
||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) {
|
||||
if (s->isLoopable()) {
|
||||
dacPos=s->loopStart;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (dacPeriod>=rate) dacPeriod-=rate;
|
||||
} else {
|
||||
dacSample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
processDAC();
|
||||
|
||||
os[0]=0; os[1]=0;
|
||||
if (!writes.empty()) {
|
||||
|
|
@ -474,7 +498,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<8; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if (chan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
|
@ -493,12 +517,14 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
chan[i].freq=(block<<11)|fNum;
|
||||
}
|
||||
if (chan[i].freq>0x3fff) chan[i].freq=0x3fff;
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||
if (chan[i].furnaceDac && dacMode) {
|
||||
if (i<6) {
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||
}
|
||||
if (chan[i].furnaceDac && chan[i].dacMode) {
|
||||
double off=1.0;
|
||||
if (dacSample>=0 && dacSample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} else {
|
||||
|
|
@ -506,14 +532,14 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
||||
dacRate=chan[i].freq*off;
|
||||
if (dacRate<1) dacRate=1;
|
||||
if (dumpWrites) addWrite(0xffff0001,dacRate);
|
||||
chan[i].dacRate=chan[i].freq*off;
|
||||
if (chan[i].dacRate<1) chan[i].dacRate=1;
|
||||
if (dumpWrites) addWrite(0xffff0001,chan[i].dacRate);
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
immWrite(0x28,0xf0|konOffs[i]);
|
||||
if (i<6) immWrite(0x28,0xf0|konOffs[i]);
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
|
@ -521,6 +547,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
|
||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>5) return;
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
|
|
@ -541,29 +568,33 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (c.chan==5) {
|
||||
if (c.chan>=5) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
dacMode=1;
|
||||
chan[c.chan].dacMode=1;
|
||||
rWrite(0x2b,1<<7);
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
dacMode=0;
|
||||
chan[c.chan].dacMode=0;
|
||||
rWrite(0x2b,0<<7);
|
||||
}
|
||||
}
|
||||
if (c.chan==5 && dacMode) {
|
||||
if (c.chan>=5 && chan[c.chan].dacMode) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
break;
|
||||
} else {
|
||||
chan[c.chan].dacReversed=ins->amiga.getReversed(c.value);
|
||||
rWrite(0x2b,1<<7);
|
||||
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffff0000,chan[c.chan].dacSample);
|
||||
addWrite(0xffff0003,chan[c.chan].getDacDirection());
|
||||
}
|
||||
}
|
||||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
chan[c.chan].dacPos=0;
|
||||
chan[c.chan].dacPeriod=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -573,23 +604,25 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
dacSample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
chan[c.chan].dacSample=12*chan[c.chan].sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
break;
|
||||
} else {
|
||||
rWrite(0x2b,1<<7);
|
||||
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
||||
if (dumpWrites) addWrite(0xffff0000,chan[c.chan].dacSample);
|
||||
}
|
||||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
dacRate=MAX(1,parent->getSample(dacSample)->rate);
|
||||
if (dumpWrites) addWrite(0xffff0001,parent->getSample(dacSample)->rate);
|
||||
chan[c.chan].dacPos=0;
|
||||
chan[c.chan].dacPeriod=0;
|
||||
chan[c.chan].dacRate=MAX(1,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||
if (dumpWrites) addWrite(0xffff0001,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||
chan[c.chan].furnaceDac=false;
|
||||
chan[c.chan].dacReversed=false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>=6) break;
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
|
@ -642,12 +675,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan==5) {
|
||||
dacSample=-1;
|
||||
if (c.chan>=5) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
if (dacMode) break;
|
||||
if (chan[c.chan].dacMode) break;
|
||||
}
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
|
|
@ -655,8 +688,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan==5) {
|
||||
dacSample=-1;
|
||||
if (c.chan>=5) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
|
|
@ -672,6 +705,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>=6) 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];
|
||||
|
|
@ -698,6 +732,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.chan>5) c.chan=5;
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
|
|
@ -735,7 +770,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
||||
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
|
@ -762,18 +797,26 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_MODE: {
|
||||
dacMode=c.value;
|
||||
if (c.chan<5) c.chan=5;
|
||||
chan[c.chan].dacMode=c.value;
|
||||
rWrite(0x2b,c.value<<7);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
if (c.chan<5) c.chan=5;
|
||||
chan[c.chan].sampleBank=c.value;
|
||||
if (chan[c.chan].sampleBank>(parent->song.sample.size()/12)) {
|
||||
chan[c.chan].sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_DIR: {
|
||||
if (c.chan<5) c.chan=5;
|
||||
chan[c.chan].dacDirection=c.value;
|
||||
if (dumpWrites) addWrite(0xffff0003,chan[c.chan].dacDirection);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
||||
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
|
|
@ -783,16 +826,19 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_LFO: {
|
||||
if (c.chan>=6) break;
|
||||
lfoValue=(c.value&7)|((c.value>>4)<<3);
|
||||
rWrite(0x22,lfoValue);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>=6) break;
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>=6) 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;
|
||||
|
|
@ -800,6 +846,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>=6) 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;
|
||||
|
|
@ -815,6 +862,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -831,6 +879,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -847,6 +896,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -863,6 +913,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -879,6 +930,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -895,6 +947,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -911,6 +964,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -927,6 +981,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -943,6 +998,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
|
@ -959,6 +1015,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
if (c.chan>=6) break;
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
|
|
@ -1007,7 +1064,7 @@ void DivPlatformGenesis::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (dacMode) {
|
||||
if (chan[5].dacMode) {
|
||||
rWrite(0x2b,0x80);
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
|
|
@ -1057,18 +1114,18 @@ void DivPlatformGenesis::reset() {
|
|||
}
|
||||
|
||||
lastBusy=60;
|
||||
dacMode=0;
|
||||
dacPeriod=0;
|
||||
dacPos=0;
|
||||
dacRate=0;
|
||||
dacDelay=0;
|
||||
dacReady=true;
|
||||
dacSample=-1;
|
||||
sampleBank=0;
|
||||
lfoValue=8;
|
||||
|
||||
softPCMTimer=0;
|
||||
extMode=false;
|
||||
|
||||
if (softPCM) {
|
||||
chan[5].dacMode=true;
|
||||
chan[6].dacMode=true;
|
||||
}
|
||||
|
||||
// normal sample direction
|
||||
if (dumpWrites) addWrite(0xffff0003,0);
|
||||
|
||||
// LFO
|
||||
immWrite(0x22,lfoValue);
|
||||
|
||||
|
|
@ -1088,7 +1145,7 @@ bool DivPlatformGenesis::keyOffAffectsPorta(int ch) {
|
|||
}
|
||||
|
||||
void DivPlatformGenesis::notifyInsChange(int ins) {
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<10; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
|
@ -1114,6 +1171,10 @@ void DivPlatformGenesis::setYMFM(bool use) {
|
|||
useYMFM=use;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::setSoftPCM(bool value) {
|
||||
softPCM=value;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::setFlags(unsigned int flags) {
|
||||
switch (flags) {
|
||||
case 1: chipClock=COLOR_PAL*12.0/7.0; break;
|
||||
|
|
@ -1152,6 +1213,11 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i
|
|||
fm_ymfm=NULL;
|
||||
setFlags(flags);
|
||||
|
||||
for (int i=0; i<128; i++) {
|
||||
dacVolTable[127-i]=128*pow(10.0f,(float)(-i)*0.75f/20.0f);
|
||||
}
|
||||
dacVolTable[0]=0;
|
||||
|
||||
reset();
|
||||
return 10;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,10 +41,24 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
|
||||
bool dacMode;
|
||||
int dacPeriod;
|
||||
int dacRate;
|
||||
unsigned int dacPos;
|
||||
int dacSample;
|
||||
int dacDelay;
|
||||
bool dacReady;
|
||||
bool dacDirection;
|
||||
bool dacReversed;
|
||||
unsigned char sampleBank;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
bool getDacDirection() {
|
||||
return dacReversed^dacDirection;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
|
|
@ -65,7 +79,18 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
inPorta(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
pan(3) {}
|
||||
outVol(0),
|
||||
pan(3),
|
||||
dacMode(false),
|
||||
dacPeriod(0),
|
||||
dacRate(0),
|
||||
dacPos(0),
|
||||
dacSample(-1),
|
||||
dacDelay(0),
|
||||
dacReady(true),
|
||||
dacDirection(false),
|
||||
dacReversed(false),
|
||||
sampleBank(0) {}
|
||||
};
|
||||
Channel chan[10];
|
||||
DivDispatchOscBuffer* oscBuf[10];
|
||||
|
|
@ -86,24 +111,21 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
DivYM2612Interface iface;
|
||||
unsigned char regPool[512];
|
||||
|
||||
bool dacMode;
|
||||
int dacPeriod;
|
||||
int dacRate;
|
||||
unsigned int dacPos;
|
||||
int dacSample;
|
||||
int dacDelay;
|
||||
bool dacReady;
|
||||
unsigned char sampleBank;
|
||||
unsigned char lfoValue;
|
||||
|
||||
bool extMode, useYMFM;
|
||||
int softPCMTimer;
|
||||
|
||||
bool extMode, softPCM, useYMFM;
|
||||
bool ladder;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
unsigned char dacVolTable[128];
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
inline void processDAC();
|
||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
|
||||
|
||||
|
|
@ -126,6 +148,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void setSoftPCM(bool value);
|
||||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
|||
|
|
@ -156,16 +156,16 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_SAMPLE_MODE: {
|
||||
// not ignored actually!
|
||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||
dacMode=c.value;
|
||||
chan[5].dacMode=c.value;
|
||||
rWrite(0x2b,c.value<<7);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
chan[5].sampleBank=c.value;
|
||||
if (chan[5].sampleBank>(parent->song.sample.size()/12)) {
|
||||
chan[5].sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -484,7 +484,7 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (dacMode) {
|
||||
if (chan[5].dacMode) {
|
||||
rWrite(0x2b,0x80);
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#define WRITE_VOLUME(ch,v) rWrite(0x20+(ch<<3),(v))
|
||||
#define WRITE_FEEDBACK(ch,v) rWrite(0x21+(ch<<3),(v))
|
||||
#define WRITE_OUTPUT(ch,v) rWrite(0x22+(ch<<3),(v))
|
||||
#define WRITE_LFSR(ch,v) rWrite(0x23+(ch<<3),(v))
|
||||
#define WRITE_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
||||
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
||||
|
|
@ -151,13 +152,18 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (s!=NULL) {
|
||||
if (isMuted[i]) {
|
||||
WRITE_VOLUME(i,0);
|
||||
WRITE_OUTPUT(i,0);
|
||||
chan[i].samplePos++;
|
||||
} else {
|
||||
WRITE_VOLUME(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
||||
WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
||||
}
|
||||
|
||||
if (chan[i].samplePos>=(int)s->samples) {
|
||||
chan[i].sample=-1;
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].samplePos=s->loopStart;
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -176,8 +182,8 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6;
|
||||
} else {
|
||||
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
||||
WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127)));
|
||||
}
|
||||
WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127)));
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
|
|
@ -244,11 +250,6 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
||||
WRITE_FEEDBACK(i,0);
|
||||
WRITE_LFSR(i,0);
|
||||
WRITE_OTHER(i,0);
|
||||
WRITE_CONTROL(i,0x18);
|
||||
WRITE_BACKUP(i,2);
|
||||
} else {
|
||||
if (chan[i].lfsr >= 0) {
|
||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||
|
|
@ -300,7 +301,8 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
WRITE_VOLUME(c.chan, 0);
|
||||
WRITE_VOLUME(c.chan,0);
|
||||
WRITE_CONTROL(c.chan,0);
|
||||
chan[c.chan].macroInit(NULL);
|
||||
if (chan[c.chan].pcm) {
|
||||
chan[c.chan].pcm=false;
|
||||
|
|
|
|||
|
|
@ -23,13 +23,18 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define rWrite(v) if (!skipRegisterWrites) {writes.emplace(0,v); if (dumpWrites) {addWrite(0,v);} }
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
const char** DivPlatformMSM6295::getRegisterSheet() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x20:
|
||||
return "20xx: Set chip output rate (0: clock/132; 1: clock/165)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +47,28 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
if (delay<=0) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
msm->command_w(w.val);
|
||||
switch (w.addr) {
|
||||
case 0: // command
|
||||
msm->command_w(w.val);
|
||||
break;
|
||||
case 8: // chip clock select (VGM)
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
break;
|
||||
case 12: // rate select
|
||||
msm->ss_w(!w.val);
|
||||
break;
|
||||
case 14: // enable bankswitch
|
||||
break;
|
||||
case 15: // set bank base
|
||||
break;
|
||||
case 16: // switch bank
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
break;
|
||||
}
|
||||
writes.pop();
|
||||
delay=32;
|
||||
}
|
||||
|
|
@ -92,9 +118,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -107,9 +133,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -117,14 +143,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
|
|
@ -153,6 +179,10 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_PORTA: {
|
||||
return 2;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
rateSel=c.value;
|
||||
rWrite(12,!rateSel);
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
|
|
@ -190,6 +220,7 @@ void DivPlatformMSM6295::forceIns() {
|
|||
for (int i=0; i<4; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
rWrite(12,!rateSel);
|
||||
}
|
||||
|
||||
void* DivPlatformMSM6295::getChanState(int ch) {
|
||||
|
|
@ -219,6 +250,7 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
|
|||
void DivPlatformMSM6295::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
msm->reset();
|
||||
msm->ss_w(false);
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
|
@ -232,6 +264,7 @@ void DivPlatformMSM6295::reset() {
|
|||
}
|
||||
|
||||
sampleBank=0;
|
||||
rateSel=false;
|
||||
|
||||
delay=0;
|
||||
}
|
||||
|
|
@ -240,6 +273,10 @@ bool DivPlatformMSM6295::keyOffAffectsArp(int ch) {
|
|||
return false;
|
||||
}
|
||||
|
||||
float DivPlatformMSM6295::getPostAmp() {
|
||||
return 3.0f;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::notifyInsChange(int ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
|
|
@ -302,12 +339,21 @@ void DivPlatformMSM6295::renderSamples() {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::setFlags(unsigned int flags) {
|
||||
if (flags&1) {
|
||||
chipClock=8448000;
|
||||
} else {
|
||||
chipClock=8000000;
|
||||
switch (flags) {
|
||||
case 0:
|
||||
chipClock=4000000/4;
|
||||
break;
|
||||
case 1:
|
||||
chipClock=4224000/4;
|
||||
break;
|
||||
case 2:
|
||||
chipClock=4000000;
|
||||
break;
|
||||
case 3:
|
||||
chipClock=4224000;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/((flags&2)?6:24);
|
||||
rate=chipClock/3;
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]->rate=rate/22;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
int delay, updateOsc;
|
||||
|
||||
bool extMode;
|
||||
bool rateSel;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
|
@ -119,6 +120,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
float getPostAmp();
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
|
|
|
|||
|
|
@ -735,6 +735,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
|
|
@ -770,6 +771,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ const char* DivPlatformSMS::getEffectName(unsigned char effect) {
|
|||
}
|
||||
|
||||
void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
int o=0;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!writes.empty()) {
|
||||
unsigned char w=writes.front();
|
||||
|
|
@ -64,7 +65,10 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
|||
YMPSG_Clock(&sn_nuked);
|
||||
YMPSG_Clock(&sn_nuked);
|
||||
YMPSG_Clock(&sn_nuked);
|
||||
bufL[h]=YMPSG_GetOutput(&sn_nuked)*8192.0;
|
||||
o=YMPSG_GetOutput(&sn_nuked);
|
||||
if (o<-32768) o=-32768;
|
||||
if (o>32767) o=32767;
|
||||
bufL[h]=o;
|
||||
/*
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isMuted[i]) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ const char* cmdName[]={
|
|||
"SAMPLE_FREQ",
|
||||
"SAMPLE_BANK",
|
||||
"SAMPLE_POS",
|
||||
"SAMPLE_DIR",
|
||||
"SAMPLE_TRANSWAVE_SLICE_MODE", // (enabled)
|
||||
"SAMPLE_TRANSWAVE_SLICE_POS", // (slice)
|
||||
|
||||
|
|
@ -570,6 +571,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
clockDrift=0;
|
||||
subticks=0;
|
||||
break;
|
||||
case 0xdf: // set sample direction
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal));
|
||||
break;
|
||||
case 0xe0: // arp speed
|
||||
if (effectVal>0) {
|
||||
curSubSong->arpLen=effectVal;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ enum DivSystem {
|
|||
DIV_SYSTEM_NAMCO,
|
||||
DIV_SYSTEM_NAMCO_15XX,
|
||||
DIV_SYSTEM_NAMCO_CUS30,
|
||||
DIV_SYSTEM_YM2612_FRAC,
|
||||
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||
DIV_SYSTEM_RESERVED_8,
|
||||
DIV_SYSTEM_DUMMY,
|
||||
DIV_SYSTEM_MAX // boundary for max system number
|
||||
};
|
||||
|
|
@ -395,6 +398,10 @@ struct DivSong {
|
|||
bool snDutyReset;
|
||||
bool pitchMacroIsLinear;
|
||||
bool oldOctaveBoundary;
|
||||
bool noOPN2Vol;
|
||||
bool newVolumeScaling;
|
||||
bool volMacroLinger;
|
||||
bool brokenOutVol;
|
||||
|
||||
std::vector<DivInstrument*> ins;
|
||||
std::vector<DivWavetable*> wave;
|
||||
|
|
@ -488,7 +495,11 @@ struct DivSong {
|
|||
fbPortaPause(false),
|
||||
snDutyReset(false),
|
||||
pitchMacroIsLinear(true),
|
||||
oldOctaveBoundary(false) {
|
||||
oldOctaveBoundary(false),
|
||||
noOPN2Vol(false),
|
||||
newVolumeScaling(true),
|
||||
volMacroLinger(true),
|
||||
brokenOutVol(false) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
|||
|
|
@ -2027,12 +2027,23 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef(
|
||||
"OKI MSM6295", NULL, 0xaa, 0, 4, false, true, 0, false,
|
||||
"OKI MSM6295", NULL, 0xaa, 0, 4, false, true, 0x161, false,
|
||||
"an ADPCM sound chip manufactured by OKI and used in many arcade boards.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||
{"CH1", "CH2", "CH3", "CH4"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
|
||||
switch (effect) {
|
||||
case 0x20: // select rate
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_MSM6258]=new DivSysDef(
|
||||
|
|
@ -2100,6 +2111,40 @@ void DivEngine::registerSystems() {
|
|||
namcoEffectHandler
|
||||
);
|
||||
|
||||
// replace with an 8-channel chip in a future
|
||||
sysDefs[DIV_SYSTEM_RESERVED_8]=new DivSysDef(
|
||||
"Reserved", NULL, 0xbc, 0, 8, false, true, 0, false,
|
||||
"this was YM2612_FRAC, but due to changes this ID is reserved.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
|
||||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_YM2612_FRAC]=new DivSysDef(
|
||||
"Yamaha YM2612 (OPN2) with DualPCM", NULL, 0xbe, 0, 7, true, false, 0, false,
|
||||
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.",
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6/PCM 1", "PCM 2"},
|
||||
{"F1", "F2", "F3", "F4", "F5", "P1", "P2"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AMIGA},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL},
|
||||
opn2EffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_YM2612_FRAC_EXT]=new DivSysDef(
|
||||
"Yamaha YM2612 (OPN2) Extended Channel 3 with DualPCM and CSM", NULL, 0xbd, 0, 11, true, false, 0, false,
|
||||
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
|
||||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6/PCM 1", "PCM 2", "CSM Timer"},
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "P1", "P2", "CSM"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AMIGA, DIV_INS_FM},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL},
|
||||
opn2EffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
|
||||
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
|
||||
"this is a system designed for testing purposes.",
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond) {
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond) {
|
||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||
unsigned char baseAddr2=isSecond?0x80:0;
|
||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||
|
|
@ -420,22 +420,22 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
case DIV_SYSTEM_Y8950_DRUMS:
|
||||
// disable envelope
|
||||
for (int i=0; i<6; i++) {
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x80+i);
|
||||
w->writeC(0x0f);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x88+i);
|
||||
w->writeC(0x0f);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x90+i);
|
||||
w->writeC(0x0f);
|
||||
}
|
||||
// key off + freq reset
|
||||
for (int i=0; i<9; i++) {
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0xa0+i);
|
||||
w->writeC(0);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0xb0+i);
|
||||
w->writeC(0);
|
||||
}
|
||||
|
|
@ -522,6 +522,15 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(rf5c68Addr);
|
||||
w->writeC(8);
|
||||
w->writeC(0xff);
|
||||
break;
|
||||
case DIV_SYSTEM_MSM6295:
|
||||
w->writeC(0xb8); // disable all channels
|
||||
w->writeC(baseAddr2|0);
|
||||
w->writeC(0x78);
|
||||
w->writeC(0xb8); // select rate
|
||||
w->writeC(baseAddr2|12);
|
||||
w->writeC(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -536,8 +545,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
w->writeC((sample->loopStart==0)); // flags
|
||||
if (sample->loopStart>0) {
|
||||
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
if (sample->loopStart>0 && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=(double)sample->loopEnd;
|
||||
loopSample[streamID]=write.val;
|
||||
}
|
||||
|
|
@ -554,6 +563,9 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(streamID);
|
||||
loopSample[streamID]=-1;
|
||||
break;
|
||||
case 3: // set sample direction
|
||||
sampleDir[streamID]=write.val;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -818,6 +830,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(write.addr&0xff);
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_MSM6295:
|
||||
w->writeC(0xb8);
|
||||
w->writeC(baseAddr2|(write.addr&0x7f));
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
default:
|
||||
logW("write not handled!");
|
||||
break;
|
||||
|
|
@ -923,11 +940,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
double loopTimer[DIV_MAX_CHANS];
|
||||
double loopFreq[DIV_MAX_CHANS];
|
||||
int loopSample[DIV_MAX_CHANS];
|
||||
bool sampleDir[DIV_MAX_CHANS];
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
loopTimer[i]=0;
|
||||
loopFreq[i]=0;
|
||||
loopSample[i]=-1;
|
||||
sampleDir[i]=false;
|
||||
}
|
||||
|
||||
bool writeDACSamples=false;
|
||||
|
|
@ -942,6 +961,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
DivDispatch* writeES5506[2]={NULL,NULL};
|
||||
DivDispatch* writeZ280[2]={NULL,NULL};
|
||||
DivDispatch* writeRF5C68[2]={NULL,NULL};
|
||||
DivDispatch* writeMSM6295[2]={NULL,NULL};
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
willExport[i]=false;
|
||||
|
|
@ -1348,6 +1368,19 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
writeRF5C68[0]=disCont[i].dispatch;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_MSM6295:
|
||||
if (!hasOKIM6295) {
|
||||
hasOKIM6295=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
writeMSM6295[0]=disCont[i].dispatch;
|
||||
} else if (!(hasOKIM6295&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
writeMSM6295[1]=disCont[i].dispatch;
|
||||
hasOKIM6295|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1694,6 +1727,15 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
w->writeI(0);
|
||||
w->write(writeRF5C68[i]->getSampleMem(),writeRF5C68[i]->getSampleMemUsage());
|
||||
}
|
||||
if (writeMSM6295[i]!=NULL && writeMSM6295[i]->getSampleMemUsage()>0) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x8b);
|
||||
w->writeI((writeMSM6295[i]->getSampleMemUsage()+8)|(i*0x80000000));
|
||||
w->writeI(writeMSM6295[i]->getSampleMemCapacity());
|
||||
w->writeI(0);
|
||||
w->write(writeMSM6295[i]->getSampleMem(),writeMSM6295[i]->getSampleMemUsage());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
|
@ -1829,7 +1871,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
for (int i=0; i<song.systemLen; i++) {
|
||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||
for (DivRegWrite& j: writes) {
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,isSecond[i]);
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i]);
|
||||
writeCount++;
|
||||
}
|
||||
writes.clear();
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ bool DivWaveSynth::tick(bool skipSubDiv) {
|
|||
break;
|
||||
case DIV_WS_PHASE_MOD:
|
||||
for (int i=0; i<=state.speed; i++) {
|
||||
int mod=(wave2[pos]*(state.param2-stage)*width)/512;
|
||||
int mod=(wave2[pos]*(state.param2-stage)*width)/(64*(height+1));
|
||||
output[pos]=wave1[(pos+mod)%width];
|
||||
if (++pos>=width) {
|
||||
pos=0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue