diff --git a/src/engine/cmdStream.cpp b/src/engine/cmdStream.cpp index 568f5ee0c..41c2c3cc8 100644 --- a/src/engine/cmdStream.cpp +++ b/src/engine/cmdStream.cpp @@ -704,7 +704,7 @@ bool DivCSPlayer::init() { // initialize state for (int i=0; igetTotalChannelCount(); 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; } diff --git a/src/engine/cmdStreamOps.cpp b/src/engine/cmdStreamOps.cpp index 4b7718424..295862a65 100644 --- a/src/engine/cmdStreamOps.cpp +++ b/src/engine/cmdStreamOps.cpp @@ -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; iinit(); if (options.longPointers) { @@ -1323,7 +1323,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options } } // max stack sizes - for (int i=0; iwriteC(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; iwriteC(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; itell()); } 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; iwriteC(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; iwriteC(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; iwriteC(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; iloopTick) { 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; hgetFinalBuf(); for (size_t i=0; isize(); i+=8) { if (buf[i]==0xb8) { @@ -1536,7 +1536,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options } // set preset volumes - for (int h=0; hgetFinalBuf(); for (size_t i=0; isize(); 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; hgetFinalBuf(); for (size_t i=0; isize(); 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; hgetFinalBuf(); int delayCount=0; for (size_t i=0; isize(); i+=8) { @@ -1639,7 +1639,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options } // condense delays - for (int h=0; hgetFinalBuf(); 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; hgetFinalBuf(); if (chanStream[h]->size()<8) continue; for (size_t i=0; isize()-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; htell(); 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; htell(); } @@ -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 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; iwriteI_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; iwriteC(chanStackSize[i]); logD("- %d: %d",i,chanStackSize[i]); cumulativeStackSize+=chanStackSize[i]; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5c552290a..1de23a682 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -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 && chaneffectHandlers.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 && chaneffectHandlers.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; ipat[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=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& 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; iforceIns(); } - for (int i=0; imidiOut!=NULL) { output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0)); - for (int i=0; i=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; igetOscBuffer(dispatchChanOfChan[i]); + for (int i=0; igetOscBuffer(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=0) { output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0)); } @@ -2102,7 +2109,7 @@ void DivEngine::reset() { } for (int i=0; idispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff; + if (idispatch(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; imuteChannel(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; imuteChannel(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; imuteChannel(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; ipat[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; iordersLen; 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; iord[i][pos]; @@ -3077,14 +3084,14 @@ void DivEngine::deepCloneOrder(int pos, bool where) { } if (where) { // at the end saveLock.lock(); - for (int i=0; iord[i][curSubSong->ordersLen]=order[i]; } curSubSong->ordersLen++; saveLock.unlock(); } else { // after current order saveLock.lock(); - for (int i=0; iordersLen; 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; ipat[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=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=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=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=song.chans) return; + for (int i=0; i=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; diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index 30224e84f..38b61a41f 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -91,7 +91,7 @@ void DivExportAmigaValidation::run() { size_t lastTick=0; //bool writeLoop=false; int loopPos=-1; - for (int i=0; ichans; i++) { + for (int i=0; isong.chans; i++) { e->chan[i].wentThroughNote=false; e->chan[i].goneThroughNote=false; } diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 492f0c21f..2557e4b6d 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -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(); diff --git a/src/engine/fileOps/fc.cpp b/src/engine/fileOps/fc.cpp index 8fbf49502..027dda971 100644 --- a/src/engine/fileOps/fc.cpp +++ b/src/engine/fileOps/fc.cpp @@ -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) { diff --git a/src/engine/fileOps/ftm.cpp b/src/engine/fileOps/ftm.cpp index 1fee6f053..b2df53798 100644 --- a/src/engine/fileOps/ftm.cpp +++ b/src/engine/fileOps/ftm.cpp @@ -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; diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 7a22eed00..6436ba98a 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -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) { diff --git a/src/engine/fileOps/it.cpp b/src/engine/fileOps/it.cpp index 3fe6285a1..3ea6c2bfc 100644 --- a/src/engine/fileOps/it.cpp +++ b/src/engine/fileOps/it.cpp @@ -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; diff --git a/src/engine/fileOps/mod.cpp b/src/engine/fileOps/mod.cpp index 7f933b27f..774a0004b 100644 --- a/src/engine/fileOps/mod.cpp +++ b/src/engine/fileOps/mod.cpp @@ -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; diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index b866b2920..3c03ad2d9 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -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; diff --git a/src/engine/fileOps/text.cpp b/src/engine/fileOps/text.cpp index 3dbc598d3..bab5dc7ea 100644 --- a/src/engine/fileOps/text.cpp +++ b/src/engine/fileOps/text.cpp @@ -302,7 +302,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) { for (int j=0; jordersLen; j++) { w->writeText(fmt::sprintf("%.2X |",j)); - for (int k=0; kwriteText(fmt::sprintf(" %.2X",s->orders.ord[k][j])); } w->writeText("\n"); @@ -318,7 +318,7 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) { for (int k=0; kpatLen; k++) { w->writeText(fmt::sprintf("%.2X ",k)); - for (int l=0; lpat[l].getPattern(s->orders.ord[l][j],false); short note, octave; noteToSplitNote(p->newData[k][DIV_PAT_NOTE],note,octave); diff --git a/src/engine/fileOps/tfm.cpp b/src/engine/fileOps/tfm.cpp index 557ad351b..7ea370f1d 100644 --- a/src/engine/fileOps/tfm.cpp +++ b/src/engine/fileOps/tfm.cpp @@ -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; diff --git a/src/engine/fileOps/xm.cpp b/src/engine/fileOps/xm.cpp index fe0ec35c1..57e59ab3a 100644 --- a/src/engine/fileOps/xm.cpp +++ b/src/engine/fileOps/xm.cpp @@ -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; diff --git a/src/engine/legacySample.cpp b/src/engine/legacySample.cpp index 21734c903..db827adda 100644 --- a/src/engine/legacySample.cpp +++ b/src/engine/legacySample.cpp @@ -22,6 +22,7 @@ #include "engine.h" #include +// 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; i9) { + 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; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 72852444d..abd79aa6c 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -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; iord[i][curOrder]); strcat(pb1,pb); @@ -1792,13 +1792,13 @@ void DivEngine::nextRow() { } // process row pre on all channels - for (int i=0; iord[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; i0) { 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; ikeyOffAffectsPorta(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; igetOscBuffer(dispatchChanOfChan[i]); + for (int i=0; igetOscBuffer(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 diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 7bf33dd9d..dad02d708 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -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 #include @@ -691,7 +691,20 @@ void DivSong::findSubSongs() { } } +void DivSong::initDefaultSystemChans() { + for (int i=0; ichannels; + } + } +} + 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(); diff --git a/src/engine/song.h b/src/engine/song.h index 83414452a..e0bde3f10 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -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; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9f00cb7cf..2baaee2c6 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -51,11 +51,11 @@ int DivEngine::getChannelCount(DivSystem sys) { } int DivEngine::getTotalChannelCount() { - return chans; + return song.chans; } std::vector& 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) { diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index cab97710f..6b59a7e86 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -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; iwriteC(0x01); w->writeC(prevOrder); w->writeC(prevRow); - for (int i=0; iwriteC(curSubSong->orders.ord[i][prevOrder]); } } diff --git a/src/engine/wavOps.cpp b/src/engine/wavOps.cpp index 899f729f8..d65af451d 100644 --- a/src/engine/wavOps.cpp +++ b/src/engine/wavOps.cpp @@ -63,7 +63,7 @@ void DivEngine::getTotalAudioFiles(int &files) { break; } case DIV_EXPORT_MODE_MANY_CHAN: { - for (int i=0; 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; imuteChannel(dispatchChanOfChan[j],isMuted[j]); + for (int j=0; jmuteChannel(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; imuteChannel(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; igetSystemName(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': { diff --git a/src/gui/channels.cpp b/src/gui/channels.cpp index 091a4103a..34f7caab3 100644 --- a/src/gui/channels.cpp +++ b/src/gui/channels.cpp @@ -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"); diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 8e152ebec..96d0a2dce 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -118,11 +118,11 @@ void FurnaceGUI::drawDebug() { ImGui::Columns(e->getTotalChannelCount()); for (int i=0; igetTotalChannelCount(); 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(); } diff --git a/src/gui/effectList.cpp b/src/gui/effectList.cpp index e4339e301..284b8cb1a 100644 --- a/src/gui/effectList.cpp +++ b/src/gui/effectList.cpp @@ -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) { diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 46f799c27..e905d8762 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -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; } diff --git a/src/log.cpp b/src/log.cpp index 215b4ddfc..0504c8f00 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -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