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);
|
Temporal::BBT_Offset r (bars + add.bars, beats + add.beats, ticks + add.ticks);
|
||||||
|
|
||||||
/* ticks-per-bar-division; PPQN is ticks-per-quarter note */
|
if (r.ticks >= ticks_per_beat) {
|
||||||
|
|
||||||
const int32_t tpg = ticks_per_grid ();
|
|
||||||
|
|
||||||
if (r.ticks >= tpg) {
|
|
||||||
|
|
||||||
/* ticks per bar */
|
/* 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) {
|
if (r.ticks >= tpB) {
|
||||||
r.bars += r.ticks / tpB;
|
r.bars += r.ticks / tpB;
|
||||||
r.ticks %= tpB;
|
r.ticks %= tpB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.ticks >= tpg) {
|
if (r.ticks >= ticks_per_beat) {
|
||||||
r.beats += r.ticks / tpg;
|
r.beats += r.ticks / ticks_per_beat;
|
||||||
r.ticks %= tpg;
|
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 */
|
/* ticks-per-bar-division; PPQN is ticks-per-quarter note */
|
||||||
|
|
||||||
const int32_t tpg = ticks_per_grid ();
|
|
||||||
|
|
||||||
if (r.ticks < 0) {
|
if (r.ticks < 0) {
|
||||||
r.beats += floor ((double) r.ticks / tpg);
|
r.beats += floor ((double) r.ticks / ticks_per_beat);
|
||||||
r.ticks = tpg + (r.ticks % Temporal::Beats::PPQN);
|
r.ticks = ticks_per_beat + (r.ticks % ticks_per_beat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.beats <= 0) {
|
if (r.beats <= 0) {
|
||||||
|
|
@ -386,21 +380,11 @@ Meter::to_quarters (Temporal::BBT_Offset const & offset) const
|
||||||
{
|
{
|
||||||
int64_t ticks = 0;
|
int64_t ticks = 0;
|
||||||
|
|
||||||
ticks += (Beats::PPQN * offset.bars * _divisions_per_bar * 4) / _note_value;
|
ticks += (ticks_per_beat * offset.bars * _divisions_per_bar * 4) / _note_value;
|
||||||
ticks += (Beats::PPQN * offset.beats * 4) / _note_value;
|
ticks += (ticks_per_beat * offset.beats * 4) / _note_value;
|
||||||
|
ticks += offset.ticks;
|
||||||
|
|
||||||
/* "parts per bar division" */
|
return Beats (ticks / Beats::PPQN, ticks % Beats::PPQN);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -711,6 +695,12 @@ TempoMap::reftime (TempoPoint const & t, MeterPoint const & m) const
|
||||||
return pi->sclock();
|
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
|
Temporal::BBT_Argument
|
||||||
TempoMetric::bbt_at (timepos_t const & pos) const
|
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"
|
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 */
|
/* 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,
|
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")));
|
(_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());
|
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;
|
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));
|
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
||||||
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gb %1\t [%2]\n", metric, ret.back()));
|
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gb %1\t [%2]\n", metric, ret.back()));
|
||||||
} else {
|
} 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;
|
int mod = Temporal::ticks_per_beat / beat_div;
|
||||||
|
|
||||||
if ((ticks % mod) == 0) {
|
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));
|
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
||||||
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gendb %1\t [%2]\n", metric, ret.back()));
|
DEBUG_TRACE (DEBUG::Grid, string_compose ("Gendb %1\t [%2]\n", metric, ret.back()));
|
||||||
} else {
|
} 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;
|
int mod = Temporal::ticks_per_beat / beat_div;
|
||||||
if ((ticks % mod) == 0) {
|
if ((ticks % mod) == 0) {
|
||||||
ret.push_back (TempoMapPoint (*this, metric, start, beats, bbt));
|
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 */
|
/* normalize possibly too-large ticks count */
|
||||||
|
assert (offset.ticks <= ticks_per_beat);
|
||||||
|
|
||||||
const int32_t tpg = metric.meter().ticks_per_grid ();
|
if (offset.ticks > ticks_per_beat) {
|
||||||
|
|
||||||
if (offset.ticks > tpg) {
|
|
||||||
/* normalize */
|
/* normalize */
|
||||||
offset.beats += offset.ticks / tpg;
|
offset.beats += offset.ticks / ticks_per_beat;
|
||||||
offset.ticks %= tpg;
|
offset.ticks %= ticks_per_beat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add each beat, 1 by 1, rechecking to see if there's a new
|
/* 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 divisions_per_bar () const { return _divisions_per_bar; }
|
||||||
int note_value() const { return _note_value; }
|
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(); }
|
||||||
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); }
|
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); }
|
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); }
|
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 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 (); }
|
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