mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-22 20:45:11 +00:00
add effects to change virtual tempo
This commit is contained in:
parent
779d1aeb61
commit
3512591fd1
7 changed files with 50 additions and 8 deletions
|
@ -70,6 +70,9 @@ not all chips support these effects.
|
|||
- `xxx` may be from `000` to `3FF`.
|
||||
- `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.
|
||||
- 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.
|
||||
|
|
|
@ -141,6 +141,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
return "FAxx: Fast volume slide (0y: down; x0: up)";
|
||||
case 0xfc:
|
||||
return "FCxx: Note release";
|
||||
case 0xfd:
|
||||
return "FDxx: Set virtual tempo numerator";
|
||||
case 0xfe:
|
||||
return "FExx: Set virtual tempo denominator";
|
||||
case 0xff:
|
||||
return "FFxx: Stop song";
|
||||
default:
|
||||
|
@ -1683,7 +1687,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
|||
runMidiTime(cycles);
|
||||
}
|
||||
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);
|
||||
if (goal>0 || goalRow>0) {
|
||||
|
@ -2121,6 +2125,8 @@ void DivEngine::reset() {
|
|||
extValue=0;
|
||||
extValuePresent=0;
|
||||
speeds=curSubSong->speeds;
|
||||
virtualTempoN=curSubSong->virtualTempoN;
|
||||
virtualTempoD=curSubSong->virtualTempoD;
|
||||
firstTick=false;
|
||||
shallStop=false;
|
||||
shallStopSched=false;
|
||||
|
@ -2368,6 +2374,21 @@ float DivEngine::getCurHz() {
|
|||
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() {
|
||||
return totalSeconds;
|
||||
}
|
||||
|
|
|
@ -442,6 +442,7 @@ class DivEngine {
|
|||
int curMidiTimePiece, curMidiTimeCode;
|
||||
unsigned char extValue, pendingMetroTick;
|
||||
DivGroovePattern speeds;
|
||||
short virtualTempoN, virtualTempoD;
|
||||
short tempoAccum;
|
||||
DivStatusView view;
|
||||
DivHaltPositions haltOn;
|
||||
|
@ -891,6 +892,13 @@ class DivEngine {
|
|||
// get current Hz
|
||||
float getCurHz();
|
||||
|
||||
// get virtual tempo
|
||||
short getVirtualTempoN();
|
||||
short getVirtualTempoD();
|
||||
|
||||
// tell engine about virtual tempo changes
|
||||
void virtualTempoChanged();
|
||||
|
||||
// get time
|
||||
int getTotalTicks(); // 1/1000000th of a second
|
||||
int getTotalSeconds();
|
||||
|
@ -1334,6 +1342,8 @@ class DivEngine {
|
|||
curMidiTimeCode(0),
|
||||
extValue(0),
|
||||
pendingMetroTick(0),
|
||||
virtualTempoN(150),
|
||||
virtualTempoD(150),
|
||||
tempoAccum(0),
|
||||
view(DIV_STATUS_NOTHING),
|
||||
haltOn(DIV_HALT_NONE),
|
||||
|
|
|
@ -487,6 +487,12 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
if (effectVal>0) speeds.val[0]=effectVal;
|
||||
}
|
||||
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
|
||||
if (changeOrd==-1 || song.jumpTreatment==0) {
|
||||
changeOrd=effectVal;
|
||||
|
@ -1442,9 +1448,9 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
subticks=tickMult;
|
||||
|
||||
if (stepPlay!=1) {
|
||||
tempoAccum+=(skipping && curSubSong->virtualTempoN<curSubSong->virtualTempoD)?curSubSong->virtualTempoD:curSubSong->virtualTempoN;
|
||||
while (tempoAccum>=curSubSong->virtualTempoD) {
|
||||
tempoAccum-=curSubSong->virtualTempoD;
|
||||
tempoAccum+=(skipping && virtualTempoN<virtualTempoD)?virtualTempoD:virtualTempoN;
|
||||
while (tempoAccum>=virtualTempoD) {
|
||||
tempoAccum-=virtualTempoD;
|
||||
if (--ticks<=0) {
|
||||
ret=endOfSong;
|
||||
if (shallStopSched) {
|
||||
|
@ -1693,7 +1699,7 @@ void DivEngine::runMidiClock(int totalCycles) {
|
|||
if (hl<=0.0) hl=4.0;
|
||||
double timeBase=curSubSong->timeBase+1;
|
||||
double speedSum=0;
|
||||
double vD=curSubSong->virtualTempoD;
|
||||
double vD=virtualTempoD;
|
||||
for (int i=0; i<MIN(16,speeds.len); i++) {
|
||||
speedSum+=speeds.val[i];
|
||||
}
|
||||
|
@ -1701,7 +1707,7 @@ void DivEngine::runMidiClock(int totalCycles) {
|
|||
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)curSubSong->virtualTempoN/vD;
|
||||
double bpm=((24.0*divider)/(timeBase*hl*speedSum))*(double)virtualTempoN/vD;
|
||||
if (bpm<1.0) bpm=1.0;
|
||||
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) {
|
||||
if (loopPos==-1) {
|
||||
if (loopOrder==curOrder && loopRow==curRow) {
|
||||
if ((ticks-((tempoAccum+curSubSong->virtualTempoN)/curSubSong->virtualTempoD))<=0) {
|
||||
if ((ticks-((tempoAccum+virtualTempoN)/virtualTempoD))<=0) {
|
||||
writeLoop=true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4446,7 +4446,7 @@ bool FurnaceGUI::loop() {
|
|||
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) {
|
||||
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 (e->curSubSong->virtualTempoN<1) e->curSubSong->virtualTempoN=1;
|
||||
if (e->curSubSong->virtualTempoN>255) e->curSubSong->virtualTempoN=255;
|
||||
e->virtualTempoChanged();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
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 (e->curSubSong->virtualTempoD<1) e->curSubSong->virtualTempoD=1;
|
||||
if (e->curSubSong->virtualTempoD>255) e->curSubSong->virtualTempoD=255;
|
||||
e->virtualTempoChanged();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Denominator (set to base tempo)");
|
||||
|
|
Loading…
Reference in a new issue