mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 15:54:57 +01:00
Use consistent ticks per beat for each metrum
BBT now counts ticks up to 1920 for each given beat value. Previously 8th note beat using a N/8 meter only counted to 960. And shorter meters e.g half notes using a N/2 meter were never displayed correctly (since they exceeded 1920). This fixes Bar/Beat display N/M meters with M < 4.
This commit is contained in:
parent
02bf47eed1
commit
2556f2d30a
2 changed files with 43 additions and 40 deletions
|
|
@ -252,23 +252,19 @@ Meter::bbt_add (Temporal::BBT_Time const & bbt, Temporal::BBT_Offset const & add
|
|||
|
||||
Temporal::BBT_Offset r (bars + add.bars, beats + add.beats, ticks + add.ticks);
|
||||
|
||||
/* ticks-per-bar-division; PPQN is ticks-per-quarter note */
|
||||
|
||||
const int32_t tpg = ticks_per_grid ();
|
||||
|
||||
if (r.ticks >= tpg) {
|
||||
if (r.ticks >= ticks_per_beat) {
|
||||
|
||||
/* ticks per bar */
|
||||
const int32_t tpB = tpg * _divisions_per_bar;
|
||||
const int32_t tpB = ticks_per_beat * _divisions_per_bar;
|
||||
|
||||
if (r.ticks >= tpB) {
|
||||
r.bars += r.ticks / tpB;
|
||||
r.ticks %= tpB;
|
||||
}
|
||||
|
||||
if (r.ticks >= tpg) {
|
||||
r.beats += r.ticks / tpg;
|
||||
r.ticks %= tpg;
|
||||
if (r.ticks >= ticks_per_beat) {
|
||||
r.beats += r.ticks / ticks_per_beat;
|
||||
r.ticks %= ticks_per_beat;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,11 +323,9 @@ Meter::bbt_subtract (Temporal::BBT_Time const & bbt, Temporal::BBT_Offset const
|
|||
|
||||
/* ticks-per-bar-division; PPQN is ticks-per-quarter note */
|
||||
|
||||
const int32_t tpg = ticks_per_grid ();
|
||||
|
||||
if (r.ticks < 0) {
|
||||
r.beats += floor ((double) r.ticks / tpg);
|
||||
r.ticks = tpg + (r.ticks % Temporal::Beats::PPQN);
|
||||
r.beats += floor ((double) r.ticks / ticks_per_beat);
|
||||
r.ticks = ticks_per_beat + (r.ticks % ticks_per_beat);
|
||||
}
|
||||
|
||||
if (r.beats <= 0) {
|
||||
|
|
@ -386,21 +380,11 @@ Meter::to_quarters (Temporal::BBT_Offset const & offset) const
|
|||
{
|
||||
int64_t ticks = 0;
|
||||
|
||||
ticks += (Beats::PPQN * offset.bars * _divisions_per_bar * 4) / _note_value;
|
||||
ticks += (Beats::PPQN * offset.beats * 4) / _note_value;
|
||||
ticks += (ticks_per_beat * offset.bars * _divisions_per_bar * 4) / _note_value;
|
||||
ticks += (ticks_per_beat * offset.beats * 4) / _note_value;
|
||||
ticks += offset.ticks;
|
||||
|
||||
/* "parts per bar division" */
|
||||
|
||||
const int tpg = ticks_per_grid ();
|
||||
|
||||
if (offset.ticks > tpg) {
|
||||
ticks += Beats::PPQN * offset.ticks / tpg;
|
||||
ticks += offset.ticks % tpg;
|
||||
} else {
|
||||
ticks += offset.ticks;
|
||||
}
|
||||
|
||||
return Beats (ticks/Beats::PPQN, ticks%Beats::PPQN);
|
||||
return Beats (ticks / Beats::PPQN, ticks % Beats::PPQN);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -711,6 +695,12 @@ TempoMap::reftime (TempoPoint const & t, MeterPoint const & m) const
|
|||
return pi->sclock();
|
||||
}
|
||||
|
||||
Temporal::BBT_Argument
|
||||
TempoMetric::bbt_at (Beats const& qn) const
|
||||
{
|
||||
return BBT_Argument (reftime(), _meter->bbt_at (qn * _meter->note_value() / 4));
|
||||
}
|
||||
|
||||
Temporal::BBT_Argument
|
||||
TempoMetric::bbt_at (timepos_t const & pos) const
|
||||
{
|
||||
|
|
@ -742,11 +732,27 @@ TempoMetric::bbt_at (timepos_t const & pos) const
|
|||
the current meter, which we'll call "grid"
|
||||
*/
|
||||
|
||||
const int64_t note_value_count = muldiv_round (dq.get_beats(), _meter->note_value(), int64_t (4));
|
||||
int64_t note_value_count;
|
||||
int64_t tick_value_count;
|
||||
|
||||
if (_meter->note_value() >= 4) {
|
||||
/* easy case: meter is in qn (or shorter) Temporal::ticks_per_beat applies */
|
||||
note_value_count = muldiv_round (dq.get_beats(), _meter->note_value(), int64_t (4));
|
||||
tick_value_count = muldiv_round (dq.get_ticks(), _meter->note_value(), int64_t (4));
|
||||
} else {
|
||||
/* we need to 'scale' down ticks for 1/1 N/2 and N/3 meters.
|
||||
* tick wraps around qn, which is shorter than a beat (e.g. half note at 2/2).
|
||||
*/
|
||||
const int64_t ticks = dq.get_beats() * Temporal::ticks_per_beat + dq.get_ticks ();
|
||||
|
||||
tick_value_count = muldiv_round (ticks, _meter->note_value(), int64_t (4));
|
||||
note_value_count = tick_value_count / Temporal::ticks_per_beat;
|
||||
tick_value_count = tick_value_count % Temporal::ticks_per_beat;
|
||||
}
|
||||
|
||||
/* now construct a BBT_Offset using the count in grid units */
|
||||
|
||||
const BBT_Offset bbt_offset (0, note_value_count, dq.get_ticks());
|
||||
const BBT_Offset bbt_offset (0, note_value_count, tick_value_count);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TemporalMap, string_compose ("BBT offset from %3 @ %1: %2\n", (_tempo->beats() < _meter->beats() ? _meter->bbt() : _tempo->bbt()), bbt_offset,
|
||||
(_tempo->beats() < _meter->beats() ? "meter" : "tempo")));
|
||||
|
|
@ -2135,7 +2141,7 @@ TempoMap::move_tempo (TempoPoint const & tp, timepos_t const & when, bool push)
|
|||
|
||||
const Beats delta ((beats - tp.beats()).abs());
|
||||
|
||||
if (delta < Beats::ticks (metric.meter().ticks_per_grid())) {
|
||||
if (delta < Beats::ticks (ticks_per_beat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2773,7 +2779,7 @@ TempoMap::fill_grid_by_walking (TempoMapPoints& ret, Points::const_iterator& p_i
|
|||
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
||||
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gb %1\t [%2]\n", metric, ret.back()));
|
||||
} else {
|
||||
int ticks = (bbt.beats * metric.meter().ticks_per_grid()) + bbt.ticks;
|
||||
int ticks = (bbt.beats * ticks_per_beat) + bbt.ticks;
|
||||
int mod = Temporal::ticks_per_beat / beat_div;
|
||||
|
||||
if ((ticks % mod) == 0) {
|
||||
|
|
@ -3010,7 +3016,7 @@ TempoMap::fill_grid_with_final_metric (TempoMapPoints& ret, TempoMetric metric,
|
|||
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
||||
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gendb %1\t [%2]\n", metric, ret.back()));
|
||||
} else {
|
||||
int ticks = (bbt.beats * metric.meter().ticks_per_grid()) + bbt.ticks;
|
||||
int ticks = (bbt.beats * ticks_per_beat) + bbt.ticks;
|
||||
int mod = Temporal::ticks_per_beat / beat_div;
|
||||
if ((ticks % mod) == 0) {
|
||||
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
||||
|
|
@ -3187,13 +3193,12 @@ TempoMap::bbt_walk (BBT_Argument const & bbt, BBT_Offset const & o) const
|
|||
|
||||
|
||||
/* normalize possibly too-large ticks count */
|
||||
assert (offset.ticks <= ticks_per_beat);
|
||||
|
||||
const int32_t tpg = metric.meter().ticks_per_grid ();
|
||||
|
||||
if (offset.ticks > tpg) {
|
||||
if (offset.ticks > ticks_per_beat) {
|
||||
/* normalize */
|
||||
offset.beats += offset.ticks / tpg;
|
||||
offset.ticks %= tpg;
|
||||
offset.beats += offset.ticks / ticks_per_beat;
|
||||
offset.ticks %= ticks_per_beat;
|
||||
}
|
||||
|
||||
/* add each beat, 1 by 1, rechecking to see if there's a new
|
||||
|
|
|
|||
|
|
@ -287,8 +287,6 @@ class LIBTEMPORAL_API Meter {
|
|||
int divisions_per_bar () const { return _divisions_per_bar; }
|
||||
int note_value() const { return _note_value; }
|
||||
|
||||
int32_t ticks_per_grid () const { return (4 * Beats::PPQN) / _note_value; }
|
||||
|
||||
inline bool operator==(const Meter& other) const { return _divisions_per_bar == other.divisions_per_bar() && _note_value == other.note_value(); }
|
||||
inline bool operator!=(const Meter& other) const { return _divisions_per_bar != other.divisions_per_bar() || _note_value != other.note_value(); }
|
||||
|
||||
|
|
@ -456,7 +454,7 @@ class LIBTEMPORAL_API TempoMetric
|
|||
superclock_t superclock_at (Beats const & qn) const { return _tempo->superclock_at (qn); }
|
||||
samplepos_t sample_at (Beats const & qn) const { return _tempo->sample_at (qn); }
|
||||
Beats quarters_at (BBT_Time const & bbt) const { return _meter->quarters_at (bbt); }
|
||||
BBT_Argument bbt_at (Beats const & beats) const { return BBT_Argument (reftime(), _meter->bbt_at (beats)); }
|
||||
BBT_Argument bbt_at (Beats const& qn) const;
|
||||
|
||||
superclock_t superclocks_per_note_type () const { return _tempo->superclocks_per_note_type (); }
|
||||
superclock_t end_superclocks_per_note_type () const {return _tempo->end_superclocks_per_note_type (); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue