add effects to change virtual tempo
This commit is contained in:
parent
779d1aeb61
commit
3512591fd1
|
@ -70,6 +70,9 @@ not all chips support these effects.
|
||||||
- `xxx` may be from `000` to `3FF`.
|
- `xxx` may be from `000` to `3FF`.
|
||||||
- `F0xx`: **Set BPM.** changes tick rate according to beats per minute. range is `01` to `FF`.
|
- `F0xx`: **Set BPM.** changes tick rate according to beats per minute. range is `01` to `FF`.
|
||||||
- ---
|
- ---
|
||||||
|
- `FDxx`: **Set virtual tempo numerator.** sets the virtual tempo's numerator to the effect value.
|
||||||
|
- `FExx`: **Set virtual tempo denominator.** sets the virtual tempo's denominator to the effect value.
|
||||||
|
- ---
|
||||||
- `0Bxx`: **Jump to order.** `x` is the order to play after the current row.
|
- `0Bxx`: **Jump to order.** `x` is the order to play after the current row.
|
||||||
- this marks the end of a loop with order `x` as the loop start.
|
- this marks the end of a loop with order `x` as the loop start.
|
||||||
- `0Dxx`: **Jump to next pattern.** skips the current row and remainder of current order. `x` is the row at which to start playing the next pattern.
|
- `0Dxx`: **Jump to next pattern.** skips the current row and remainder of current order. `x` is the row at which to start playing the next pattern.
|
||||||
|
|
|
@ -141,6 +141,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
||||||
return "FAxx: Fast volume slide (0y: down; x0: up)";
|
return "FAxx: Fast volume slide (0y: down; x0: up)";
|
||||||
case 0xfc:
|
case 0xfc:
|
||||||
return "FCxx: Note release";
|
return "FCxx: Note release";
|
||||||
|
case 0xfd:
|
||||||
|
return "FDxx: Set virtual tempo numerator";
|
||||||
|
case 0xfe:
|
||||||
|
return "FExx: Set virtual tempo denominator";
|
||||||
case 0xff:
|
case 0xff:
|
||||||
return "FFxx: Stop song";
|
return "FFxx: Stop song";
|
||||||
default:
|
default:
|
||||||
|
@ -1683,7 +1687,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
||||||
runMidiTime(cycles);
|
runMidiTime(cycles);
|
||||||
}
|
}
|
||||||
if (oldOrder!=curOrder) break;
|
if (oldOrder!=curOrder) break;
|
||||||
if (ticks-((tempoAccum+curSubSong->virtualTempoN)/MAX(1,curSubSong->virtualTempoD))<1 && curRow>=goalRow) break;
|
if (ticks-((tempoAccum+virtualTempoN)/MAX(1,virtualTempoD))<1 && curRow>=goalRow) break;
|
||||||
}
|
}
|
||||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
|
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
|
||||||
if (goal>0 || goalRow>0) {
|
if (goal>0 || goalRow>0) {
|
||||||
|
@ -2121,6 +2125,8 @@ void DivEngine::reset() {
|
||||||
extValue=0;
|
extValue=0;
|
||||||
extValuePresent=0;
|
extValuePresent=0;
|
||||||
speeds=curSubSong->speeds;
|
speeds=curSubSong->speeds;
|
||||||
|
virtualTempoN=curSubSong->virtualTempoN;
|
||||||
|
virtualTempoD=curSubSong->virtualTempoD;
|
||||||
firstTick=false;
|
firstTick=false;
|
||||||
shallStop=false;
|
shallStop=false;
|
||||||
shallStopSched=false;
|
shallStopSched=false;
|
||||||
|
@ -2368,6 +2374,21 @@ float DivEngine::getCurHz() {
|
||||||
return divider;
|
return divider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
short DivEngine::getVirtualTempoN() {
|
||||||
|
return virtualTempoN;
|
||||||
|
}
|
||||||
|
|
||||||
|
short DivEngine::getVirtualTempoD() {
|
||||||
|
return virtualTempoD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivEngine::virtualTempoChanged() {
|
||||||
|
BUSY_BEGIN;
|
||||||
|
virtualTempoN=curSubSong->virtualTempoN;
|
||||||
|
virtualTempoD=curSubSong->virtualTempoD;
|
||||||
|
BUSY_END;
|
||||||
|
}
|
||||||
|
|
||||||
int DivEngine::getTotalSeconds() {
|
int DivEngine::getTotalSeconds() {
|
||||||
return totalSeconds;
|
return totalSeconds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,6 +442,7 @@ class DivEngine {
|
||||||
int curMidiTimePiece, curMidiTimeCode;
|
int curMidiTimePiece, curMidiTimeCode;
|
||||||
unsigned char extValue, pendingMetroTick;
|
unsigned char extValue, pendingMetroTick;
|
||||||
DivGroovePattern speeds;
|
DivGroovePattern speeds;
|
||||||
|
short virtualTempoN, virtualTempoD;
|
||||||
short tempoAccum;
|
short tempoAccum;
|
||||||
DivStatusView view;
|
DivStatusView view;
|
||||||
DivHaltPositions haltOn;
|
DivHaltPositions haltOn;
|
||||||
|
@ -891,6 +892,13 @@ class DivEngine {
|
||||||
// get current Hz
|
// get current Hz
|
||||||
float getCurHz();
|
float getCurHz();
|
||||||
|
|
||||||
|
// get virtual tempo
|
||||||
|
short getVirtualTempoN();
|
||||||
|
short getVirtualTempoD();
|
||||||
|
|
||||||
|
// tell engine about virtual tempo changes
|
||||||
|
void virtualTempoChanged();
|
||||||
|
|
||||||
// get time
|
// get time
|
||||||
int getTotalTicks(); // 1/1000000th of a second
|
int getTotalTicks(); // 1/1000000th of a second
|
||||||
int getTotalSeconds();
|
int getTotalSeconds();
|
||||||
|
@ -1334,6 +1342,8 @@ class DivEngine {
|
||||||
curMidiTimeCode(0),
|
curMidiTimeCode(0),
|
||||||
extValue(0),
|
extValue(0),
|
||||||
pendingMetroTick(0),
|
pendingMetroTick(0),
|
||||||
|
virtualTempoN(150),
|
||||||
|
virtualTempoD(150),
|
||||||
tempoAccum(0),
|
tempoAccum(0),
|
||||||
view(DIV_STATUS_NOTHING),
|
view(DIV_STATUS_NOTHING),
|
||||||
haltOn(DIV_HALT_NONE),
|
haltOn(DIV_HALT_NONE),
|
||||||
|
|
|
@ -487,6 +487,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
if (effectVal>0) speeds.val[0]=effectVal;
|
if (effectVal>0) speeds.val[0]=effectVal;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0xfd: // virtual tempo num
|
||||||
|
if (effectVal>0) virtualTempoN=effectVal;
|
||||||
|
break;
|
||||||
|
case 0xfe: // virtual tempo den
|
||||||
|
if (effectVal>0) virtualTempoD=effectVal;
|
||||||
|
break;
|
||||||
case 0x0b: // change order
|
case 0x0b: // change order
|
||||||
if (changeOrd==-1 || song.jumpTreatment==0) {
|
if (changeOrd==-1 || song.jumpTreatment==0) {
|
||||||
changeOrd=effectVal;
|
changeOrd=effectVal;
|
||||||
|
@ -1442,9 +1448,9 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
subticks=tickMult;
|
subticks=tickMult;
|
||||||
|
|
||||||
if (stepPlay!=1) {
|
if (stepPlay!=1) {
|
||||||
tempoAccum+=(skipping && curSubSong->virtualTempoN<curSubSong->virtualTempoD)?curSubSong->virtualTempoD:curSubSong->virtualTempoN;
|
tempoAccum+=(skipping && virtualTempoN<virtualTempoD)?virtualTempoD:virtualTempoN;
|
||||||
while (tempoAccum>=curSubSong->virtualTempoD) {
|
while (tempoAccum>=virtualTempoD) {
|
||||||
tempoAccum-=curSubSong->virtualTempoD;
|
tempoAccum-=virtualTempoD;
|
||||||
if (--ticks<=0) {
|
if (--ticks<=0) {
|
||||||
ret=endOfSong;
|
ret=endOfSong;
|
||||||
if (shallStopSched) {
|
if (shallStopSched) {
|
||||||
|
@ -1693,7 +1699,7 @@ void DivEngine::runMidiClock(int totalCycles) {
|
||||||
if (hl<=0.0) hl=4.0;
|
if (hl<=0.0) hl=4.0;
|
||||||
double timeBase=curSubSong->timeBase+1;
|
double timeBase=curSubSong->timeBase+1;
|
||||||
double speedSum=0;
|
double speedSum=0;
|
||||||
double vD=curSubSong->virtualTempoD;
|
double vD=virtualTempoD;
|
||||||
for (int i=0; i<MIN(16,speeds.len); i++) {
|
for (int i=0; i<MIN(16,speeds.len); i++) {
|
||||||
speedSum+=speeds.val[i];
|
speedSum+=speeds.val[i];
|
||||||
}
|
}
|
||||||
|
@ -1701,7 +1707,7 @@ void DivEngine::runMidiClock(int totalCycles) {
|
||||||
if (timeBase<1.0) timeBase=1.0;
|
if (timeBase<1.0) timeBase=1.0;
|
||||||
if (speedSum<1.0) speedSum=1.0;
|
if (speedSum<1.0) speedSum=1.0;
|
||||||
if (vD<1) vD=1;
|
if (vD<1) vD=1;
|
||||||
double bpm=((24.0*divider)/(timeBase*hl*speedSum))*(double)curSubSong->virtualTempoN/vD;
|
double bpm=((24.0*divider)/(timeBase*hl*speedSum))*(double)virtualTempoN/vD;
|
||||||
if (bpm<1.0) bpm=1.0;
|
if (bpm<1.0) bpm=1.0;
|
||||||
int increment=got.rate*pow(2,MASTER_CLOCK_PREC)/(bpm);
|
int increment=got.rate*pow(2,MASTER_CLOCK_PREC)/(bpm);
|
||||||
|
|
||||||
|
|
|
@ -2424,7 +2424,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
while (!done) {
|
while (!done) {
|
||||||
if (loopPos==-1) {
|
if (loopPos==-1) {
|
||||||
if (loopOrder==curOrder && loopRow==curRow) {
|
if (loopOrder==curOrder && loopRow==curRow) {
|
||||||
if ((ticks-((tempoAccum+curSubSong->virtualTempoN)/curSubSong->virtualTempoD))<=0) {
|
if ((ticks-((tempoAccum+virtualTempoN)/virtualTempoD))<=0) {
|
||||||
writeLoop=true;
|
writeLoop=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4446,7 +4446,7 @@ bool FurnaceGUI::loop() {
|
||||||
info="| Groove";
|
info="| Groove";
|
||||||
}
|
}
|
||||||
|
|
||||||
info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD));
|
info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->getVirtualTempoN(),e->getVirtualTempoD()));
|
||||||
|
|
||||||
if (settings.orderRowsBase) {
|
if (settings.orderRowsBase) {
|
||||||
info+=fmt::sprintf("| Order %.2X/%.2X ",playOrder,e->curSubSong->ordersLen-1);
|
info+=fmt::sprintf("| Order %.2X/%.2X ",playOrder,e->curSubSong->ordersLen-1);
|
||||||
|
|
|
@ -171,6 +171,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
|
||||||
if (ImGui::InputScalar("##VTempoN",ImGuiDataType_S16,&e->curSubSong->virtualTempoN,&_ONE,&_TEN)) { MARK_MODIFIED
|
if (ImGui::InputScalar("##VTempoN",ImGuiDataType_S16,&e->curSubSong->virtualTempoN,&_ONE,&_TEN)) { MARK_MODIFIED
|
||||||
if (e->curSubSong->virtualTempoN<1) e->curSubSong->virtualTempoN=1;
|
if (e->curSubSong->virtualTempoN<1) e->curSubSong->virtualTempoN=1;
|
||||||
if (e->curSubSong->virtualTempoN>255) e->curSubSong->virtualTempoN=255;
|
if (e->curSubSong->virtualTempoN>255) e->curSubSong->virtualTempoN=255;
|
||||||
|
e->virtualTempoChanged();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Numerator");
|
ImGui::SetTooltip("Numerator");
|
||||||
|
@ -180,6 +181,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
|
||||||
if (ImGui::InputScalar("##VTempoD",ImGuiDataType_S16,&e->curSubSong->virtualTempoD,&_ONE,&_TEN)) { MARK_MODIFIED
|
if (ImGui::InputScalar("##VTempoD",ImGuiDataType_S16,&e->curSubSong->virtualTempoD,&_ONE,&_TEN)) { MARK_MODIFIED
|
||||||
if (e->curSubSong->virtualTempoD<1) e->curSubSong->virtualTempoD=1;
|
if (e->curSubSong->virtualTempoD<1) e->curSubSong->virtualTempoD=1;
|
||||||
if (e->curSubSong->virtualTempoD>255) e->curSubSong->virtualTempoD=255;
|
if (e->curSubSong->virtualTempoD>255) e->curSubSong->virtualTempoD=255;
|
||||||
|
e->virtualTempoChanged();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("Denominator (set to base tempo)");
|
ImGui::SetTooltip("Denominator (set to base tempo)");
|
||||||
|
|
Loading…
Reference in a new issue