unlock the power of DECIMAL HZ!
This commit is contained in:
parent
02760ddcbc
commit
02e9edbad9
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue