Even if we start at time T, if the tempo point before T is ramped, we need to
adjust it's omega value based on the beat time of the following tempo point. If
we don't do this, then using that tempo to compute ::superclock_at() for
subsequent points will be incorrect.
Note: there may be an ordering issue here with Tempo/Meter points. We might
need to pass over all tempo points first, then process meters etc. Something
like that.
changes in tempo can be negative (decelerando/slowing down), and thus so can _omega. We cannot call log() or its
cousins on negative values, so in this scenario use an alternate expression for "t from b" in the tempo.pdf paper
omega can be computed from Beat or superclock duration. This gives rise to
different units for omega, and we must use the correct value in a given
context.
This commit also changes the way that the audio time omega is computed during
TempoMap::reset_starting_at()
Rampable only existed to provide exclusive access to ::set_end() for the
TempoMap. More idiomatic C++ but now that _type has also gone away, so has
::set_ramped() and it really was not worth keeping it around.
Ramped/Constant is really a function of start/end note_types_per_minute. Having
a separate member is really just caching it and leads to errors or risk thereof.
Temporal::most_recent_engine_sample_rate is used in performance-critical code so shouldn't be accessed via a 'get()' function. But (via the TEMPORAL_SAMPLE_RATE #define) it does get accessed outside of libtemporal and therefore needs to get exported.
We were using a given tempo or meter point as part of the metric used when
recomputing its position. In fact, the metric should be only use the
tempo/meter immediately preceding the given point.
It is more useful to get the actual TempoPoint than just the Tempo
that we discover.
Aside: it would be awesome to understand how to use boost::intrusive to get the
next tempo point directly from the tempo hook.
This commit leaves two issues outstanding:
1. unclear/ugly semantics for drag operations that reset the GUI thread's tempo map to the writable copy
2. undo/redo for the tempo map
These will be addressed in future commits
std::upper_bound() was not the correct tool to find the existing point,
it should have been std::lower_bound(). For code consistency, this
change doesn't use either but like ::remove_tempo() and similar methods,
just iterates over the whole list
We do not want a value as large as the previous one, which limits the time
range that can be represented in 62 bits unnecessarily. The new value is
9 times smaller than the previous value, and loses only 384000 as a significant
factor.
This commit also switches to using an (inline) accessor for superclock_ticks_per_second,
making it possible in debug/testing phases to spot early/illegal uses of the value.
Now using a globally-scoped static variable which is updated by the
AudioEngine whenever an SR change occurs. Defaults to 48kHz and can
be used even before there is a backend.
This just uses the old Evoral BeatTest. Some of the tests needed amending
because temporal uses rint() to convert between float and int, not just
a cast.
THe length of a Source(File) is always measured from its start. In this sense,
the length is like a position on the timeline, which is a duration with an
implicit origin, or a Region start, also a duration with an implicit origin (in
that case the start of the Source). There is no good reason for using
a timecnt_t for this value, because the position component of a timecnt_t
(the origin for the duration) is implicit and always zero. So we make
this property into a timepos_t, and include a number of asserts() to check
for common possible coding errors related to the time domain
This is mainly for the benefit of Lua bindings, but also increases
overall API naming consistency with functions and methods
`is_XYZ()` being used elsewhere.
This API change breaks builds!
::snap_to() was intended to round a Beats value to the nearest multiple
of another Beats value. It did not do that, but instead rounded down.
Worse, it used Beats::operator/ which in turn uses int_div_round(),
which is incorrect for a situation where we need integer truncation.
The changes fix the actual arithmetic and add 2 variant functions so that the
API includes round down, round up and round to nearest.
max_samplepos and max_samplecnt and both INT64_MAX which is (a) too large to fit into a signed 62 bit
integer and (b) definitely too large to be represented in a signed 62 bit superclock value.
Move the constructors that use samplepos_t into the .cc file, and treat these two values as special
cases that mean "as large/late/huge/long as possible".
The old code used the instantaneous tempo at T0 to compute where the next
quarter note would be. This is incorrect, since the tempo is
changing (continuously, for now) during the time represented by that quarter
note. Instead, we need to add a quarter note (or technically, whatever the
tempo note type is) to get a new position in beats, then compute the superclock
time at that location (which will use our equations for tempo, including the
use of omega, the ramp factor).
These comments should correct an impression left in the commit message for
6e9e28343bc3695d that there may be some sort of problem with synchronization
of TempoMap changes. The actual problem is that TempoMap edits are done using
RCU, so the modifications are performaned using a copy of the map, but with
map elements taken from the pre-copy version.
The correct algorithm is to traverse the type-specific list of points,
find the point (if any) whose time matches that of the argument (because
we do not allow multiple points of the same type at the same time), and
then use that discovered point from the _points list.
This approach is required because the actual argument may no longer be
in the tempo map (due to a change made by another thread). The lack of
sync, however, needs investigation.
a negative beat position needs to be legal, so the assert was moved and modified. The only check
for a negative value is that the TempoPoint being used is at absolute zero.
This check might turn out to be wrong in the future, but for now we still require a tempo and
meter point at absolute zero