giga-refactor, part 13

get rid of time base
This commit is contained in:
tildearrow 2025-11-16 15:45:24 -05:00
parent 334d8708e2
commit 663f32d9d4
9 changed files with 43 additions and 35 deletions

View file

@ -775,7 +775,7 @@ int DivEngine::duplicateSubSong(int index) {
theCopy->notes=theOrig->notes;
theCopy->hilightA=theOrig->hilightA;
theCopy->hilightB=theOrig->hilightB;
theCopy->timeBase=theOrig->timeBase;
theCopy->effectDivider=theOrig->effectDivider;
theCopy->arpLen=theOrig->arpLen;
theCopy->speeds=theOrig->speeds;
theCopy->virtualTempoN=theOrig->virtualTempoN;

View file

@ -256,11 +256,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
bool customTempo=false;
ds.subsong[0]->timeBase=reader.readC();
unsigned char oldTimeBase=reader.readC();
ds.subsong[0]->speeds.len=2;
ds.subsong[0]->speeds.val[0]=reader.readC();
ds.subsong[0]->speeds.val[0]=(unsigned char)reader.readC();
if (ds.version>0x07) {
ds.subsong[0]->speeds.val[1]=reader.readC();
ds.subsong[0]->speeds.val[1]=(unsigned char)reader.readC();
bool pal=reader.readC();
ds.subsong[0]->hz=pal?60:50;
customTempo=reader.readC();
@ -317,7 +317,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
if (ds.system[0]==DIV_SYSTEM_YMU759) {
switch (ds.subsong[0]->timeBase) {
switch (oldTimeBase) {
case 0:
ds.subsong[0]->hz=248;
break;
@ -340,8 +340,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.subsong[0]->hz=248;
break;
}
ds.subsong[0]->timeBase=0;
addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system.");
} else {
ds.subsong[0]->speeds.val[0]*=(oldTimeBase+1);
ds.subsong[0]->speeds.val[1]*=(oldTimeBase+1);
}
logV("%x",reader.tell());
@ -1346,7 +1348,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
int intHz=curSubSong->hz;
w->writeC(curSubSong->timeBase);
w->writeC(0);
w->writeC(curSubSong->speeds.val[0]);
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
w->writeC((intHz<=53)?0:1);

View file

@ -1077,7 +1077,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
}
reader.readI();
subSong->timeBase=reader.readC();
unsigned char oldTimeBase=reader.readC();
subSong->speeds.len=2;
subSong->speeds.val[0]=(unsigned char)reader.readC();
subSong->speeds.val[1]=(unsigned char)reader.readC();
@ -1641,6 +1641,10 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
}
}
for (int i=0; i<16; i++) {
subSong->speeds.val[i]*=(oldTimeBase+1);
}
if (ds.version>=156) {
assetDirPtr.push_back(reader.readI());
assetDirPtr.push_back(reader.readI());

View file

@ -296,7 +296,6 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
}
w->writeText("\n");
w->writeText(fmt::sprintf("- virtual tempo: %d/%d\n",s->virtualTempoN,s->virtualTempoD));
w->writeText(fmt::sprintf("- time base: %d\n",s->timeBase));
w->writeText(fmt::sprintf("- pattern length: %d\n",s->patLen));
w->writeText(fmt::sprintf("\norders:\n```\n"));

View file

@ -705,12 +705,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
if (effectVal!=0) {
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
// - 0: strict
// - delays equal or greater to the speed * timeBase are ignored
// - delays equal or greater to the speed are ignored (formerly time base was involved but that has been removed now)
// - 1: strict old
// - delays equal or greater to the speed are ignored
// - delays greater to the speed are ignored
// - 2: lax (default)
// - no delay is ever ignored unless overridden by another
bool comparison=(song.compatFlags.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed*(curSubSong->timeBase+1)));
bool comparison=(song.compatFlags.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed));
if (song.compatFlags.delayBehavior==2) comparison=true;
if (comparison) {
// set the delay row, order and timer
@ -1868,16 +1868,16 @@ void DivEngine::nextRow() {
// if the pattern length is odd and the current order is odd, use speed 2 for even rows and speed 1 for odd ones
if ((curSubSong->patLen&1) && curOrder&1) {
ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1);
ticks=((curRow&1)?speed2:speed1);
nextSpeed=(curRow&1)?speed1:speed2;
} else {
ticks=((curRow&1)?speed1:speed2)*(curSubSong->timeBase+1);
ticks=((curRow&1)?speed1:speed2);
nextSpeed=(curRow&1)?speed2:speed1;
}
} else {
// normal speed alternation
// set the number of ticks and cycle to the next speed
ticks=speeds.val[curSpeed]*(curSubSong->timeBase+1);
ticks=speeds.val[curSpeed];
curSpeed++;
if (curSpeed>=speeds.len) curSpeed=0;
// cache the next speed for future operations
@ -2633,20 +2633,18 @@ void DivEngine::runMidiClock(int totalCycles) {
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
// calculate tempo using highlight, timeBase, tick rate, speeds and virtual tempo
// calculate tempo using highlight, tick rate, speeds and virtual tempo
double hl=curSubSong->hilightA;
if (hl<=0.0) hl=4.0;
double timeBase=curSubSong->timeBase+1;
double speedSum=0;
double vD=virtualTempoD;
for (int i=0; i<MIN(16,speeds.len); i++) {
speedSum+=speeds.val[i];
}
speedSum/=MAX(1,speeds.len);
if (timeBase<1.0) timeBase=1.0;
if (speedSum<1.0) speedSum=1.0;
if (vD<1) vD=1;
double bpm=((24.0*divider)/(timeBase*hl*speedSum))*(double)virtualTempoN/vD;
double bpm=((24.0*divider)/(hl*speedSum))*(double)virtualTempoN/vD;
// avoid a division by zer
if (bpm<1.0) bpm=1.0;
int increment=got.rate/(bpm);

View file

@ -197,12 +197,12 @@ void DivSubSong::calcTimestamps(int chans, std::vector<DivGroovePattern>& groove
if (effectVal!=0) {
// COMPAT FLAG: cut/delay effect policy (delayBehavior)
// - 0: strict
// - delays equal or greater to the speed * timeBase are ignored
// - delays equal or greater to the speed are ignored (formerly time base was involved but that has been removed now)
// - 1: strict old
// - delays equal or greater to the speed are ignored
// - delays greater to the speed are ignored
// - 2: lax (default)
// - no delay is ever ignored unless overridden by another
bool comparison=(delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed*(timeBase+1)));
bool comparison=(delayBehavior==1)?(effectVal<=nextSpeed):(effectVal<(nextSpeed));
if (delayBehavior==2) comparison=true;
if (comparison) {
// set the delay row, order and timer
@ -327,16 +327,16 @@ void DivSubSong::calcTimestamps(int chans, std::vector<DivGroovePattern>& groove
// we subtract firstPat from curOrder as firstPat is used by a function which finds sub-songs
// (the beginning of a new sub-song will be in order 0)
if ((patLen&1) && (curOrder-firstPat)&1) {
ticks=((curRow&1)?speed2:speed1)*(timeBase+1);
ticks=((curRow&1)?speed2:speed1);
nextSpeed=(curRow&1)?speed1:speed2;
} else {
ticks=((curRow&1)?speed1:speed2)*(timeBase+1);
ticks=((curRow&1)?speed1:speed2);
nextSpeed=(curRow&1)?speed2:speed1;
}
} else {
// normal speed alternation
// set the number of ticks and cycle to the next speed
ticks=curSpeeds.val[curSpeed]*(timeBase+1);
ticks=curSpeeds.val[curSpeed];
curSpeed++;
if (curSpeed>=curSpeeds.len) curSpeed=0;
// cache the next speed for future operations
@ -465,7 +465,7 @@ bool DivSubSong::readData(SafeReader& reader, int version, int chans) {
hz=reader.readF();
arpLen=reader.readC();
timeBase=reader.readC();
effectDivider=reader.readC();
patLen=reader.readS();
ordersLen=reader.readS();
@ -519,7 +519,7 @@ bool DivSubSong::readData(SafeReader& reader, int version, int chans) {
}
reader.readI();
timeBase=reader.readC();
unsigned char oldTimeBase=reader.readC();
speeds.len=2;
speeds.val[0]=(unsigned char)reader.readC();
speeds.val[1]=(unsigned char)reader.readC();
@ -582,6 +582,10 @@ bool DivSubSong::readData(SafeReader& reader, int version, int chans) {
speeds.val[i]=(unsigned char)reader.readC();
}
}
for (int i=0; i<16; i++) {
speeds.val[i]*=(oldTimeBase+1);
}
}
return true;
@ -595,7 +599,7 @@ void DivSubSong::putData(SafeWriter* w, int chans) {
w->writeF(hz);
w->writeC(arpLen);
w->writeC(timeBase);
w->writeC(effectDivider);
w->writeS(patLen);
w->writeS(ordersLen);
w->writeC(hilightA);
@ -819,7 +823,7 @@ void DivSong::findSubSongs() {
theCopy->notes=i->notes;
theCopy->hilightA=i->hilightA;
theCopy->hilightB=i->hilightB;
theCopy->timeBase=i->timeBase;
theCopy->effectDivider=i->effectDivider;
theCopy->arpLen=i->arpLen;
theCopy->speeds=i->speeds;
theCopy->virtualTempoN=i->virtualTempoN;

View file

@ -226,7 +226,7 @@ struct DivSongTimestamps {
struct DivSubSong {
String name, notes;
unsigned char hilightA, hilightB;
unsigned char timeBase, arpLen;
unsigned char effectDivider, arpLen;
DivGroovePattern speeds;
short virtualTempoN, virtualTempoD;
float hz;
@ -269,7 +269,7 @@ struct DivSubSong {
DivSubSong():
hilightA(4),
hilightB(16),
timeBase(0),
effectDivider(0),
arpLen(1),
virtualTempoN(150),
virtualTempoD(150),

View file

@ -1295,16 +1295,14 @@ void FurnaceGUI::prepareLayout() {
float FurnaceGUI::calcBPM(const DivGroovePattern& speeds, float hz, int vN, int vD) {
float hl=e->curSubSong->hilightA;
if (hl<=0.0f) hl=4.0f;
float timeBase=e->curSubSong->timeBase+1;
float speedSum=0;
for (int i=0; i<MIN(16,speeds.len); i++) {
speedSum+=speeds.val[i];
}
speedSum/=MAX(1,speeds.len);
if (timeBase<1.0f) timeBase=1.0f;
if (speedSum<1.0f) speedSum=1.0f;
if (vD<1) vD=1;
return (60.0f*hz/(timeBase*hl*speedSum))*(float)vN/(float)vD;
return (60.0f*hz/(hl*speedSum))*(float)vN/(float)vD;
}
void FurnaceGUI::play(int row) {

View file

@ -198,9 +198,11 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
/*
ImGui::AlignTextToFramePadding();
ImGui::Text(_("Divider"));
ImGui::Text(_("Divider"));*/
ImGui::TableNextColumn();
/*
ImGui::SetNextItemWidth(halfAvail);
unsigned char realTB=e->curSubSong->timeBase+1;
if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { MARK_MODIFIED
@ -210,6 +212,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
recalcTimestamps=true;
}
ImGui::SameLine();
*/
ImGui::Text("%.2f BPM",calcBPM(e->curSubSong->speeds,e->curSubSong->hz,e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD));
ImGui::TableNextRow();