giga-refactor, part 2

This commit is contained in:
tildearrow 2025-11-12 05:06:51 -05:00
parent a654d33df2
commit db419dc6c8
27 changed files with 282 additions and 237 deletions

View file

@ -704,7 +704,7 @@ bool DivCSPlayer::init() {
// initialize state
for (int i=0; i<e->getTotalChannelCount(); i++) {
chan[i].volMax=(e->getDispatch(e->dispatchOfChan[i])->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,e->dispatchChanOfChan[i]))<<8)|0xff;
chan[i].volMax=(e->getDispatch(e->song.dispatchOfChan[i])->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,e->song.dispatchChanOfChan[i]))<<8)|0xff;
chan[i].volume=chan[i].volMax;
}

View file

@ -1303,7 +1303,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// write header
w->write("FCS",4);
w->writeS(chans);
w->writeS(song.chans);
// flags
w->writeC((options.longPointers?1:0)|(options.bigEndian?2:0));
// reserved
@ -1313,7 +1313,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
w->writeC(0);
}
// offsets
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]=new SafeWriter;
chanStream[i]->init();
if (options.longPointers) {
@ -1323,7 +1323,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
}
// max stack sizes
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
w->writeC(0);
}
@ -1338,7 +1338,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 0: play the song and log channel command streams
// song beginning marker
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xd0);
chanStream[i]->writeC(i);
chanStream[i]->writeC(0x00);
@ -1350,7 +1350,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
chanStream[i]->writeC(0x00);
}
while (!done) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
tickPos[i].push_back(chanStream[i]->tell());
}
if (loopTick==-1) {
@ -1359,7 +1359,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
logI("loop is on tick %d",tick);
loopTick=tick;
// loop marker
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xd0);
chanStream[i]->writeC(i);
chanStream[i]->writeC(0x00);
@ -1410,7 +1410,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
}
cmdStream.clear();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xde);
// padding
chanStream[i]->writeC(0x00);
@ -1424,7 +1424,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
tick++;
}
if (!playing || loopTick<0) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStream[i]->writeC(0xdf);
// padding
chanStream[i]->writeC(0x00);
@ -1436,7 +1436,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
chanStream[i]->writeC(0x00);
}
} else {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if ((int)tickPos[i].size()>loopTick) {
chanStream[i]->writeC(0xda);
chanStream[i]->writeI(tickPos[i][loopTick]);
@ -1494,7 +1494,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set preset instruments
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xb8) {
@ -1536,7 +1536,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set preset volumes
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xc7) {
@ -1578,7 +1578,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// set speed dial commands
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
if (buf[i]==0xd7) {
@ -1601,7 +1601,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 2: condense delays
if (!options.noDelayCondense) {
// calculate delay usage
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
int delayCount=0;
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
@ -1639,7 +1639,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
}
// condense delays
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
int delayPos=-1;
int delayCount=0;
@ -1693,7 +1693,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 3: note off + one-tick wait
// optimize one-tick gaps sometimes used in songs
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf();
if (chanStream[h]->size()<8) continue;
for (size_t i=0; i<chanStream[h]->size()-8; i+=8) {
@ -1714,12 +1714,12 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// PASS 4: remove nop's
// this includes modifying call addresses to compensate
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
chanStream[h]=stripNops(chanStream[h]);
}
// PASS 5: put all channels together
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chanStreamOff[i]=globalStream->tell();
logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size());
reloc8(chanStream[i]->getFinalBuf(),chanStream[i]->size(),0,globalStream->tell());
@ -1798,7 +1798,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
// also find new offsets
globalStream=stripNopsPacked(globalStream,sortedCmd,chanStreamOff);
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
chanStreamOff[h]+=w->tell();
}
@ -1807,7 +1807,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
w->write(globalStream->getFinalBuf(),globalStream->size());
// calculate max stack sizes
for (int h=0; h<chans; h++) {
for (int h=0; h<song.chans; h++) {
std::stack<unsigned int> callStack;
unsigned int maxStackSize=0;
unsigned char* buf=w->getFinalBuf();
@ -1866,7 +1866,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
delete globalStream;
w->seek(40,SEEK_SET);
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (options.longPointers) {
if (options.bigEndian) {
w->writeI_BE(chanStreamOff[i]);
@ -1884,7 +1884,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
logD("maximum stack sizes:");
unsigned int cumulativeStackSize=0;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
w->writeC(chanStackSize[i]);
logD("- %d: %d",i,chanStackSize[i]);
cumulativeStackSize+=chanStackSize[i];

View file

@ -179,19 +179,23 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0x92:
return _("92xx: Set sample offset (third byte, ×65536)");
}
} else if (chan>=0 && chan<chans) {
DivSysDef* sysDef=sysDefs[sysOfChan[chan]];
auto iter=sysDef->effectHandlers.find(effect);
if (iter!=sysDef->effectHandlers.end()) {
return iter->second.description;
}
iter=sysDef->postEffectHandlers.find(effect);
if (iter!=sysDef->postEffectHandlers.end()) {
return iter->second.description;
}
iter=sysDef->preEffectHandlers.find(effect);
if (iter!=sysDef->preEffectHandlers.end()) {
return iter->second.description;
} else if (chan>=0 && chan<song.chans) {
DivSysDef* sysDef=sysDefs[song.sysOfChan[chan]];
if (sysDef==NULL) {
return notNull?_("Invalid effect"):NULL;
} else {
auto iter=sysDef->effectHandlers.find(effect);
if (iter!=sysDef->effectHandlers.end()) {
return iter->second.description;
}
iter=sysDef->postEffectHandlers.find(effect);
if (iter!=sysDef->postEffectHandlers.end()) {
return iter->second.description;
}
iter=sysDef->preEffectHandlers.find(effect);
if (iter!=sysDef->preEffectHandlers.end()) {
return iter->second.description;
}
}
}
break;
@ -201,7 +205,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
void DivEngine::calcSongTimestamps() {
if (curSubSong!=NULL) {
curSubSong->calcTimestamps(chans,song.grooves,song.jumpTreatment,song.ignoreJumpAtEnd,song.brokenSpeedSel,song.delayBehavior);
curSubSong->calcTimestamps(song.chans,song.grooves,song.jumpTreatment,song.ignoreJumpAtEnd,song.brokenSpeedSel,song.delayBehavior);
}
}
@ -531,6 +535,7 @@ void DivEngine::initSongWithDesc(const char* description, bool inBase64, bool ol
song.systemFlags[index].loadFromBase64(flags.c_str());
}
song.systemLen=index;
song.initDefaultSystemChans();
// extra attributes
song.subsong[0]->hz=c.getDouble("tickRate",60.0);
@ -564,7 +569,8 @@ void DivEngine::createNew(const char* description, String sysName, bool inBase64
} else {
song.systemName=sysName;
}
recalcChans();
song.initDefaultSystemChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -602,7 +608,8 @@ void DivEngine::createNewFromDefaults() {
song.systemName=sysName;
}
recalcChans();
song.initDefaultSystemChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -710,8 +717,8 @@ void DivEngine::changeSong(size_t songIndex) {
}
void DivEngine::copyChannelP(int src, int dest) {
if (src<0 || src>=chans) return;
if (dest<0 || dest>=chans) return;
if (src<0 || src>=song.chans) return;
if (dest<0 || dest>=song.chans) return;
BUSY_BEGIN;
saveLock.lock();
copyChannel(src,dest);
@ -720,8 +727,8 @@ void DivEngine::copyChannelP(int src, int dest) {
}
void DivEngine::swapChannelsP(int src, int dest) {
if (src<0 || src>=chans) return;
if (dest<0 || dest>=chans) return;
if (src<0 || src>=song.chans) return;
if (dest<0 || dest>=song.chans) return;
BUSY_BEGIN;
saveLock.lock();
swapChannels(src,dest);
@ -874,7 +881,7 @@ void DivEngine::delUnusedIns() {
memset(isUsed,0,256*sizeof(bool));
// scan
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
for (size_t j=0; j<song.subsong.size(); j++) {
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
@ -992,12 +999,12 @@ bool DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) {
lastError=_("invalid index");
return false;
}
if (chans-getChannelCount(song.system[index])+getChannelCount(which)>DIV_MAX_CHANS) {
if (song.chans-getChannelCount(song.system[index])+getChannelCount(which)>DIV_MAX_CHANS) {
lastError=fmt::sprintf(_("max number of total channels is %d"),DIV_MAX_CHANS);
return false;
}
int chanCount=chans;
int chanCount=song.chans;
quitDispatch();
BUSY_BEGIN;
saveLock.lock();
@ -1005,7 +1012,7 @@ bool DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) {
if (!preserveOrder) {
int firstChan=0;
int chanMovement=getChannelCount(which)-getChannelCount(song.system[index]);
while (dispatchOfChan[firstChan]!=index) firstChan++;
while (song.dispatchOfChan[firstChan]!=index) firstChan++;
int lastChan=firstChan+getChannelCount(song.system[index]);
if (chanMovement!=0) {
if (chanMovement>0) {
@ -1030,7 +1037,7 @@ bool DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) {
song.system[index]=which;
song.systemFlags[index].clear();
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1047,7 +1054,7 @@ bool DivEngine::addSystem(DivSystem which) {
lastError=fmt::sprintf(_("max number of systems is %d"),DIV_MAX_CHIPS);
return false;
}
if (chans+getChannelCount(which)>DIV_MAX_CHANS) {
if (song.chans+getChannelCount(which)>DIV_MAX_CHANS) {
lastError=fmt::sprintf(_("max number of total channels is %d"),DIV_MAX_CHANS);
return false;
}
@ -1059,7 +1066,7 @@ bool DivEngine::addSystem(DivSystem which) {
song.systemPan[song.systemLen]=0;
song.systemPanFR[song.systemLen]=0;
song.systemFlags[song.systemLen++].clear();
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1101,7 +1108,7 @@ bool DivEngine::duplicateSystem(int index, bool pat, bool end) {
lastError=fmt::sprintf(_("max number of systems is %d"),DIV_MAX_CHIPS);
return false;
}
if (chans+getChannelCount(song.system[index])>DIV_MAX_CHANS) {
if (song.chans+getChannelCount(song.system[index])>DIV_MAX_CHANS) {
lastError=fmt::sprintf(_("max number of total channels is %d"),DIV_MAX_CHANS);
return false;
}
@ -1113,7 +1120,7 @@ bool DivEngine::duplicateSystem(int index, bool pat, bool end) {
song.systemPan[song.systemLen]=song.systemPan[index];
song.systemPanFR[song.systemLen]=song.systemPanFR[index];
song.systemFlags[song.systemLen++]=song.systemFlags[index];
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1184,7 +1191,7 @@ bool DivEngine::duplicateSystem(int index, bool pat, bool end) {
swapSystemUnsafe(i,i-1,false);
}
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1206,14 +1213,14 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) {
lastError=_("invalid index");
return false;
}
int chanCount=chans;
int chanCount=song.chans;
quitDispatch();
BUSY_BEGIN;
saveLock.lock();
if (!preserveOrder) {
int firstChan=0;
while (dispatchOfChan[firstChan]!=index) firstChan++;
while (song.dispatchOfChan[firstChan]!=index) firstChan++;
for (int i=0; i<getChannelCount(song.system[index]); i++) {
stompChannel(i+firstChan);
}
@ -1239,7 +1246,7 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) {
song.systemPanFR[i]=song.systemPanFR[i+1];
song.systemFlags[i]=song.systemFlags[i+1];
}
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1391,7 +1398,7 @@ bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) {
swapSystemUnsafe(src,dest,preserveOrder);
recalcChans();
song.recalcChans();
saveLock.unlock();
BUSY_END;
initDispatch();
@ -1514,28 +1521,28 @@ void DivEngine::setLoops(int loops) {
}
DivChannelState* DivEngine::getChanState(int ch) {
if (ch<0 || ch>=chans) return NULL;
if (ch<0 || ch>=song.chans) return NULL;
return &chan[ch];
}
unsigned short DivEngine::getChanPan(int ch) {
if (ch<0 || ch>=chans) return 0;
return disCont[dispatchOfChan[ch]].dispatch->getPan(dispatchChanOfChan[ch]);
if (ch<0 || ch>=song.chans) return 0;
return disCont[song.dispatchOfChan[ch]].dispatch->getPan(song.dispatchChanOfChan[ch]);
}
void* DivEngine::getDispatchChanState(int ch) {
if (ch<0 || ch>=chans) return NULL;
return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]);
if (ch<0 || ch>=song.chans) return NULL;
return disCont[song.dispatchOfChan[ch]].dispatch->getChanState(song.dispatchChanOfChan[ch]);
}
void DivEngine::getChanPaired(int ch, std::vector<DivChannelPair>& ret) {
if (ch<0 || ch>=chans) return;
disCont[dispatchOfChan[ch]].dispatch->getPaired(dispatchChanOfChan[ch],ret);
if (ch<0 || ch>=song.chans) return;
disCont[song.dispatchOfChan[ch]].dispatch->getPaired(song.dispatchChanOfChan[ch],ret);
}
DivChannelModeHints DivEngine::getChanModeHints(int ch) {
if (ch<0 || ch>=chans) return DivChannelModeHints();
return disCont[dispatchOfChan[ch]].dispatch->getModeHints(dispatchChanOfChan[ch]);
if (ch<0 || ch>=song.chans) return DivChannelModeHints();
return disCont[song.dispatchOfChan[ch]].dispatch->getModeHints(song.dispatchChanOfChan[ch]);
}
unsigned char* DivEngine::getRegisterPool(int sys, int& size, int& depth) {
@ -1547,18 +1554,18 @@ unsigned char* DivEngine::getRegisterPool(int sys, int& size, int& depth) {
}
DivMacroInt* DivEngine::getMacroInt(int chan) {
if (chan<0 || chan>=chans) return NULL;
return disCont[dispatchOfChan[chan]].dispatch->getChanMacroInt(dispatchChanOfChan[chan]);
if (chan<0 || chan>=song.chans) return NULL;
return disCont[song.dispatchOfChan[chan]].dispatch->getChanMacroInt(song.dispatchChanOfChan[chan]);
}
DivSamplePos DivEngine::getSamplePos(int chan) {
if (chan<0 || chan>=chans) return DivSamplePos();
return disCont[dispatchOfChan[chan]].dispatch->getSamplePos(dispatchChanOfChan[chan]);
if (chan<0 || chan>=song.chans) return DivSamplePos();
return disCont[song.dispatchOfChan[chan]].dispatch->getSamplePos(song.dispatchChanOfChan[chan]);
}
DivDispatchOscBuffer* DivEngine::getOscBuffer(int chan) {
if (chan<0 || chan>=chans) return NULL;
return disCont[dispatchOfChan[chan]].dispatch->getOscBuffer(dispatchChanOfChan[chan]);
if (chan<0 || chan>=song.chans) return NULL;
return disCont[song.dispatchOfChan[chan]].dispatch->getOscBuffer(song.dispatchChanOfChan[chan]);
}
void DivEngine::enableCommandStream(bool enable) {
@ -1694,7 +1701,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
if (goal>0 || goalRow>0) {
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->forceIns();
}
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
chan[i].cut=-1;
chan[i].cutType=0;
}
@ -2041,7 +2048,7 @@ void DivEngine::stop() {
}
if (output) if (output->midiOut!=NULL) {
output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0));
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (chan[i].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0));
}
@ -2053,8 +2060,8 @@ void DivEngine::stop() {
}
// reset all chan oscs
for (int i=0; i<chans; i++) {
DivDispatchOscBuffer* buf=disCont[dispatchOfChan[i]].dispatch->getOscBuffer(dispatchChanOfChan[i]);
for (int i=0; i<song.chans; i++) {
DivDispatchOscBuffer* buf=disCont[song.dispatchOfChan[i]].dispatch->getOscBuffer(song.dispatchChanOfChan[i]);
if (buf!=NULL) {
buf->reset();
}
@ -2094,7 +2101,7 @@ const char** DivEngine::getRegisterSheet(int sys) {
void DivEngine::reset() {
if (output) if (output->midiOut!=NULL) {
output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0));
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (chan[i].curMidiNote>=0) {
output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0));
}
@ -2102,7 +2109,7 @@ void DivEngine::reset() {
}
for (int i=0; i<DIV_MAX_CHANS; i++) {
chan[i]=DivChannelState();
if (i<chans) chan[i].volMax=(disCont[dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff;
if (i<song.chans) chan[i].volMax=(disCont[song.dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,song.dispatchChanOfChan[i]))<<8)|0xff;
chan[i].volume=chan[i].volMax;
if (!song.linearPitch) chan[i].vibratoFine=4;
}
@ -2375,16 +2382,16 @@ int DivEngine::getMaxVolumeChan(int ch) {
int DivEngine::mapVelocity(int ch, float vel) {
if (ch<0) return 0;
if (ch>=chans) return 0;
if (disCont[dispatchOfChan[ch]].dispatch==NULL) return 0;
return disCont[dispatchOfChan[ch]].dispatch->mapVelocity(dispatchChanOfChan[ch],vel);
if (ch>=song.chans) return 0;
if (disCont[song.dispatchOfChan[ch]].dispatch==NULL) return 0;
return disCont[song.dispatchOfChan[ch]].dispatch->mapVelocity(song.dispatchChanOfChan[ch],vel);
}
float DivEngine::getGain(int ch, int vol) {
if (ch<0) return 0;
if (ch>=chans) return 0;
if (disCont[dispatchOfChan[ch]].dispatch==NULL) return 0;
return disCont[dispatchOfChan[ch]].dispatch->getGain(dispatchChanOfChan[ch],vol);
if (ch>=song.chans) return 0;
if (disCont[song.dispatchOfChan[ch]].dispatch==NULL) return 0;
return disCont[song.dispatchOfChan[ch]].dispatch->getGain(song.dispatchChanOfChan[ch],vol);
}
unsigned char DivEngine::getOrder() {
@ -2494,7 +2501,7 @@ void DivEngine::toggleMute(int chan) {
void DivEngine::toggleSolo(int chan) {
bool solo=false;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (i==chan) {
solo=true;
continue;
@ -2507,17 +2514,17 @@ void DivEngine::toggleSolo(int chan) {
}
BUSY_BEGIN;
if (!solo) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
isMuted[i]=(i!=chan);
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],isMuted[i]);
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
disCont[song.dispatchOfChan[i]].dispatch->muteChannel(song.dispatchChanOfChan[i],isMuted[i]);
}
}
} else {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
isMuted[i]=false;
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],isMuted[i]);
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
disCont[song.dispatchOfChan[i]].dispatch->muteChannel(song.dispatchChanOfChan[i],isMuted[i]);
}
}
}
@ -2527,18 +2534,18 @@ void DivEngine::toggleSolo(int chan) {
void DivEngine::muteChannel(int chan, bool mute) {
BUSY_BEGIN;
isMuted[chan]=mute;
if (disCont[dispatchOfChan[chan]].dispatch!=NULL) {
disCont[dispatchOfChan[chan]].dispatch->muteChannel(dispatchChanOfChan[chan],isMuted[chan]);
if (disCont[song.dispatchOfChan[chan]].dispatch!=NULL) {
disCont[song.dispatchOfChan[chan]].dispatch->muteChannel(song.dispatchChanOfChan[chan],isMuted[chan]);
}
BUSY_END;
}
void DivEngine::unmuteAll() {
BUSY_BEGIN;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
isMuted[i]=false;
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],isMuted[i]);
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
disCont[song.dispatchOfChan[i]].dispatch->muteChannel(song.dispatchChanOfChan[i],isMuted[i]);
}
}
BUSY_END;
@ -2609,8 +2616,8 @@ int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) {
DivInstrument* ins=new DivInstrument;
int insCount=(int)song.ins.size();
DivInstrumentType prefType;
if (refChan>chans) {
refChan=chans-1;
if (refChan>song.chans) {
refChan=song.chans-1;
}
if (refChan<0) {
prefType=fallbackType;
@ -2634,7 +2641,7 @@ int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) {
break;
}
if (refChan>=0) {
if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
if (song.sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
*ins=song.nullInsQSound;
}
}
@ -2694,7 +2701,7 @@ void DivEngine::delInstrumentUnsafe(int index) {
delete song.ins[index];
song.ins.erase(song.ins.begin()+index);
song.insLen=song.ins.size();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
for (size_t j=0; j<song.subsong.size(); j++) {
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
@ -3004,7 +3011,7 @@ void DivEngine::addOrder(int pos, bool duplicate, bool where) {
}
} else {
bool used[DIV_MAX_PATTERNS];
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
memset(used,0,sizeof(bool)*DIV_MAX_PATTERNS);
for (int j=0; j<curSubSong->ordersLen; j++) {
used[curOrders->ord[i][j]]=true;
@ -3053,7 +3060,7 @@ void DivEngine::deepCloneOrder(int pos, bool where) {
if (curSubSong->ordersLen>=(DIV_MAX_PATTERNS-1)) return;
warnings="";
BUSY_BEGIN_SOFT;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
bool didNotFind=true;
logD("channel %d",i);
order[i]=curOrders->ord[i][pos];
@ -3077,14 +3084,14 @@ void DivEngine::deepCloneOrder(int pos, bool where) {
}
if (where) { // at the end
saveLock.lock();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
curOrders->ord[i][curSubSong->ordersLen]=order[i];
}
curSubSong->ordersLen++;
saveLock.unlock();
} else { // after current order
saveLock.lock();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
for (int j=curSubSong->ordersLen; j>pos; j--) {
curOrders->ord[i][j]=curOrders->ord[i][j-1];
}
@ -3182,7 +3189,7 @@ void DivEngine::moveOrderDown(int& pos) {
}
void DivEngine::exchangeIns(int one, int two) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
for (size_t j=0; j<song.subsong.size(); j++) {
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
@ -3468,7 +3475,7 @@ void DivEngine::patchDisconnectAll(unsigned int portSet) {
}
void DivEngine::noteOn(int chan, int ins, int note, int vol) {
if (chan<0 || chan>=chans) return;
if (chan<0 || chan>=song.chans) return;
BUSY_BEGIN;
pendingNotes.push_back(DivNoteEvent(chan,ins,note,vol,true));
if (!playing) {
@ -3480,7 +3487,7 @@ void DivEngine::noteOn(int chan, int ins, int note, int vol) {
}
void DivEngine::noteOff(int chan) {
if (chan<0 || chan>=chans) return;
if (chan<0 || chan>=song.chans) return;
BUSY_BEGIN;
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false));
if (!playing) {
@ -3497,7 +3504,7 @@ int DivEngine::getViableChannel(int chan, int off, int ins) {
// if there isn't an instrument, just offset chan by off
if (ins==-1) {
return (chan+off)%chans;
return (chan+off)%song.chans;
}
bool isViable[DIV_MAX_CHANS];
@ -3507,7 +3514,7 @@ int DivEngine::getViableChannel(int chan, int off, int ins) {
// this is a copy of the routine in autoNoteOn...... I am lazy
DivInstrument* insInst=getIns(ins);
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (ins==-1 || ins>=song.insLen || getPreferInsType(i)==insInst->type || (getPreferInsType(i)==DIV_INS_NULL && finalChanType==DIV_CH_NOISE) || getPreferInsSecondType(i)==insInst->type) {
if (insInst->type==DIV_INS_OPL) {
if (insInst->fm.ops==2 || getChannelType(i)==DIV_CH_OP) {
@ -3527,12 +3534,12 @@ int DivEngine::getViableChannel(int chan, int off, int ins) {
// screw it if none of the channels are viable
if (!isAtLeastOneViable) {
return (chan+off)%chans;
return (chan+off)%song.chans;
}
// now offset (confined to viable channels)
int channelsCycled=0;
int i=(chan+1)%chans;
int i=(chan+1)%song.chans;
int attempts=0;
while (true) {
if (isViable[i]) {
@ -3543,7 +3550,7 @@ int DivEngine::getViableChannel(int chan, int off, int ins) {
}
}
if (++i>=chans) {
if (++i>=song.chans) {
i=0;
}
@ -3555,7 +3562,7 @@ int DivEngine::getViableChannel(int chan, int off, int ins) {
}
// fail-safe
return (chan+off)%chans;
return (chan+off)%song.chans;
}
bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol, int transpose) {
@ -3563,7 +3570,7 @@ bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol, int transpose) {
bool canPlayAnyway=false;
bool notInViableChannel=false;
if (midiBaseChan<0) midiBaseChan=0;
if (midiBaseChan>=chans) midiBaseChan=chans-1;
if (midiBaseChan>=song.chans) midiBaseChan=song.chans-1;
int finalChan=midiBaseChan;
int finalChanType=getChannelType(finalChan);
@ -3576,7 +3583,7 @@ bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol, int transpose) {
// 1. check which channels are viable for this instrument
DivInstrument* insInst=getIns(ins);
if (getPreferInsType(finalChan)!=insInst->type && getPreferInsSecondType(finalChan)!=insInst->type && getPreferInsType(finalChan)!=DIV_INS_NULL) notInViableChannel=true;
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (ins==-1 || ins>=song.insLen || getPreferInsType(i)==insInst->type || (getPreferInsType(i)==DIV_INS_NULL && finalChanType==DIV_CH_NOISE) || getPreferInsSecondType(i)==insInst->type) {
if (insInst->type==DIV_INS_OPL) {
if (insInst->fm.ops==2 || getChannelType(i)==DIV_CH_OP) {
@ -3604,7 +3611,7 @@ bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol, int transpose) {
pendingNotes.push_back(DivNoteEvent(finalChan,ins,note+transpose,vol,true));
return true;
}
if (++finalChan>=chans) {
if (++finalChan>=song.chans) {
finalChan=0;
}
} while (finalChan!=midiBaseChan);
@ -3615,7 +3622,7 @@ bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol, int transpose) {
if (isViable[finalChan] && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel) && chan[finalChan].midiAge<chan[candidate].midiAge) {
candidate=finalChan;
}
if (++finalChan>=chans) {
if (++finalChan>=song.chans) {
finalChan=0;
}
} while (finalChan!=midiBaseChan);
@ -3630,8 +3637,8 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) {
if (!playing) {
return;
}
//if (ch<0 || ch>=chans) return;
for (int i=0; i<chans; i++) {
//if (ch<0 || ch>=song.chans) return;
for (int i=0; i<song.chans; i++) {
if (chan[i].midiNote==note) {
pendingNotes.push_back(DivNoteEvent(i,-1,-1,-1,false));
chan[i].midiNote=-1;
@ -3643,7 +3650,7 @@ void DivEngine::autoNoteOffAll() {
if (!playing) {
return;
}
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (chan[i].midiNote!=-1) {
pendingNotes.push_back(DivNoteEvent(i,-1,-1,-1,false));
chan[i].midiNote=-1;
@ -3768,7 +3775,7 @@ bool DivEngine::switchMaster(bool full) {
}
void DivEngine::setMidiBaseChan(int chan) {
if (chan<0 || chan>=chans) chan=0;
if (chan<0 || chan>=song.chans) chan=0;
midiBaseChan=chan;
}
@ -3912,7 +3919,7 @@ void DivEngine::initDispatch(bool isRender) {
autoPatchbay();
saveLock.unlock();
}
recalcChans();
song.recalcChans();
BUSY_END;
}
@ -3928,7 +3935,6 @@ void DivEngine::quitDispatch() {
midiClockDrift=0;
midiTimeCycles=0;
midiTimeDrift=0;
chans=0;
playing=false;
curSpeed=0;
endOfSong=false;

View file

@ -91,7 +91,7 @@ void DivExportAmigaValidation::run() {
size_t lastTick=0;
//bool writeLoop=false;
int loopPos=-1;
for (int i=0; i<e->chans; i++) {
for (int i=0; i<e->song.chans; i++) {
e->chan[i].wentThroughNote=false;
e->chan[i].goneThroughNote=false;
}

View file

@ -1168,6 +1168,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
@ -1175,6 +1176,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
// always convert to normal sample mode (I have no idea how will I do export)
convertLegacySampleMode();

View file

@ -664,6 +664,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
ds.subsong[0]->optimizePatterns();
ds.subsong[0]->rearrangePatterns();
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
@ -671,8 +672,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
recalcChans();
saveLock.unlock();
BUSY_END;
if (active) {

View file

@ -2802,6 +2802,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
@ -2809,6 +2810,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -2136,6 +2136,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
// removal of legacy sample mode
if (song.version<239) {

View file

@ -1675,6 +1675,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
ds.systemName="PC";
// find subsongs
ds.initDefaultSystemChans();
ds.recalcChans();
ds.findSubSongs();
@ -1708,6 +1709,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -431,6 +431,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
ds.insLen=ds.ins.size();
// find subsongs
ds.initDefaultSystemChans();
ds.recalcChans();
ds.findSubSongs();
@ -439,6 +440,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -1179,6 +1179,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
}
// find subsongs
ds.initDefaultSystemChans();
ds.recalcChans();
ds.findSubSongs();
@ -1215,6 +1216,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -302,7 +302,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
for (int j=0; j<s->ordersLen; j++) {
w->writeText(fmt::sprintf("%.2X |",j));
for (int k=0; k<chans; k++) {
for (int k=0; k<song.chans; k++) {
w->writeText(fmt::sprintf(" %.2X",s->orders.ord[k][j]));
}
w->writeText("\n");
@ -318,7 +318,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
for (int k=0; k<s->patLen; k++) {
w->writeText(fmt::sprintf("%.2X ",k));
for (int l=0; l<chans; l++) {
for (int l=0; l<song.chans; l++) {
DivPattern* p=s->pat[l].getPattern(s->orders.ord[l][j],false);
short note, octave;
noteToSplitNote(p->newData[k][DIV_PAT_NOTE],note,octave);

View file

@ -711,6 +711,7 @@ bool DivEngine::loadTFMv1(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;
@ -905,6 +906,7 @@ bool DivEngine::loadTFMv2(unsigned char* file, size_t len) {
info.loopPos=loopPos;
TFMParsePattern(info);
ds.initDefaultSystemChans();
ds.recalcChans();
if (active) quitDispatch();
@ -912,6 +914,7 @@ bool DivEngine::loadTFMv2(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -1377,6 +1377,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
}
// find subsongs
ds.initDefaultSystemChans();
ds.recalcChans();
ds.findSubSongs();
@ -1385,6 +1386,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
saveLock.lock();
song.unload();
song=ds;
hasLoadedSomething=true;
changeSong(0);
saveLock.unlock();
BUSY_END;

View file

@ -22,6 +22,7 @@
#include "engine.h"
#include <fmt/printf.h>
// TODO: this function could be in DivSong instead
bool DivEngine::convertLegacySampleMode() {
logD("converting legacy sample mode...");
int legacyInsInit=-1;
@ -114,7 +115,7 @@ bool DivEngine::convertLegacySampleMode() {
};
for (DivSubSong* h: song.subsong) {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// 0: sample off
// 1: legacy mode
// 2: normal mode
@ -125,11 +126,11 @@ bool DivEngine::convertLegacySampleMode() {
bool noteOffDisablesSampleMode=false;
bool hasLegacyToggle=false;
switch (sysOfChan[i]) {
switch (song.sysOfChan[i]) {
case DIV_SYSTEM_NES:
case DIV_SYSTEM_5E01:
// NES PCM channel (on by default)
if (dispatchChanOfChan[i]!=4) {
if (song.dispatchChanOfChan[i]!=4) {
continue;
}
sampleMode=1;
@ -137,14 +138,14 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_MMC5:
// MMC5 PCM channel
if (dispatchChanOfChan[i]!=2) {
if (song.dispatchChanOfChan[i]!=2) {
continue;
}
sampleMode=1;
break;
case DIV_SYSTEM_YM2612:
// YM2612 DAC channel
if (dispatchChanOfChan[i]!=5) {
if (song.dispatchChanOfChan[i]!=5) {
continue;
}
hasLegacyToggle=true;
@ -152,7 +153,7 @@ bool DivEngine::convertLegacySampleMode() {
case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2612_CSM:
// YM2612 DAC channel
if (dispatchChanOfChan[i]!=8) {
if (song.dispatchChanOfChan[i]!=8) {
continue;
}
hasLegacyToggle=true;
@ -170,7 +171,7 @@ bool DivEngine::convertLegacySampleMode() {
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_FULL:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<7) {
if (song.dispatchChanOfChan[i]<7) {
continue;
}
sampleMode=1;
@ -180,7 +181,7 @@ bool DivEngine::convertLegacySampleMode() {
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL_EXT:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<10) {
if (song.dispatchChanOfChan[i]<10) {
continue;
}
sampleMode=1;
@ -189,7 +190,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2612_DUALPCM:
// DualPCM DAC
if (dispatchChanOfChan[i]<5) {
if (song.dispatchChanOfChan[i]<5) {
continue;
}
sampleMode=1;
@ -197,7 +198,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
// DualPCM DAC
if (dispatchChanOfChan[i]<8 || dispatchChanOfChan[i]>9) {
if (song.dispatchChanOfChan[i]<8 || song.dispatchChanOfChan[i]>9) {
continue;
}
sampleMode=1;
@ -205,7 +206,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610_CSM:
// Neo Geo CD ADPCM channels
if (dispatchChanOfChan[i]<11) {
if (song.dispatchChanOfChan[i]<11) {
continue;
}
sampleMode=1;
@ -214,7 +215,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B:
// ADPCM channels
if (dispatchChanOfChan[i]<9) {
if (song.dispatchChanOfChan[i]<9) {
continue;
}
sampleMode=1;
@ -223,7 +224,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B_EXT:
// ADPCM channels
if (dispatchChanOfChan[i]<12) {
if (song.dispatchChanOfChan[i]<12) {
continue;
}
sampleMode=1;
@ -232,7 +233,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2610B_CSM:
// ADPCM channels
if (dispatchChanOfChan[i]<13) {
if (song.dispatchChanOfChan[i]<13) {
continue;
}
sampleMode=1;
@ -241,7 +242,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608:
// ADPCM channel
if (dispatchChanOfChan[i]!=15) {
if (song.dispatchChanOfChan[i]!=15) {
continue;
}
sampleMode=1;
@ -249,7 +250,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608_EXT:
// ADPCM channel
if (dispatchChanOfChan[i]!=18) {
if (song.dispatchChanOfChan[i]!=18) {
continue;
}
sampleMode=1;
@ -257,7 +258,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_YM2608_CSM:
// ADPCM channel
if (dispatchChanOfChan[i]!=19) {
if (song.dispatchChanOfChan[i]!=19) {
continue;
}
sampleMode=1;
@ -279,21 +280,21 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_Y8950:
// Y8950 ADPCM
if (dispatchChanOfChan[i]!=9) {
if (song.dispatchChanOfChan[i]!=9) {
continue;
}
sampleMode=1;
break;
case DIV_SYSTEM_Y8950_DRUMS:
// Y8950 ADPCM
if (dispatchChanOfChan[i]!=11) {
if (song.dispatchChanOfChan[i]!=11) {
continue;
}
sampleMode=1;
break;
case DIV_SYSTEM_SWAN:
// PCM channel
if (dispatchChanOfChan[i]!=1) {
if (song.dispatchChanOfChan[i]!=1) {
continue;
}
noteOffDisablesSampleMode=true;
@ -301,7 +302,7 @@ bool DivEngine::convertLegacySampleMode() {
break;
case DIV_SYSTEM_VRC6:
// pulse DAC mode
if (dispatchChanOfChan[i]>=2) {
if (song.dispatchChanOfChan[i]>=2) {
continue;
}
hasLegacyToggle=true;

View file

@ -498,16 +498,16 @@ int DivEngine::dispatchCmd(DivCommand c) {
// map the channel to channel of chip
// c.dis is a copy of c.chan because we'll use it in the next call
c.chan=dispatchChanOfChan[c.dis];
c.chan=song.dispatchChanOfChan[c.dis];
// dispatch command to chip dispatch
return disCont[dispatchOfChan[c.dis]].dispatch->dispatch(c);
return disCont[song.dispatchOfChan[c.dis]].dispatch->dispatch(c);
}
// this function handles per-chip normal effects
bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) {
// don't process invalid chips
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
if (sysDef==NULL) return false;
// find the effect handler
auto iter=sysDef->effectHandlers.find(effect);
@ -530,7 +530,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
// this handles per-chip post effects...
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
// don't process invalid chips
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
if (sysDef==NULL) return false;
// find the effect handler
auto iter=sysDef->postEffectHandlers.find(effect);
@ -552,7 +552,7 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
// ...and this handles chip pre-effects
bool DivEngine::perSystemPreEffect(int ch, unsigned char effect, unsigned char effectVal) {
DivSysDef* sysDef=sysDefs[sysOfChan[ch]];
DivSysDef* sysDef=sysDefs[song.sysOfChan[ch]];
if (sysDef==NULL) return false;
auto iter=sysDef->preEffectHandlers.find(effect);
if (iter==sysDef->preEffectHandlers.end()) return false;
@ -721,7 +721,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
// this hack is disabled due to its dirtiness and the fact I
// don't feel like being compatible with a buggy tracker any further
if (effectVal==nextSpeed) {
//if (sysOfChan[i]!=DIV_SYSTEM_YM2610 && sysOfChan[i]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true;
//if (song.sysOfChan[i]!=DIV_SYSTEM_YM2610 && song.sysOfChan[i]!=DIV_SYSTEM_YM2610_EXT) chan[i].delayLocked=true;
} else {
chan[i].delayLocked=false;
}
@ -784,12 +784,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].stopOnOff=false;
}
// depending on the system, portamento may still be disabled
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
chan[i].portaNote=-1;
chan[i].portaSpeed=-1;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
// this here is a now-disabled hack which makes the noise channel also stop when square 3 is
/*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) {
/*if (i==2 && song.sysOfChan[i]==DIV_SYSTEM_SMS) {
chan[i+1].portaNote=-1;
chan[i+1].portaSpeed=-1;
}*/
@ -812,11 +812,11 @@ void DivEngine::processRow(int i, bool afterDelay) {
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
chan[i].stopOnOff=false;
}
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
chan[i].portaNote=-1;
chan[i].portaSpeed=-1;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
/*if (i==2 && sysOfChan[i]==DIV_SYSTEM_SMS) {
/*if (i==2 && song.sysOfChan[i]==DIV_SYSTEM_SMS) {
chan[i+1].portaNote=-1;
chan[i+1].portaSpeed=-1;
}*/
@ -839,7 +839,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
// ...unless there's a way to trigger keyOn twice
if (!chan[i].keyOn) {
// the behavior of arpeggio reset upon note off varies per system
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsArp(dispatchChanOfChan[i])) {
if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsArp(song.dispatchChanOfChan[i])) {
chan[i].arp=0;
dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp));
}
@ -876,7 +876,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
// COMPAT FLAG: legacy ALWAYS_SET_VOLUME behavior (oldAlwaysSetVolume)
// - prior to its addition, volume changes wouldn't be effective depending on the system if the volume is the same as the current one
// - afterwards, volume change is made regardless in order to set the bottom byte of volume ("subvolume")
if (!song.oldAlwaysSetVolume || disCont[dispatchOfChan[i]].dispatch->getLegacyAlwaysSetVolume() || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->newData[whatRow][DIV_PAT_VOL]) {
if (!song.oldAlwaysSetVolume || disCont[song.dispatchOfChan[i]].dispatch->getLegacyAlwaysSetVolume() || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->newData[whatRow][DIV_PAT_VOL]) {
// here we let dispatchCmd() know we can do MIDI aftertouch if there isn't a note
if (pat->newData[whatRow][DIV_PAT_NOTE]==-1) {
chan[i].midiAftertouch=true;
@ -1039,7 +1039,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
// COMPAT FLAG: limit slide range
// - this confines pitch slides from dispatch->getPortaFloor to C-8 (I think)
// - yep, the lowest portamento note depends on the system...
chan[i].portaNote=song.limitSlides?disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]):-60;
chan[i].portaNote=song.limitSlides?disCont[song.dispatchOfChan[i]].dispatch->getPortaFloor(song.dispatchChanOfChan[i]):-60;
chan[i].portaSpeed=effectVal;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
chan[i].portaStop=true;
@ -1684,7 +1684,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].portaNote=song.limitSlides?0x60:255;
} else {
// COMPAT FLAG: limit slide range
chan[i].portaNote=song.limitSlides?disCont[dispatchOfChan[i]].dispatch->getPortaFloor(dispatchChanOfChan[i]):-60;
chan[i].portaNote=song.limitSlides?disCont[song.dispatchOfChan[i]].dispatch->getPortaFloor(song.dispatchChanOfChan[i]):-60;
}
chan[i].portaSpeed=effectVal;
chan[i].portaStop=true;
@ -1726,7 +1726,7 @@ void DivEngine::nextRow() {
if (view==DIV_STATUS_PATTERN && !skipping) {
strcpy(pb1,"");
strcpy(pb3,"");
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// orders
snprintf(pb,4095," %.2x",curOrders->ord[i][curOrder]);
strcat(pb1,pb);
@ -1792,13 +1792,13 @@ void DivEngine::nextRow() {
}
// process row pre on all channels
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// try to find pre effects
processRowPre(i);
}
// process row on all channels
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
// - if not lax, reset the row delay timer so it never happens
if (song.delayBehavior!=2) {
@ -1895,7 +1895,7 @@ void DivEngine::nextRow() {
// post row details
// schedule pre-notes and delays (for C64 and/or a compat flag)
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][curOrder],false);
if (pat->newData[curRow][DIV_PAT_NOTE]!=-1) {
// if there is a note
@ -1904,8 +1904,8 @@ void DivEngine::nextRow() {
if (!chan[i].legato) {
// check whether we should fire a pre-note event
bool wantPreNote=false;
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote();
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
wantPreNote=disCont[song.dispatchOfChan[i]].dispatch->getWantPreNote();
if (wantPreNote) {
bool doPreparePreNote=true;
int addition=0;
@ -2039,7 +2039,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
// this is a check that nullifies any note off event that right after a note on
// it prevents a situation where some notes do not play
for (int i=pendingNotes.size()-1; i>=0; i--) {
if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=chans) continue;
if (pendingNotes[i].channel<0 || pendingNotes[i].channel>=song.chans) continue;
if (pendingNotes[i].on) {
isOn[pendingNotes[i].channel]=true;
} else {
@ -2058,7 +2058,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
// fetch event
DivNoteEvent& note=pendingNotes.front();
// don't if channel is out of bounds or event is canceled
if (note.nop || note.channel<0 || note.channel>=chans) {
if (note.nop || note.channel<0 || note.channel>=song.chans) {
pendingNotes.pop_front();
continue;
}
@ -2077,10 +2077,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
}
// set volume as long as there's one associated with the event
// and the chip has per-channel volume
if (note.volume>=0 && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
if (note.volume>=0 && !disCont[song.dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
// map velocity to curve and then to equivalent chip volume
float curvedVol=pow((float)note.volume/127.0f,midiVolExp);
int mappedVol=disCont[dispatchOfChan[note.channel]].dispatch->mapVelocity(dispatchChanOfChan[note.channel],curvedVol);
int mappedVol=disCont[song.dispatchOfChan[note.channel]].dispatch->mapVelocity(song.dispatchChanOfChan[note.channel],curvedVol);
// fire command
dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,mappedVol));
}
@ -2094,11 +2094,11 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
chan[note.channel].lastIns=note.ins;
} else {
// note off
DivMacroInt* macroInt=disCont[dispatchOfChan[note.channel]].dispatch->getChanMacroInt(dispatchChanOfChan[note.channel]);
DivMacroInt* macroInt=disCont[song.dispatchOfChan[note.channel]].dispatch->getChanMacroInt(song.dispatchChanOfChan[note.channel]);
if (macroInt!=NULL) {
// if the current instrument has a release point in any macros and
// volume is per-channel, send a note release instead of a note off
if (macroInt->hasRelease && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
if (macroInt->hasRelease && !disCont[song.dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,note.channel));
} else {
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel));
@ -2123,7 +2123,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
// delayed row's state before it has a chance to do anything. a typical example would be
// a delay scheduling a note-on to be simultaneous with the next row, and the next row also
// containing a delayed note. if we don't apply the delayed row first, the world explodes.
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
// delay effects
if (chan[i].rowDelay>0) {
if (--chan[i].rowDelay==0) {
@ -2189,7 +2189,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
}
// process stuff such as effects
if (!shallStop) for (int i=0; i<chans; i++) {
if (!shallStop) for (int i=0; i<song.chans; i++) {
// retrigger
if (chan[i].retrigSpeed) {
if (--chan[i].retrigTick<0) {
@ -2463,7 +2463,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
chan[i].stopOnOff=false;
}
// depending on the system, portamento may still be disabled
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsPorta(dispatchChanOfChan[i])) {
if (disCont[song.dispatchOfChan[i]].dispatch->keyOffAffectsPorta(song.dispatchChanOfChan[i])) {
chan[i].portaNote=-1;
chan[i].portaSpeed=-1;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
@ -2564,8 +2564,8 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
shallStop=false;
shallStopSched=false;
// reset all chan oscs
for (int i=0; i<chans; i++) {
DivDispatchOscBuffer* buf=disCont[dispatchOfChan[i]].dispatch->getOscBuffer(dispatchChanOfChan[i]);
for (int i=0; i<song.chans; i++) {
DivDispatchOscBuffer* buf=disCont[song.dispatchOfChan[i]].dispatch->getOscBuffer(song.dispatchChanOfChan[i]);
if (buf!=NULL) {
buf->reset();
}
@ -2858,7 +2858,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
case TA_MIDI_NOTE_OFF: {
if (midiIsDirect) {
// in direct mode, map the event directly to the channel
if (chan<0 || chan>=chans) break;
if (chan<0 || chan>=song.chans) break;
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
} else {
// find a suitable channel and add this event to the queue
@ -2877,7 +2877,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (msg.data[1]==0) {
if (midiIsDirect) {
// in direct mode, map the event directly to the channel
if (chan<0 || chan>=chans) break;
if (chan<0 || chan>=song.chans) break;
pendingNotes.push_back(DivNoteEvent(chan,-1,-1,-1,false,false,true));
} else {
// find a suitable channel and add this event to the queue
@ -2886,7 +2886,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
} else {
if (midiIsDirect) {
// in direct mode, map the event directly to the channel
if (chan<0 || chan>=chans) break;
if (chan<0 || chan>=song.chans) break;
pendingNotes.push_back(DivNoteEvent(chan,ins,msg.data[0]-12,msg.data[1],true,false,true));
} else {
// find a suitable channel and add this event to the queue

View file

@ -17,7 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "song.h"
#include "engine.h"
#include "../ta-log.h"
#include <inttypes.h>
#include <chrono>
@ -691,7 +691,20 @@ void DivSong::findSubSongs() {
}
}
void DivSong::initDefaultSystemChans() {
for (int i=0; i<systemLen; i++) {
const DivSysDef* sysDef=DivEngine::getSystemDef(system[i]);
if (sysDef==NULL) {
systemChans[i]=0;
} else {
systemChans[i]=sysDef->channels;
}
}
}
void DivSong::recalcChans() {
logV("DivSong: recalcChans() called");
bool isInsTypePossible[DIV_INS_MAX];
chans=0;
int chanIndex=0;
@ -707,7 +720,7 @@ void DivSong::recalcChans() {
dispatchFirstChan[chanIndex]=firstChan;
chanIndex++;
DivSysDef* sysDef=DivEngine::getSystemDef(system[i]);
const DivSysDef* sysDef=DivEngine::getSystemDef(system[i]);
if (sysDef!=NULL) {
if (sysDef->chanInsType[j][0]!=DIV_INS_NULL) {
isInsTypePossible[sysDef->chanInsType[j][0]]=true;
@ -729,10 +742,9 @@ void DivSong::recalcChans() {
checkAssetDir(waveDir,wave.size());
checkAssetDir(sampleDir,sample.size());
hasLoadedSomething=true;
logV("%d channels (%d chips)",chans,systemLen);
}
void DivSong::clearSongData() {
for (DivSubSong* i: subsong) {
i->clearData();

View file

@ -429,9 +429,15 @@ struct DivSong {
*/
void clearSamples();
/**
* set systemChans[] to default values.
* call recalcChans() afterwards.
*/
void initDefaultSystemChans();
/**
* recalculate channel count and internal state.
" call after editing system[] or systemChans[].
* call after editing system[] or systemChans[].
*/
void recalcChans();
@ -538,6 +544,8 @@ struct DivSong {
subsong.push_back(new DivSubSong);
system[0]=DIV_SYSTEM_YM2612;
system[1]=DIV_SYSTEM_SMS;
systemChans[0]=6;
systemChans[1]=4;
// OPLL default instrument contest winner - piano_guitar_idk by Weeppiko
nullInsOPLL.type=DIV_INS_OPLL;

View file

@ -51,11 +51,11 @@ int DivEngine::getChannelCount(DivSystem sys) {
}
int DivEngine::getTotalChannelCount() {
return chans;
return song.chans;
}
std::vector<DivInstrumentType>& DivEngine::getPossibleInsTypes() {
return possibleInsTypes;
return song.possibleInsTypes;
}
// for pre-dev103 modules
@ -311,41 +311,41 @@ bool DivEngine::isSTDSystem(DivSystem sys) {
}
const char* DivEngine::getChannelName(int chan) {
if (chan<0 || chan>chans) return "??";
if (chan<0 || chan>song.chans) return "??";
if (!curSubSong->chanName[chan].empty()) return curSubSong->chanName[chan].c_str();
if (sysDefs[sysOfChan[chan]]==NULL) return "??";
if (sysDefs[song.sysOfChan[chan]]==NULL) return "??";
const char* ret=sysDefs[sysOfChan[chan]]->chanNames[dispatchChanOfChan[chan]];
const char* ret=sysDefs[song.sysOfChan[chan]]->chanNames[song.dispatchChanOfChan[chan]];
if (ret==NULL) return "??";
return ret;
}
const char* DivEngine::getChannelShortName(int chan) {
if (chan<0 || chan>chans) return "??";
if (chan<0 || chan>song.chans) return "??";
if (!curSubSong->chanShortName[chan].empty()) return curSubSong->chanShortName[chan].c_str();
if (sysDefs[sysOfChan[chan]]==NULL) return "??";
if (sysDefs[song.sysOfChan[chan]]==NULL) return "??";
const char* ret=sysDefs[sysOfChan[chan]]->chanShortNames[dispatchChanOfChan[chan]];
const char* ret=sysDefs[song.sysOfChan[chan]]->chanShortNames[song.dispatchChanOfChan[chan]];
if (ret==NULL) return "??";
return ret;
}
int DivEngine::getChannelType(int chan) {
if (chan<0 || chan>chans) return DIV_CH_NOISE;
if (sysDefs[sysOfChan[chan]]==NULL) return DIV_CH_NOISE;
return sysDefs[sysOfChan[chan]]->chanTypes[dispatchChanOfChan[chan]];
if (chan<0 || chan>song.chans) return DIV_CH_NOISE;
if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_CH_NOISE;
return sysDefs[song.sysOfChan[chan]]->chanTypes[song.dispatchChanOfChan[chan]];
}
DivInstrumentType DivEngine::getPreferInsType(int chan) {
if (chan<0 || chan>chans) return DIV_INS_STD;
if (sysDefs[sysOfChan[chan]]==NULL) return DIV_INS_STD;
return sysDefs[sysOfChan[chan]]->chanInsType[dispatchChanOfChan[chan]][0];
if (chan<0 || chan>song.chans) return DIV_INS_STD;
if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_INS_STD;
return sysDefs[song.sysOfChan[chan]]->chanInsType[song.dispatchChanOfChan[chan]][0];
}
DivInstrumentType DivEngine::getPreferInsSecondType(int chan) {
if (chan<0 || chan>chans) return DIV_INS_NULL;
if (sysDefs[sysOfChan[chan]]==NULL) return DIV_INS_NULL;
return sysDefs[sysOfChan[chan]]->chanInsType[dispatchChanOfChan[chan]][1];
if (chan<0 || chan>song.chans) return DIV_INS_NULL;
if (sysDefs[song.sysOfChan[chan]]==NULL) return DIV_INS_NULL;
return sysDefs[song.sysOfChan[chan]]->chanInsType[song.dispatchChanOfChan[chan]][1];
}
int DivEngine::minVGMVersion(DivSystem which) {

View file

@ -2689,8 +2689,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
bool alreadyWroteLoop=false;
int ord=-1;
int exportChans=0;
for (int i=0; i<chans; i++) {
if (!willExport[dispatchOfChan[i]]) continue;
for (int i=0; i<song.chans; i++) {
if (!willExport[song.dispatchOfChan[i]]) continue;
exportChans++;
chan[i].wentThroughNote=false;
chan[i].goneThroughNote=false;
@ -2710,8 +2710,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (trailing) beenOneLoopAlready=true;
trailing=true;
if (!loop) countDown=0;
for (int i=0; i<chans; i++) {
if (!willExport[dispatchOfChan[i]]) continue;
for (int i=0; i<song.chans; i++) {
if (!willExport[song.dispatchOfChan[i]]) continue;
chan[i].wentThroughNote=false;
}
}
@ -2719,8 +2719,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
switch (trailingTicks) {
case -1: { // automatic
bool stillHaveTo=false;
for (int i=0; i<chans; i++) {
if (!willExport[dispatchOfChan[i]]) continue;
for (int i=0; i<song.chans; i++) {
if (!willExport[song.dispatchOfChan[i]]) continue;
if (!chan[i].goneThroughNote) continue;
if (!chan[i].wentThroughNote) {
stillHaveTo=true;
@ -2777,8 +2777,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
w->writeC(0x01);
w->writeC(prevOrder);
w->writeC(prevRow);
for (int i=0; i<chans; i++) {
if (!willExport[dispatchOfChan[i]]) continue;
for (int i=0; i<song.chans; i++) {
if (!willExport[song.dispatchOfChan[i]]) continue;
w->writeC(curSubSong->orders.ord[i][prevOrder]);
}
}

View file

@ -63,7 +63,7 @@ void DivEngine::getTotalAudioFiles(int &files) {
break;
}
case DIV_EXPORT_MODE_MANY_CHAN: {
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (!exportChannelMask[i]) continue;
files++;
@ -71,7 +71,7 @@ void DivEngine::getTotalAudioFiles(int &files) {
if (getChannelType(i)==5) {
i++;
while (true) {
if (i>=chans) break;
if (i>=song.chans) break;
if (getChannelType(i)!=5) break;
i++;
}
@ -425,7 +425,7 @@ void DivEngine::runExportThread() {
logI("rendering to files...");
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (!exportChannelMask[i]) continue;
SNDFILE* sf;
@ -476,19 +476,19 @@ void DivEngine::runExportThread() {
MAP_BITRATE;
for (int j=0; j<chans; j++) {
for (int j=0; j<song.chans; j++) {
bool mute=(j!=i);
isMuted[j]=mute;
}
if (getChannelType(i)==5) {
for (int j=i; j<chans; j++) {
for (int j=i; j<song.chans; j++) {
if (getChannelType(j)!=5) break;
isMuted[j]=false;
}
}
for (int j=0; j<chans; j++) {
if (disCont[dispatchOfChan[j]].dispatch!=NULL) {
disCont[dispatchOfChan[j]].dispatch->muteChannel(dispatchChanOfChan[j],isMuted[j]);
for (int j=0; j<song.chans; j++) {
if (disCont[song.dispatchOfChan[j]].dispatch!=NULL) {
disCont[song.dispatchOfChan[j]].dispatch->muteChannel(song.dispatchChanOfChan[j],isMuted[j]);
}
}
@ -549,7 +549,7 @@ void DivEngine::runExportThread() {
if (getChannelType(i)==5) {
i++;
while (true) {
if (i>=chans) break;
if (i>=song.chans) break;
if (getChannelType(i)!=5) break;
i++;
}
@ -564,10 +564,10 @@ void DivEngine::runExportThread() {
delete[] outBuf[i];
}
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
isMuted[i]=false;
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
disCont[dispatchOfChan[i]].dispatch->muteChannel(dispatchChanOfChan[i],false);
if (disCont[song.dispatchOfChan[i]].dispatch!=NULL) {
disCont[song.dispatchOfChan[i]].dispatch->muteChannel(song.dispatchChanOfChan[i],false);
}
}
@ -642,7 +642,7 @@ bool DivEngine::saveAudio(const char* path, DivAudioExportOptions options) {
quitDispatch();
initDispatch(true);
renderSamplesP();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (isMutedBefore[i]) {
muteChannel(i,true);
}
@ -680,7 +680,7 @@ void DivEngine::finishAudioFile() {
quitDispatch();
initDispatch(false);
renderSamplesP();
for (int i=0; i<chans; i++) {
for (int i=0; i<song.chans; i++) {
if (isMutedBefore[i]) {
muteChannel(i,true);
}

View file

@ -868,15 +868,15 @@ void FurnaceGUI::drawChanOsc() {
break;
}
case 's': {
text+=e->getSystemName(e->sysOfChan[ch]);
text+=e->getSystemName(e->song.sysOfChan[ch]);
break;
}
case 'p': {
text+=FurnaceGUI::getSystemPartNumber(e->sysOfChan[ch],e->song.systemFlags[e->dispatchOfChan[ch]]);
text+=FurnaceGUI::getSystemPartNumber(e->song.sysOfChan[ch],e->song.systemFlags[e->song.dispatchOfChan[ch]]);
break;
}
case 'S': {
text+=fmt::sprintf("%d",e->dispatchOfChan[ch]);
text+=fmt::sprintf("%d",e->song.dispatchOfChan[ch]);
break;
}
case 'v': {

View file

@ -78,7 +78,7 @@ void FurnaceGUI::drawChannels() {
ImGui::Button(ICON_FA_ARROWS "##ChanDrag");
ImGui::EndDragDropSource();
} else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("%s #%d\n(drag to swap channels)\n(Shift-drag to copy channel contents)"),e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]);
ImGui::SetTooltip(_("%s #%d\n(drag to swap channels)\n(Shift-drag to copy channel contents)"),e->getSystemName(e->song.sysOfChan[i]),e->song.dispatchChanOfChan[i]);
}
if (ImGui::BeginDragDropTarget()) {
const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN");

View file

@ -118,11 +118,11 @@ void FurnaceGUI::drawDebug() {
ImGui::Columns(e->getTotalChannelCount());
for (int i=0; i<e->getTotalChannelCount(); i++) {
void* ch=e->getDispatchChanState(i);
ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Ch. %d: %d, %d",i,e->dispatchOfChan[i],e->dispatchChanOfChan[i]);
ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Ch. %d: %d, %d",i,e->song.dispatchOfChan[i],e->song.dispatchChanOfChan[i]);
if (ch==NULL) {
ImGui::Text("NULL");
} else {
putDispatchChan(ch,e->dispatchChanOfChan[i],e->sysOfChan[i]);
putDispatchChan(ch,e->song.dispatchChanOfChan[i],e->song.sysOfChan[i]);
}
ImGui::NextColumn();
}

View file

@ -15,7 +15,7 @@ void FurnaceGUI::drawEffectList() {
float availB=ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing();
if (availB>0) {
ImGui::PushTextWrapPos(availB);
ImGui::TextWrapped(_("Chip at cursor: %s"),e->getSystemName(e->sysOfChan[cursor.xCoarse]));
ImGui::TextWrapped(_("Chip at cursor: %s"),e->getSystemName(e->song.sysOfChan[cursor.xCoarse]));
ImGui::PopTextWrapPos();
}
effectSearch.Draw(_("Search"));
@ -55,7 +55,7 @@ void FurnaceGUI::drawEffectList() {
}
prevName=name;
if (fxColors[i]==GUI_COLOR_PATTERN_EFFECT_PANNING) {
DivDispatch* dispatch=e->getDispatch(e->dispatchOfChan[cursor.xCoarse]);
DivDispatch* dispatch=e->getDispatch(e->song.dispatchOfChan[cursor.xCoarse]);
if (dispatch!=NULL) {
int outputs=dispatch->getOutputCount();
if (outputs<2) {

View file

@ -1458,7 +1458,7 @@ void FurnaceGUI::drawPattern() {
for (int j=0; j<8; j++) {
if (pair.pairs[j]==-1) continue;
int pairCh=e->dispatchFirstChan[i]+pair.pairs[j];
int pairCh=e->song.dispatchFirstChan[i]+pair.pairs[j];
if (!e->curSubSong->chanShow[pairCh]) {
continue;
}
@ -1514,7 +1514,7 @@ void FurnaceGUI::drawPattern() {
for (int j=0; j<8; j++) {
if (pair.pairs[j]==-1) continue;
int pairCh=e->dispatchFirstChan[i]+pair.pairs[j];
int pairCh=e->song.dispatchFirstChan[i]+pair.pairs[j];
if (!e->curSubSong->chanShow[pairCh]) {
continue;
}

View file

@ -32,8 +32,8 @@ int logLevel=LOGLEVEL_TRACE;
int logLevel=LOGLEVEL_TRACE; // until done
#endif
FILE* logOut;
FILE* logFile;
FILE* logOut=NULL;
FILE* logFile=NULL;
char* logFileBuf;
char* logFileWriteBuf;
unsigned int logFilePosI;
@ -140,6 +140,7 @@ int writeLog(int level, const char* msg, fmt::printf_args args) {
}
if (logLevel<level) return 0;
if (logOut==NULL) return -1;
switch (level) {
case LOGLEVEL_ERROR:
return fmt::fprintf(logOut,"\x1b[1;31m[ERROR]\x1b[m %s\n",logEntries[pos].text);