this does not compile

This commit is contained in:
tildearrow 2022-01-08 16:03:32 -05:00
parent f47543ab98
commit 7080434ed4
8 changed files with 302 additions and 222 deletions

View File

@ -98,6 +98,7 @@ src/engine/platform/ym2610Interface.cpp
src/engine/blip_buf.c src/engine/blip_buf.c
src/engine/safeReader.cpp src/engine/safeReader.cpp
src/engine/safeWriter.cpp src/engine/safeWriter.cpp
src/engine/dispatchContainer.cpp
src/engine/engine.cpp src/engine/engine.cpp
src/engine/macroInt.cpp src/engine/macroInt.cpp
src/engine/pattern.cpp src/engine/pattern.cpp

View File

@ -66,21 +66,24 @@ enum DivDispatchCmds {
struct DivCommand { struct DivCommand {
DivDispatchCmds cmd; DivDispatchCmds cmd;
unsigned char chan; unsigned char chan, dis;
int value, value2; int value, value2;
DivCommand(DivDispatchCmds c, unsigned char ch, int val, int val2): DivCommand(DivDispatchCmds c, unsigned char ch, int val, int val2):
cmd(c), cmd(c),
chan(ch), chan(ch),
dis(ch),
value(val), value(val),
value2(val2) {} value2(val2) {}
DivCommand(DivDispatchCmds c, unsigned char ch, int val): DivCommand(DivDispatchCmds c, unsigned char ch, int val):
cmd(c), cmd(c),
chan(ch), chan(ch),
dis(ch),
value(val), value(val),
value2(0) {} value2(0) {}
DivCommand(DivDispatchCmds c, unsigned char ch): DivCommand(DivDispatchCmds c, unsigned char ch):
cmd(c), cmd(c),
chan(ch), chan(ch),
dis(ch),
value(0), value(0),
value2(0) {} value2(0) {}
}; };

View File

@ -0,0 +1,108 @@
#include "engine.h"
#include "platform/genesis.h"
#include "platform/genesisext.h"
#include "platform/sms.h"
#include "platform/gb.h"
#include "platform/pce.h"
#include "platform/nes.h"
#include "platform/c64.h"
#include "platform/arcade.h"
#include "platform/ym2610.h"
#include "platform/ym2610ext.h"
#include "platform/dummy.h"
#include "../ta-log.h"
void DivDispatchContainer::setRates(double gotRate) {
blip_set_rates(bb[0],dispatch->rate,gotRate);
blip_set_rates(bb[1],dispatch->rate,gotRate);
}
void DivDispatchContainer::clear() {
blip_clear(bb[0]);
blip_clear(bb[1]);
temp[0]=0;
temp[1]=0;
prevSample[0]=0;
prevSample[1]=0;
}
void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, bool pal) {
if (dispatch!=NULL) return;
bb[0]=blip_new(32768);
if (bb[0]==NULL) {
logE("not enough memory!\n");
return;
}
bb[1]=blip_new(32768);
if (bb[1]==NULL) {
logE("not enough memory!\n");
return;
}
bbOut[0]=new short[32768];
bbOut[1]=new short[32768];
bbIn[0]=new short[32768];
bbIn[1]=new short[32768];
bbInLen=32768;
switch (sys) {
case DIV_SYSTEM_GENESIS:
dispatch=new DivPlatformGenesis;
break;
case DIV_SYSTEM_GENESIS_EXT:
dispatch=new DivPlatformGenesisExt;
break;
case DIV_SYSTEM_SMS:
dispatch=new DivPlatformSMS;
break;
case DIV_SYSTEM_GB:
dispatch=new DivPlatformGB;
break;
case DIV_SYSTEM_PCE:
dispatch=new DivPlatformPCE;
break;
case DIV_SYSTEM_NES:
dispatch=new DivPlatformNES;
break;
case DIV_SYSTEM_C64_6581:
dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setChipModel(true);
break;
case DIV_SYSTEM_C64_8580:
dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setChipModel(false);
break;
case DIV_SYSTEM_ARCADE:
dispatch=new DivPlatformArcade;
((DivPlatformArcade*)dispatch)->setYMFM(true);
break;
case DIV_SYSTEM_YM2610:
dispatch=new DivPlatformYM2610;
break;
case DIV_SYSTEM_YM2610_EXT:
dispatch=new DivPlatformYM2610Ext;
break;
default:
logW("this system is not supported yet! using dummy platform.\n");
dispatch=new DivPlatformDummy;
break;
}
dispatch->init(eng,chanCount,gotRate,pal);
}
void DivDispatchContainer::quit() {
if (dispatch==NULL) return;
dispatch->quit();
delete dispatch;
dispatch=NULL;
delete[] bbOut[0];
delete[] bbOut[1];
delete[] bbIn[0];
delete[] bbIn[1];
bbInLen=0;
blip_delete(bb[0]);
blip_delete(bb[1]);
}

View File

@ -13,17 +13,6 @@
#ifdef HAVE_JACK #ifdef HAVE_JACK
#include "../audio/jack.h" #include "../audio/jack.h"
#endif #endif
#include "platform/genesis.h"
#include "platform/genesisext.h"
#include "platform/sms.h"
#include "platform/gb.h"
#include "platform/pce.h"
#include "platform/nes.h"
#include "platform/c64.h"
#include "platform/arcade.h"
#include "platform/ym2610.h"
#include "platform/ym2610ext.h"
#include "platform/dummy.h"
#include <math.h> #include <math.h>
#include <zlib.h> #include <zlib.h>
#include <sndfile.h> #include <sndfile.h>
@ -246,117 +235,119 @@ const int chanTypes[11][17]={
}; };
const char* DivEngine::getChannelName(int chan) { const char* DivEngine::getChannelName(int chan) {
switch (song.system[0]) { if (chan<0 || chan>chans) return "??";
switch (sysOfChan[chan]) {
case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759: case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759:
return chanNames[0][chan]; return chanNames[0][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
return chanNames[1][chan]; return chanNames[1][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_GENESIS_EXT:
return chanNames[2][chan]; return chanNames[2][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
return chanNames[3][chan]; return chanNames[3][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GB: case DIV_SYSTEM_GB:
return chanNames[4][chan]; return chanNames[4][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_PCE: case DIV_SYSTEM_PCE:
return chanNames[5][chan]; return chanNames[5][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
return chanNames[6][chan]; return chanNames[6][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580:
return chanNames[7][chan]; return chanNames[7][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_ARCADE:
return chanNames[8][chan]; return chanNames[8][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
return chanNames[9][chan]; return chanNames[9][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
return chanNames[10][chan]; return chanNames[10][dispatchChanOfChan[chan]];
break; break;
} }
return "??"; return "??";
} }
const char* DivEngine::getChannelShortName(int chan) { const char* DivEngine::getChannelShortName(int chan) {
switch (song.system[0]) { if (chan<0 || chan>chans) return "??";
switch (sysOfChan[chan]) {
case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759: case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759:
return chanShortNames[0][chan]; return chanShortNames[0][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
return chanShortNames[1][chan]; return chanShortNames[1][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_GENESIS_EXT:
return chanShortNames[2][chan]; return chanShortNames[2][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
return chanShortNames[3][chan]; return chanShortNames[3][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GB: case DIV_SYSTEM_GB:
return chanShortNames[4][chan]; return chanShortNames[4][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_PCE: case DIV_SYSTEM_PCE:
return chanShortNames[5][chan]; return chanShortNames[5][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
return chanShortNames[6][chan]; return chanShortNames[6][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580:
return chanShortNames[7][chan]; return chanShortNames[7][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_ARCADE:
return chanShortNames[8][chan]; return chanShortNames[8][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
return chanShortNames[9][chan]; return chanShortNames[9][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
return chanShortNames[10][chan]; return chanShortNames[10][dispatchChanOfChan[chan]];
break; break;
} }
return "??"; return "??";
} }
int DivEngine::getChannelType(int chan) { int DivEngine::getChannelType(int chan) {
switch (song.system[0]) { switch (sysOfChan[chan]) {
case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759: case DIV_SYSTEM_NULL: case DIV_SYSTEM_YMU759:
return chanTypes[0][chan]; return chanTypes[0][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
return chanTypes[1][chan]; return chanTypes[1][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_GENESIS_EXT:
return chanTypes[2][chan]; return chanTypes[2][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
return chanTypes[3][chan]; return chanTypes[3][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_GB: case DIV_SYSTEM_GB:
return chanTypes[4][chan]; return chanTypes[4][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_PCE: case DIV_SYSTEM_PCE:
return chanTypes[5][chan]; return chanTypes[5][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_NES: case DIV_SYSTEM_NES:
return chanTypes[6][chan]; return chanTypes[6][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580:
return chanTypes[7][chan]; return chanTypes[7][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_ARCADE:
return chanTypes[8][chan]; return chanTypes[8][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
return chanTypes[9][chan]; return chanTypes[9][dispatchChanOfChan[chan]];
break; break;
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
return chanTypes[10][chan]; return chanTypes[10][dispatchChanOfChan[chan]];
break; break;
} }
return 1; return 1;
@ -882,7 +873,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
isBusy.lock(); isBusy.lock();
song.unload(); song.unload();
song=ds; song=ds;
chans=getChannelCount(song.system[0]); recalcChans();
renderSamples(); renderSamples();
isBusy.unlock(); isBusy.unlock();
if (active) { if (active) {
@ -1494,7 +1485,7 @@ void DivEngine::createNew() {
song.unload(); song.unload();
song=DivSong(); song=DivSong();
song.system[0]=sys; song.system[0]=sys;
chans=getChannelCount(song.system[0]); recalcChans();
renderSamples(); renderSamples();
isBusy.unlock(); isBusy.unlock();
initDispatch(); initDispatch();
@ -1503,17 +1494,17 @@ void DivEngine::createNew() {
isBusy.unlock(); isBusy.unlock();
} }
void DivEngine::changeSystem(DivSystem which) { void DivEngine::changeSystem(int index, DivSystem which) {
quitDispatch(); quitDispatch();
isBusy.lock(); isBusy.lock();
song.system[0]=which; song.system[index]=which;
chans=getChannelCount(song.system[0]); recalcChans();
// instrument safety check // instrument safety check (TODO: rewrite for multi-system)
for (DivInstrument* i: song.ins) { for (DivInstrument* i: song.ins) {
if (!isFMSystem(song.system[0]) && i->mode) { if (!isFMSystem(song.system[index]) && i->mode) {
i->mode=false; i->mode=false;
} }
if (!isSTDSystem(song.system[0]) && !i->mode) { if (!isSTDSystem(song.system[index]) && !i->mode) {
i->mode=true; i->mode=true;
} }
} }
@ -1557,9 +1548,12 @@ void DivEngine::playSub(bool preserveDrift) {
int goal=curOrder; int goal=curOrder;
curOrder=0; curOrder=0;
curRow=0; curRow=0;
int prevDrift=clockDrift; int prevDrift[32];
clockDrift=0; for (int i=0; i<song.systemLen; i++) {
cycles=0; prevDrift[i]=disCont[i].clockDrift;
disCont[i].clockDrift=0;
disCont[i].cycles=0;
}
if (preserveDrift) { if (preserveDrift) {
endOfSong=false; endOfSong=false;
} else { } else {
@ -1568,22 +1562,24 @@ void DivEngine::playSub(bool preserveDrift) {
} }
speedAB=false; speedAB=false;
playing=true; playing=true;
dispatch->setSkipRegisterWrites(true); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true);
while (curOrder<goal) { while (curOrder<goal) {
if (nextTick(preserveDrift)) break; if (nextTick(preserveDrift)) break;
} }
dispatch->setSkipRegisterWrites(false); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
if (goal>0) { if (goal>0) {
dispatch->forceIns(); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->forceIns();
} }
repeatPattern=oldRepeatPattern; repeatPattern=oldRepeatPattern;
if (preserveDrift) { for (int i=0; i<song.systemLen; i++) {
clockDrift=prevDrift; if (preserveDrift) {
} else { disCont[i].clockDrift=prevDrift[i];
clockDrift=0; } else {
disCont[i].clockDrift=0;
disCont[i].cycles=0;
}
} }
if (!preserveDrift) { if (!preserveDrift) {
cycles=0;
ticks=1; ticks=1;
} }
} }
@ -1609,10 +1605,25 @@ void DivEngine::stop() {
isBusy.unlock(); isBusy.unlock();
} }
void DivEngine::recalcChans() {
chans=0;
int chanIndex=0;
for (int i=0; i<song.systemLen; i++) {
int chanCount=getChannelCount(song.system[i]);
chans+=chanCount;
for (int j=0; j<chanCount; j++) {
sysOfChan[chanIndex]=song.system[i];
dispatchOfChan[chanIndex]=i;
dispatchChanOfChan[chanIndex]=j;
chanIndex++;
}
}
}
void DivEngine::reset() { void DivEngine::reset() {
for (int i=0; i<DIV_MAX_CHANS; i++) { for (int i=0; i<DIV_MAX_CHANS; i++) {
chan[i]=DivChannelState(); chan[i]=DivChannelState();
chan[i].volMax=(dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,i))<<8)|0xff; if (i<chans) chan[i].volMax=(disCont[dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff;
chan[i].volume=chan[i].volMax; chan[i].volume=chan[i].volMax;
} }
extValue=0; extValue=0;
@ -1621,13 +1632,10 @@ void DivEngine::reset() {
speed2=song.speed2; speed2=song.speed2;
nextSpeed=speed1; nextSpeed=speed1;
globalPitch=0; globalPitch=0;
blip_clear(bb[0]); for (int i=0; i<song.systemLen; i++) {
blip_clear(bb[1]); disCont[i].clear();
temp[0]=0; disCont[i].dispatch->reset();
temp[1]=0; }
prevSample[0]=0;
prevSample[1]=0;
dispatch->reset();
} }
void DivEngine::syncReset() { void DivEngine::syncReset() {
@ -1690,9 +1698,9 @@ void DivEngine::previewSample(int sample) {
isBusy.unlock(); isBusy.unlock();
return; return;
} }
blip_clear(bb[2]); blip_clear(samp_bb);
blip_set_rates(bb[2],song.sample[sample]->rate,got.rate); blip_set_rates(samp_bb,song.sample[sample]->rate,got.rate);
prevSample[2]=0; samp_prevSample=0;
sPreview.pos=0; sPreview.pos=0;
sPreview.sample=sample; sPreview.sample=sample;
isBusy.unlock(); isBusy.unlock();
@ -1784,15 +1792,15 @@ void DivEngine::toggleSolo(int chan) {
if (!solo) { if (!solo) {
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
isMuted[i]=(i!=chan); isMuted[i]=(i!=chan);
if (dispatch!=NULL) { if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
dispatch->muteChannel(i,isMuted[i]); disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],isMuted[i]);
} }
} }
} else { } else {
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
isMuted[i]=false; isMuted[i]=false;
if (dispatch!=NULL) { if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
dispatch->muteChannel(i,isMuted[i]); disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],isMuted[i]);
} }
} }
} }
@ -1802,8 +1810,8 @@ void DivEngine::toggleSolo(int chan) {
void DivEngine::muteChannel(int chan, bool mute) { void DivEngine::muteChannel(int chan, bool mute) {
isBusy.lock(); isBusy.lock();
isMuted[chan]=mute; isMuted[chan]=mute;
if (dispatch!=NULL) { if (disCont[dispatchOfChan[chan]].dispatch!=NULL) {
dispatch->muteChannel(chan,isMuted[chan]); disCont[dispatchOfChan[chan]].dispatch->muteChannel(dispatchChanOfChan[chan],isMuted[chan]);
} }
isBusy.unlock(); isBusy.unlock();
} }
@ -2061,9 +2069,10 @@ void DivEngine::setSongRate(int hz, bool pal) {
song.pal=!pal; song.pal=!pal;
song.hz=hz; song.hz=hz;
song.customTempo=(song.hz!=50 && song.hz!=60); song.customTempo=(song.hz!=50 && song.hz!=60);
dispatch->setPAL((!song.pal) || (song.customTempo!=0 && song.hz<53)); for (int i=0; i<song.systemLen; i++) {
blip_set_rates(bb[0],dispatch->rate,got.rate); disCont[i].dispatch->setPAL((!song.pal) || (song.customTempo!=0 && song.hz<53));
blip_set_rates(bb[1],dispatch->rate,got.rate); disCont[i].setRates(got.rate);
}
isBusy.unlock(); isBusy.unlock();
} }
@ -2089,74 +2098,30 @@ void DivEngine::setConsoleMode(bool enable) {
} }
void DivEngine::initDispatch() { void DivEngine::initDispatch() {
if (dispatch!=NULL) return;
isBusy.lock(); isBusy.lock();
switch (song.system[0]) { for (int i=0; i<song.systemLen; i++) {
case DIV_SYSTEM_GENESIS: disCont[i].init(song.system[i],this,getChannelCount(song.system[i]),got.rate,(!song.pal) || (song.customTempo!=0 && song.hz<53));
dispatch=new DivPlatformGenesis; disCont[i].setRates(got.rate);
break;
case DIV_SYSTEM_GENESIS_EXT:
dispatch=new DivPlatformGenesisExt;
break;
case DIV_SYSTEM_SMS:
dispatch=new DivPlatformSMS;
break;
case DIV_SYSTEM_GB:
dispatch=new DivPlatformGB;
break;
case DIV_SYSTEM_PCE:
dispatch=new DivPlatformPCE;
break;
case DIV_SYSTEM_NES:
dispatch=new DivPlatformNES;
break;
case DIV_SYSTEM_C64_6581:
dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setChipModel(true);
break;
case DIV_SYSTEM_C64_8580:
dispatch=new DivPlatformC64;
((DivPlatformC64*)dispatch)->setChipModel(false);
break;
case DIV_SYSTEM_ARCADE:
dispatch=new DivPlatformArcade;
((DivPlatformArcade*)dispatch)->setYMFM(true);
break;
case DIV_SYSTEM_YM2610:
dispatch=new DivPlatformYM2610;
break;
case DIV_SYSTEM_YM2610_EXT:
dispatch=new DivPlatformYM2610Ext;
break;
default:
logW("this system is not supported yet! using dummy platform.\n");
dispatch=new DivPlatformDummy;
break;
} }
dispatch->init(this,getChannelCount(song.system[0]),got.rate,(!song.pal) || (song.customTempo!=0 && song.hz<53)); recalcChans();
chans=getChannelCount(song.system[0]);
blip_set_rates(bb[0],dispatch->rate,got.rate);
blip_set_rates(bb[1],dispatch->rate,got.rate);
isBusy.unlock(); isBusy.unlock();
} }
void DivEngine::quitDispatch() { void DivEngine::quitDispatch() {
if (dispatch==NULL) return;
isBusy.lock(); isBusy.lock();
dispatch->quit(); for (int i=0; i<song.systemLen; i++) {
delete dispatch; disCont[i].quit();
dispatch=NULL; disCont[i].cycles=0;
disCont[i].clockDrift=0;
}
chans=0; chans=0;
playing=false; playing=false;
speedAB=false; speedAB=false;
endOfSong=false; endOfSong=false;
ticks=0; ticks=0;
cycles=0;
curRow=0; curRow=0;
curOrder=0; curOrder=0;
nextSpeed=3; nextSpeed=3;
clockDrift=0;
changeOrd=-1; changeOrd=-1;
changePos=0; changePos=0;
totalTicks=0; totalTicks=0;
@ -2193,6 +2158,7 @@ void DivEngine::quitDispatch() {
#include "winStuff.h" #include "winStuff.h"
#endif #endif
// TODO: all of this!
bool DivEngine::init(String outName) { bool DivEngine::init(String outName) {
// init config // init config
#ifdef _WIN32 #ifdef _WIN32
@ -2279,34 +2245,18 @@ bool DivEngine::init(String outName) {
} }
} }
bb[0]=blip_new(32768); samp_bb=blip_new(32768);
if (bb[0]==NULL) { if (samp_bb==NULL) {
logE("not enough memory!\n"); logE("not enough memory!\n");
return false; return false;
} }
bb[1]=blip_new(32768); samp_bbOut=new short[got.bufsize];
if (bb[1]==NULL) {
logE("not enough memory!\n");
return false;
}
bb[2]=blip_new(32768); samp_bbIn=new short[32768];
if (bb[2]==NULL) { samp_bbInLen=32768;
logE("not enough memory!\n");
return false;
}
bbOut[0]=new short[got.bufsize]; blip_set_rates(samp_bb,44100,got.rate);
bbOut[1]=new short[got.bufsize];
bbOut[2]=new short[got.bufsize];
bbIn[0]=new short[32768];
bbIn[1]=new short[32768];
bbIn[2]=new short[32768];
bbInLen=32768;
blip_set_rates(bb[2],44100,got.rate);
for (int i=0; i<64; i++) { for (int i=0; i<64; i++) {
vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI)); vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI));

View File

@ -90,10 +90,27 @@ struct DivDispatchContainer {
int temp[2], prevSample[2]; int temp[2], prevSample[2];
short* bbIn[2]; short* bbIn[2];
short* bbOut[2]; short* bbOut[2];
int cycles, clockDrift;
void setRates(double gotRate);
void clear();
void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, bool pal);
void quit();
DivDispatchContainer():
dispatch(NULL),
bb{NULL,NULL},
bbInLen(0),
temp{0,0},
prevSample{0,0},
bbIn{NULL,NULL},
bbOut{NULL,NULL},
cycles(0),
clockDrift(0) {}
}; };
class DivEngine { class DivEngine {
DivDispatch* dispatch; DivDispatchContainer disCont[32];
TAAudio* output; TAAudio* output;
TAAudioDesc want, got; TAAudioDesc want, got;
int chans; int chans;
@ -106,7 +123,7 @@ class DivEngine {
bool extValuePresent; bool extValuePresent;
bool repeatPattern; bool repeatPattern;
bool metronome; bool metronome;
int ticks, cycles, curRow, curOrder, remainingLoops, nextSpeed, clockDrift; int ticks, curRow, curOrder, remainingLoops, nextSpeed;
int changeOrd, changePos, totalTicks, totalCmds, lastCmds, cmdsPerSecond, globalPitch; int changeOrd, changePos, totalTicks, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue; unsigned char extValue;
unsigned char speed1, speed2; unsigned char speed1, speed2;
@ -116,6 +133,9 @@ class DivEngine {
std::map<String,String> conf; std::map<String,String> conf;
std::queue<DivNoteEvent> pendingNotes; std::queue<DivNoteEvent> pendingNotes;
bool isMuted[DIV_MAX_CHANS]; bool isMuted[DIV_MAX_CHANS];
DivSystem sysOfChan[DIV_MAX_CHANS];
int dispatchOfChan[DIV_MAX_CHANS];
int dispatchChanOfChan[DIV_MAX_CHANS];
std::mutex isBusy; std::mutex isBusy;
String configPath; String configPath;
String configFile; String configFile;
@ -131,11 +151,11 @@ class DivEngine {
short vibTable[64]; short vibTable[64];
blip_buffer_t* bb[3]; blip_buffer_t* samp_bb;
size_t bbInLen; size_t samp_bbInLen;
int temp[3], prevSample[3]; int samp_temp, samp_prevSample;
short* bbIn[3]; short* samp_bbIn;
short* bbOut[3]; short* samp_bbOut;
unsigned char* metroTick; unsigned char* metroTick;
size_t metroTickLen; size_t metroTickLen;
float metroFreq, metroPos; float metroFreq, metroPos;
@ -153,6 +173,7 @@ class DivEngine {
bool nextTick(bool noAccum=false); bool nextTick(bool noAccum=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
void recalcChans();
void renderSamples(); void renderSamples();
void reset(); void reset();
void playSub(bool preserveDrift); void playSub(bool preserveDrift);
@ -376,7 +397,13 @@ class DivEngine {
void renderSamplesP(); void renderSamplesP();
// change system // change system
void changeSystem(DivSystem which); void changeSystem(int index, DivSystem which);
// add system
void addSystem(DivSystem which);
// remove system
void removeSystem(int index);
// get last error // get last error
String getLastError(); String getLastError();
@ -407,12 +434,10 @@ class DivEngine {
repeatPattern(false), repeatPattern(false),
metronome(false), metronome(false),
ticks(0), ticks(0),
cycles(0),
curRow(0), curRow(0),
curOrder(0), curOrder(0),
remainingLoops(-1), remainingLoops(-1),
nextSpeed(3), nextSpeed(3),
clockDrift(0),
changeOrd(-1), changeOrd(-1),
changePos(0), changePos(0),
totalTicks(0), totalTicks(0),
@ -424,9 +449,9 @@ class DivEngine {
speed2(3), speed2(3),
view(DIV_STATUS_NOTHING), view(DIV_STATUS_NOTHING),
audioEngine(DIV_AUDIO_SDL), audioEngine(DIV_AUDIO_SDL),
bbInLen(0), samp_bbInLen(0),
temp{0,0}, samp_temp(0),
prevSample{0,0}, samp_prevSample(0),
metroTick(NULL), metroTick(NULL),
metroTickLen(0), metroTickLen(0),
metroFreq(0), metroFreq(0),

View File

@ -90,11 +90,12 @@ int DivEngine::dispatchCmd(DivCommand c) {
printf("%8d | %d: %s(%d, %d)\n",totalTicks,c.chan,cmdName[c.cmd],c.value,c.value2); printf("%8d | %d: %s(%d, %d)\n",totalTicks,c.chan,cmdName[c.cmd],c.value,c.value2);
} }
totalCmds++; totalCmds++;
return dispatch->dispatch(c); c.chan=dispatchChanOfChan[c.dis];
return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c);
} }
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
switch (song.system[0]) { switch (sysOfChan[ch]) {
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_GENESIS_EXT:
switch (effect) { switch (effect) {
@ -172,7 +173,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
} }
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) { bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
switch (song.system[0]) { switch (sysOfChan[ch]) {
case DIV_SYSTEM_GENESIS: case DIV_SYSTEM_GENESIS:
case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_GENESIS_EXT:
case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_ARCADE:
@ -180,7 +181,7 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
switch (effect) { switch (effect) {
case 0x10: // LFO or noise mode case 0x10: // LFO or noise mode
if (song.system[0]==DIV_SYSTEM_ARCADE) { if (sysOfChan[ch]==DIV_SYSTEM_ARCADE) {
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
} else { } else {
dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
@ -207,12 +208,12 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
} }
break; break;
case 0x17: // arcade LFO case 0x17: // arcade LFO
if (song.system[0]==DIV_SYSTEM_ARCADE) { if (sysOfChan[ch]==DIV_SYSTEM_ARCADE) {
dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal));
} }
break; break;
case 0x18: // EXT or LFO waveform case 0x18: // EXT or LFO waveform
if (song.system[0]==DIV_SYSTEM_ARCADE) { if (sysOfChan[ch]==DIV_SYSTEM_ARCADE) {
dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal));
} else { } else {
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal));
@ -234,29 +235,29 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31)); dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31));
break; break;
case 0x20: // PCM frequency or Neo Geo PSG mode case 0x20: // PCM frequency or Neo Geo PSG mode
if (song.system[0]==DIV_SYSTEM_ARCADE) { if (sysOfChan[ch]==DIV_SYSTEM_ARCADE) {
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
} else if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) { } else if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
} }
break; break;
case 0x21: // Neo Geo PSG noise freq case 0x21: // Neo Geo PSG noise freq
if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) { if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
} }
break; break;
case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable
if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) { if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal));
} }
break; break;
case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low
if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) { if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal));
} }
break; break;
case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high
if (song.system[0]==DIV_SYSTEM_YM2610 || song.system[0]==DIV_SYSTEM_YM2610_EXT) { if (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT) {
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal));
} }
break; break;
@ -322,7 +323,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].delayOrder=whatOrder; chan[i].delayOrder=whatOrder;
chan[i].delayRow=whatRow; chan[i].delayRow=whatRow;
if (effectVal==nextSpeed) { if (effectVal==nextSpeed) {
if (song.system[0]!=DIV_SYSTEM_YM2610 && song.system[0]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true; if (sysOfChan[i]!=DIV_SYSTEM_YM2610 && sysOfChan[i]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true;
} else { } else {
chan[i].delayLocked=false; chan[i].delayLocked=false;
} }
@ -348,10 +349,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;
chan[i].stopOnOff=false; chan[i].stopOnOff=false;
} }
if (dispatch->keyOffAffectsPorta(i)) { if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;
if (i==2 && song.system[0]==DIV_SYSTEM_SMS) { if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) {
chan[i+1].portaNote=-1; chan[i+1].portaNote=-1;
chan[i+1].portaSpeed=-1; chan[i+1].portaSpeed=-1;
} }
@ -361,7 +362,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].oldNote=chan[i].note; chan[i].oldNote=chan[i].note;
chan[i].note=pat->data[whatRow][0]+pat->data[whatRow][1]*12; chan[i].note=pat->data[whatRow][0]+pat->data[whatRow][1]*12;
if (!chan[i].keyOn) { if (!chan[i].keyOn) {
if (dispatch->keyOffAffectsArp(i)) { if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsArp(dispatchChanOfChan[i])) {
chan[i].arp=0; chan[i].arp=0;
} }
} }
@ -428,7 +429,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;
chan[i].inPorta=false; chan[i].inPorta=false;
} else { } else {
chan[i].portaNote=dispatch->getPortaFloor(i); chan[i].portaNote=disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]);
chan[i].portaSpeed=effectVal; chan[i].portaSpeed=effectVal;
chan[i].portaStop=true; chan[i].portaStop=true;
chan[i].nowYouCanStop=false; chan[i].nowYouCanStop=false;
@ -507,7 +508,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
break; break;
case 0xe5: // pitch case 0xe5: // pitch
chan[i].pitch=effectVal-0x80; chan[i].pitch=effectVal-0x80;
if (song.system[0]==DIV_SYSTEM_ARCADE) { // arcade pitch oddity if (sysOfChan[i]==DIV_SYSTEM_ARCADE) { // arcade pitch oddity
chan[i].pitch*=2; chan[i].pitch*=2;
if (chan[i].pitch<-128) chan[i].pitch=-128; if (chan[i].pitch<-128) chan[i].pitch=-128;
if (chan[i].pitch>127) chan[i].pitch=127; if (chan[i].pitch>127) chan[i].pitch=127;
@ -708,11 +709,15 @@ bool DivEngine::nextTick(bool noAccum) {
divider=50; divider=50;
} }
} }
cycles=dispatch->rate/divider;
clockDrift+=dispatch->rate%divider; for (int i=0; i<song.systemLen; i++) {
if (clockDrift>=divider) { DivDispatchContainer& dc=dispatch[i];
clockDrift-=divider; dc.cycles=dc.dispatch->rate/divider;
cycles++; dc.clockDrift+=dc.dispatch->rate%divider;
if (dc.clockDrift>=divider) {
dc.clockDrift-=divider;
dc.cycles++;
}
} }
while (!pendingNotes.empty()) { while (!pendingNotes.empty()) {
@ -813,7 +818,7 @@ bool DivEngine::nextTick(bool noAccum) {
} }
// system tick // system tick
dispatch->tick(); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick();
if (!freelance) { if (!freelance) {
if (!noAccum) totalTicks++; if (!noAccum) totalTicks++;
@ -837,6 +842,13 @@ bool DivEngine::nextTick(bool noAccum) {
return ret; return ret;
} }
// TODO: all of this!
// PLAYBACK LOGIC:
// 1. end of buffer for all chips? if so quit
// 2. are all chips clocked yet?
// if not clock them until possible and try again
// 3. engine tick
void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) { void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) {
if (out!=NULL) { if (out!=NULL) {
memset(out[0],0,size*sizeof(float)); memset(out[0],0,size*sizeof(float));
@ -869,10 +881,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
} }
} }
if (!playing || dispatch==NULL) { if (!playing) {
isBusy.unlock(); isBusy.unlock();
return; return;
} }
// logic starts here
size_t runtotal=blip_clocks_needed(bb[0],size); size_t runtotal=blip_clocks_needed(bb[0],size);
if (runtotal>bbInLen) { if (runtotal>bbInLen) {

View File

@ -1713,9 +1713,6 @@ void FurnaceGUI::editAdvance() {
void FurnaceGUI::prepareUndo(ActionType action) { void FurnaceGUI::prepareUndo(ActionType action) {
int order=e->getOrder(); int order=e->getOrder();
switch (action) { switch (action) {
case GUI_ACTION_CHANGE_SYSTEM:
oldSystem=e->song.system[0];
break;
case GUI_ACTION_CHANGE_ORDER: case GUI_ACTION_CHANGE_ORDER:
oldOrders=e->song.orders; oldOrders=e->song.orders;
oldOrdersLen=e->song.ordersLen; oldOrdersLen=e->song.ordersLen;
@ -1744,13 +1741,6 @@ void FurnaceGUI::makeUndo(ActionType action) {
s.order=order; s.order=order;
s.nibble=curNibble; s.nibble=curNibble;
switch (action) { switch (action) {
case GUI_ACTION_CHANGE_SYSTEM:
if (oldSystem!=e->song.system[0]) {
s.oldSystem=oldSystem;
s.newSystem=e->song.system[0];
doPush=true;
}
break;
case GUI_ACTION_CHANGE_ORDER: case GUI_ACTION_CHANGE_ORDER:
for (int i=0; i<32; i++) { for (int i=0; i<32; i++) {
for (int j=0; j<128; j++) { for (int j=0; j<128; j++) {
@ -2085,10 +2075,6 @@ void FurnaceGUI::doUndo() {
modified=true; modified=true;
switch (us.type) { switch (us.type) {
case GUI_ACTION_CHANGE_SYSTEM:
e->changeSystem(us.oldSystem);
updateWindowTitle();
break;
case GUI_ACTION_CHANGE_ORDER: case GUI_ACTION_CHANGE_ORDER:
e->song.ordersLen=us.oldOrdersLen; e->song.ordersLen=us.oldOrdersLen;
for (UndoOrderData& i: us.ord) { for (UndoOrderData& i: us.ord) {
@ -2126,10 +2112,6 @@ void FurnaceGUI::doRedo() {
modified=true; modified=true;
switch (us.type) { switch (us.type) {
case GUI_ACTION_CHANGE_SYSTEM:
e->changeSystem(us.newSystem);
updateWindowTitle();
break;
case GUI_ACTION_CHANGE_ORDER: case GUI_ACTION_CHANGE_ORDER:
e->song.ordersLen=us.newOrdersLen; e->song.ordersLen=us.newOrdersLen;
for (UndoOrderData& i: us.ord) { for (UndoOrderData& i: us.ord) {
@ -2575,10 +2557,8 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
#define sysChangeOption(x) \ #define sysChangeOption(x) \
if (ImGui::MenuItem(e->getSystemName(x),NULL,e->song.system[0]==x)) { \ if (ImGui::MenuItem(e->getSystemName(x),NULL,e->song.system[0]==x)) { \
prepareUndo(GUI_ACTION_CHANGE_SYSTEM); \ e->changeSystem(0,x); \
e->changeSystem(x); \
updateWindowTitle(); \ updateWindowTitle(); \
makeUndo(GUI_ACTION_CHANGE_SYSTEM); \
} }
bool FurnaceGUI::loop() { bool FurnaceGUI::loop() {

View File

@ -87,7 +87,6 @@ struct SelectionPoint {
}; };
enum ActionType { enum ActionType {
GUI_ACTION_CHANGE_SYSTEM,
GUI_ACTION_CHANGE_ORDER, GUI_ACTION_CHANGE_ORDER,
GUI_ACTION_PATTERN_EDIT, GUI_ACTION_PATTERN_EDIT,
GUI_ACTION_PATTERN_DELETE, GUI_ACTION_PATTERN_DELETE,