How Is Calculated each tempoSection?

HI, I’d like to understand how is calculated a tempo section in a curve:

I understand that when tempo-curve is diffrent from -1 and 1, betwen the 2 tempos are created various TempoSections to make a discrete curve, but I’d like to know the logic behind this calculation and if there’s the possibility to change its accurancy, if I well remember logic gives the possibility to modify a curve transforming it in a series of points to keep under control performances (while for example steinberg is very CPU intensive in tempo ramps and this makes low latencies impracticables)!

Thank you in advice!

Also need to understand this:

    edit->tempoSequence.getTimeSigs()[0]->setStringTimeSig("4/4");
    
    edit->tempoSequence.getTempos()[0]->setBpm(240);
    edit->tempoSequence.getTempos()[0]->setCurve(0.5);
    edit->tempoSequence.insertTempo(1);
    edit->tempoSequence.getTempos()[1]->setBpm(30);
    edit->tempoSequence.getTempos()[1]->setCurve(0.5);
    edit->tempoSequence.insertTempo(6); 
    edit->tempoSequence.getTempos()[2]->setBpm(90);
    edit->tempoSequence.getTempos()[2]->setCurve(-1);
    edit->tempoSequence.insertTempo(9);
    edit->tempoSequence.getTempos()[3]->setBpm(240);
    edit->tempoSequence.getTempos()[3]->setCurve(1);

    double getTempoSectionStartTime(int const atIndex) const 
    { 
    return edit->tempoSequence.getTempoSections().getReference(atIndex).startTime; 
    }

    for (int i = 0; i < edit->tempoSequence.getTempoSections().size(); i++)
    {
        DBG(getTempoSectionStartTime(i));
    }

this print me:

0
0.0625
0.126228
0.191383
0.258203
0.326977
0.398059
0.471899
0.549072
0.63034
0.716744
0.809768
0.911636
1.02594 MARK: Why this is not 1??
1.15908
1.32439
1.55851
2.05851
2.5159
2.92964
3.29973
3.62699
3.9127
4.15829
4.36477
6.11477 MARK: Why this is not 6??

and after I search on framework and I found that insertTempo() round argument every time to nearest beat… but this a limitation, should be more accurate (for also other stuffs) to insert tempo in the right time searched and remap the TempoSections from the previous tempo to this new one to get the new tempo in the right place, what about this?

Can I ask what you’re actually trying to do as it might help answer how you should be using the class.

It’s basically impossible to have a tempo change not on a beat and it still make sense. You’ll end up with fractions of beats all over the place. If you’re dealing with tempos, you really should be thinking in terms fo beats and things changing on those beats. Time is really the other side of the coin.

Personally I would only use curves between ± 0.5. This will keep them as true bezier curves. If you go up to ± 1.0, the algorithm changes to basically extend the bezier in to infinity to allow for abrupt jumps. But it you need these, just do it with two tempo changes.

Finally, grab a copy of Waveform Free and modify the tempo sequence as above, it should become a lot clearer what it’s doing then.

1 Like

Sorry for changing tempo I mean change bpm, not time sig :upside_down_face:

Basically I have my timeline with my tempo line drawed in (with all curves, lines, points and handles). I’d like to insert a bpm change not only on beat and to decide by myself the accuracy of the ramp (or the curve) that is created between two points (that define the bpm change). Between them are created tempo sections to make the curve (or ramp) discrete, but I don’t understand the logic of how many of them are created to describe the curve (more accurancy or less should change the performance: I should decide to do some stuffs at start of each tempoSection to inform some object of the new bpm and according with my buffer size I’d like to decide on my program to have more accuracy [maybe during a mixing session] or less [because maybe I’m in a live performance where is more important the real time])

You can see the algorithm used in TempoSequence::updateTempoData:

        if (nextTempo != nullptr && (currTempo->getCurve() != -1.0f && currTempo->getCurve() != 1.0f))
            numSubdivisions = int (jlimit (1.0, 100.0, 4.0 * (nextTempo->startBeatNumber - currentBeat)));

So basically 4 changes per section.

Are you saying you have a use case where this is very audible?

I’m generally hesitant to suggest going too deeply in to this area as its really internal details and likely to change in the future.

1 Like

Ok thank you for suggestion! Yes, I already studied around that code, I’ll follow your advice!