unlock the power of DECIMAL HZ!

This commit is contained in:
tildearrow 2022-03-15 23:30:15 -05:00
parent 02760ddcbc
commit 02e9edbad9
7 changed files with 41 additions and 31 deletions

View File

@ -1095,18 +1095,18 @@ unsigned char DivEngine::getSpeed2() {
return speed2; return speed2;
} }
int DivEngine::getHz() { float DivEngine::getHz() {
if (song.customTempo) { if (song.customTempo) {
return song.hz; return song.hz;
} else if (song.pal) { } else if (song.pal) {
return 60; return 60.0;
} else { } else {
return 50; return 50.0;
} }
return 60; return 60.0;
} }
int DivEngine::getCurHz() { float DivEngine::getCurHz() {
return divider; return divider;
} }
@ -2216,11 +2216,12 @@ void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) {
isBusy.unlock(); isBusy.unlock();
} }
void DivEngine::setSongRate(int hz, bool pal) { void DivEngine::setSongRate(float hz, bool pal) {
isBusy.lock(); isBusy.lock();
song.pal=!pal; song.pal=!pal;
song.hz=hz; song.hz=hz;
song.customTempo=(song.hz!=50 && song.hz!=60); // what?
song.customTempo=true;
divider=60; divider=60;
if (song.customTempo) { if (song.customTempo) {
divider=song.hz; divider=song.hz;

View File

@ -182,8 +182,11 @@ class DivEngine {
bool halted; bool halted;
bool forceMono; bool forceMono;
bool cmdStreamEnabled; bool cmdStreamEnabled;
int ticks, curRow, curOrder, remainingLoops, nextSpeed, divider; int ticks, curRow, curOrder, remainingLoops, nextSpeed;
int cycles, clockDrift, stepPlay; double divider;
int cycles;
double clockDrift;
int stepPlay;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch; int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue; unsigned char extValue;
unsigned char speed1, speed2; unsigned char speed1, speed2;
@ -431,10 +434,10 @@ class DivEngine {
unsigned char getSpeed2(); unsigned char getSpeed2();
// get Hz // get Hz
int getHz(); float getHz();
// get current Hz // get current Hz
int getCurHz(); float getCurHz();
// get time // get time
int getTotalTicks(); // 1/1000000th of a second int getTotalTicks(); // 1/1000000th of a second
@ -526,7 +529,7 @@ class DivEngine {
void setSysFlags(int system, unsigned int flags, bool restart); void setSysFlags(int system, unsigned int flags, bool restart);
// set Hz // set Hz
void setSongRate(int hz, bool pal); void setSongRate(float hz, bool pal);
// set remaining loops. -1 means loop forever. // set remaining loops. -1 means loop forever.
void setLoops(int loops); void setLoops(int loops);

View File

@ -841,7 +841,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
ds.arpLen=reader.readC(); ds.arpLen=reader.readC();
ds.hz=reader.readF(); ds.hz=reader.readF();
ds.pal=(ds.hz>=53); ds.pal=(ds.hz>=53);
if (ds.hz!=50 && ds.hz!=60) ds.customTempo=true; ds.customTempo=true;
ds.patLen=reader.readS(); ds.patLen=reader.readS();
ds.ordersLen=reader.readS(); ds.ordersLen=reader.readS();
@ -2064,7 +2064,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
w->writeC(song.customTempo); w->writeC(song.customTempo);
char customHz[4]; char customHz[4];
memset(customHz,0,4); memset(customHz,0,4);
snprintf(customHz,4,"%d",song.hz); snprintf(customHz,4,"%d",(int)song.hz);
w->write(customHz,3); w->write(customHz,3);
w->writeI(song.patLen); w->writeI(song.patLen);
w->writeC(song.ordersLen); w->writeC(song.ordersLen);

View File

@ -946,7 +946,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
globalPitch+=(signed char)(effectVal-0x80); globalPitch+=(signed char)(effectVal-0x80);
break; break;
case 0xf0: // set Hz by tempo case 0xf0: // set Hz by tempo
divider=(effectVal*2+2)/5; divider=(double)effectVal*2.0/5.0;
if (divider<10) divider=10; if (divider<10) divider=10;
cycles=((int)(got.rate)<<MASTER_CLOCK_PREC)/divider; cycles=((int)(got.rate)<<MASTER_CLOCK_PREC)/divider;
clockDrift=0; clockDrift=0;
@ -1166,7 +1166,7 @@ bool DivEngine::nextTick(bool noAccum) {
if (divider<10) divider=10; if (divider<10) divider=10;
cycles=((int)(got.rate)<<MASTER_CLOCK_PREC)/divider; cycles=((int)(got.rate)<<MASTER_CLOCK_PREC)/divider;
clockDrift+=((int)(got.rate)<<MASTER_CLOCK_PREC)%divider; clockDrift+=fmod((double)((int)(got.rate)<<MASTER_CLOCK_PREC),(double)divider);
if (clockDrift>=divider) { if (clockDrift>=divider) {
clockDrift-=divider; clockDrift-=divider;
cycles++; cycles++;

View File

@ -271,8 +271,8 @@ struct DivSong {
unsigned char timeBase, speed1, speed2, arpLen; unsigned char timeBase, speed1, speed2, arpLen;
bool pal; bool pal;
bool customTempo; bool customTempo;
// TODO: change Hz to float? float hz;
int hz, patLen, ordersLen, insLen, waveLen, sampleLen; int patLen, ordersLen, insLen, waveLen, sampleLen;
float masterVol; float masterVol;
float tuning; float tuning;
@ -345,7 +345,7 @@ struct DivSong {
arpLen(1), arpLen(1),
pal(true), pal(true),
customTempo(false), customTempo(false),
hz(60), hz(60.0),
patLen(64), patLen(64),
ordersLen(1), ordersLen(1),
insLen(0), insLen(0),

View File

@ -666,6 +666,16 @@ void FurnaceGUI::prepareLayout() {
fclose(check); fclose(check);
} }
float FurnaceGUI::calcBPM(int s1, int s2, float hz) {
float hl=e->song.hilightA;
if (hl<=0.0f) hl=4.0f;
float timeBase=e->song.timeBase+1;
float speedSum=s1+s2;
if (timeBase<1.0f) timeBase=1.0f;
if (speedSum<1.0f) speedSum=1.0f;
return 120.0f*hz/(timeBase*hl*speedSum);
}
void FurnaceGUI::drawEditControls() { void FurnaceGUI::drawEditControls() {
if (nextWindow==GUI_WINDOW_EDIT_CONTROLS) { if (nextWindow==GUI_WINDOW_EDIT_CONTROLS) {
editControlsOpen=true; editControlsOpen=true;
@ -1020,13 +1030,7 @@ void FurnaceGUI::drawSongInfo() {
e->song.timeBase=realTB-1; e->song.timeBase=realTB-1;
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
float hl=e->song.hilightA; ImGui::Text("%.2f BPM",calcBPM(e->song.speed1,e->song.speed2,e->song.hz));
if (hl<=0.0f) hl=4.0f;
float timeBase=e->song.timeBase+1;
float speedSum=e->song.speed1+e->song.speed2;
if (timeBase<1.0f) timeBase=1.0f;
if (speedSum<1.0f) speedSum=1.0f;
ImGui::Text("%.2f BPM",120.0f*(float)e->song.hz/(timeBase*hl*speedSum));
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@ -1083,17 +1087,17 @@ void FurnaceGUI::drawSongInfo() {
ImGui::Text("Tick Rate"); ImGui::Text("Tick Rate");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail); ImGui::SetNextItemWidth(avail);
int setHz=e->song.hz; float setHz=e->song.hz;
if (ImGui::InputInt("##Rate",&setHz)) { if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) {
if (setHz<10) setHz=10; if (setHz<10) setHz=10;
if (setHz>999) setHz=999; if (setHz>999) setHz=999;
e->setSongRate(setHz,setHz<52); e->setSongRate(setHz,setHz<52);
} }
if (e->song.hz==50) { if (e->song.hz>=49.98 && e->song.hz<=50.02) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("PAL"); ImGui::Text("PAL");
} }
if (e->song.hz==60) { if (e->song.hz>=59.9 && e->song.hz<=60.11) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("NTSC"); ImGui::Text("NTSC");
} }
@ -6078,7 +6082,7 @@ bool FurnaceGUI::loop() {
if (e->isPlaying()) { if (e->isPlaying()) {
int totalTicks=e->getTotalTicks(); int totalTicks=e->getTotalTicks();
int totalSeconds=e->getTotalSeconds(); int totalSeconds=e->getTotalSeconds();
ImGui::Text("| Speed %d:%d @ %dHz | Order %d/%d | Row %d/%d | %d:%.2d:%.2d.%.2d",e->getSpeed1(),e->getSpeed2(),e->getCurHz(),e->getOrder(),e->song.ordersLen,e->getRow(),e->song.patLen,totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); ImGui::Text("| Speed %d:%d @ %gHz (%g BPM) | Order %d/%d | Row %d/%d | %d:%.2d:%.2d.%.2d",e->getSpeed1(),e->getSpeed2(),e->getCurHz(),calcBPM(e->getSpeed1(),e->getSpeed2(),e->getCurHz()),e->getOrder(),e->song.ordersLen,e->getRow(),e->song.patLen,totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000);
} else { } else {
bool hasInfo=false; bool hasInfo=false;
String info; String info;

View File

@ -719,6 +719,8 @@ class FurnaceGUI {
void updateWindowTitle(); void updateWindowTitle();
void prepareLayout(); void prepareLayout();
float calcBPM(int s1, int s2, float hz);
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord); void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord);
void actualWaveList(); void actualWaveList();