Add quarter-note position methods to TempoMap.
This commit is contained in:
parent
21054f6d8d
commit
395183ee7b
@ -363,6 +363,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||
framepos_t round_to_bar (framepos_t frame, RoundMode dir);
|
||||
framepos_t round_to_beat (framepos_t frame, RoundMode dir);
|
||||
framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir);
|
||||
framepos_t round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir);
|
||||
|
||||
void set_length (framepos_t frames);
|
||||
|
||||
@ -446,12 +447,16 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||
|
||||
framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
|
||||
framepos_t framepos_plus_beats (framepos_t, Evoral::Beats) const;
|
||||
framepos_t framepos_plus_qn (framepos_t, Evoral::Beats) const;
|
||||
framepos_t framepos_minus_beats (framepos_t, Evoral::Beats) const;
|
||||
Evoral::Beats framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
|
||||
Evoral::Beats framewalk_to_qn (framepos_t pos, framecnt_t distance) const;
|
||||
|
||||
double quarter_note_at_frame (const framepos_t frame);
|
||||
double quarter_note_at_frame_rt (const framepos_t frame);
|
||||
framepos_t frame_at_quarter_note (const double quarter_note);
|
||||
double quarter_note_at_beat (const double beat);
|
||||
double beat_at_quarter_note (const double beat);
|
||||
|
||||
void gui_move_tempo (TempoSection*, const framepos_t& frame, const int& sub_num);
|
||||
void gui_move_meter (MeterSection*, const framepos_t& frame);
|
||||
@ -459,6 +464,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||
void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame, const double& pulse);
|
||||
|
||||
double exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num);
|
||||
double exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num);
|
||||
|
||||
std::pair<double, framepos_t> predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt);
|
||||
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
|
||||
@ -489,6 +495,10 @@ private:
|
||||
double pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const;
|
||||
Timecode::BBT_Time bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
|
||||
|
||||
framepos_t frame_at_quarter_note_locked (const Metrics& metrics, const double quarter_note);
|
||||
double quarter_note_at_frame_locked (const Metrics& metrics, const framepos_t frame);
|
||||
double quarter_note_at_beat_locked (const Metrics& metrics, const double beat);
|
||||
|
||||
const TempoSection& tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const;
|
||||
const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
|
||||
|
||||
@ -504,6 +514,7 @@ private:
|
||||
bool solve_map_bbt (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt);
|
||||
|
||||
double exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num);
|
||||
double exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num);
|
||||
|
||||
friend class ::BBTTest;
|
||||
friend class ::FrameposPlusBeatsTest;
|
||||
|
@ -2106,7 +2106,15 @@ TempoMap::quarter_note_at_frame (const framepos_t frame)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
const double ret = pulse_at_frame_locked (_metrics, frame) * 4.0;
|
||||
const double ret = quarter_note_at_frame_locked (_metrics, frame);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double
|
||||
TempoMap::quarter_note_at_frame_locked (const Metrics& metrics, const framepos_t frame)
|
||||
{
|
||||
const double ret = pulse_at_frame_locked (metrics, frame) * 4.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2130,7 +2138,43 @@ TempoMap::frame_at_quarter_note (const double quarter_note)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
const framepos_t ret = frame_at_pulse_locked (_metrics, quarter_note / 4.0);
|
||||
const framepos_t ret = frame_at_quarter_note_locked (_metrics, quarter_note);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
framepos_t
|
||||
TempoMap::frame_at_quarter_note_locked (const Metrics& metrics, const double quarter_note)
|
||||
{
|
||||
const framepos_t ret = frame_at_pulse_locked (metrics, quarter_note / 4.0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double
|
||||
TempoMap::quarter_note_at_beat (const double beat)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
const double ret = quarter_note_at_beat_locked (_metrics, beat);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double
|
||||
TempoMap::quarter_note_at_beat_locked (const Metrics& metrics, const double beat)
|
||||
{
|
||||
const double ret = pulse_at_beat_locked (metrics, beat) * 4.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double
|
||||
TempoMap::beat_at_quarter_note (const double quarter_note)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
const double ret = beat_at_pulse_locked (_metrics, quarter_note / 4.0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -3102,6 +3146,43 @@ TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t&
|
||||
|
||||
return beat;
|
||||
}
|
||||
double
|
||||
TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock);
|
||||
|
||||
return exact_qn_at_frame_locked (_metrics, frame, sub_num);
|
||||
}
|
||||
|
||||
double
|
||||
TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
|
||||
{
|
||||
double qn = quarter_note_at_frame_locked (metrics, frame);
|
||||
|
||||
if (sub_num > 1) {
|
||||
qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
|
||||
} else if (sub_num == 1) {
|
||||
/* snap to quarter note */
|
||||
qn = floor (qn + 0.5);
|
||||
} else if (sub_num == -1) {
|
||||
/* snap to bar */
|
||||
Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
|
||||
bbt.beats = 1;
|
||||
bbt.ticks = 0;
|
||||
|
||||
const double prev_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
|
||||
++bbt.bars;
|
||||
const double next_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
|
||||
|
||||
if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
|
||||
qn = next_b;
|
||||
} else {
|
||||
qn = prev_b;
|
||||
}
|
||||
}
|
||||
|
||||
return qn;
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
|
||||
@ -3223,6 +3304,102 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
|
||||
return ret_frame;
|
||||
}
|
||||
|
||||
framepos_t
|
||||
TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock);
|
||||
uint32_t ticks = (uint32_t) floor (max (0.0, quarter_note_at_frame_locked (_metrics, fr)) * BBT_Time::ticks_per_beat);
|
||||
uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
|
||||
uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
|
||||
|
||||
ticks -= beats * BBT_Time::ticks_per_beat;
|
||||
|
||||
if (dir > 0) {
|
||||
/* round to next (or same iff dir == RoundUpMaybe) */
|
||||
|
||||
uint32_t mod = ticks % ticks_one_subdivisions_worth;
|
||||
|
||||
if (mod == 0 && dir == RoundUpMaybe) {
|
||||
/* right on the subdivision, which is fine, so do nothing */
|
||||
|
||||
} else if (mod == 0) {
|
||||
/* right on the subdivision, so the difference is just the subdivision ticks */
|
||||
ticks += ticks_one_subdivisions_worth;
|
||||
|
||||
} else {
|
||||
/* not on subdivision, compute distance to next subdivision */
|
||||
|
||||
ticks += ticks_one_subdivisions_worth - mod;
|
||||
}
|
||||
|
||||
if (ticks >= BBT_Time::ticks_per_beat) {
|
||||
ticks -= BBT_Time::ticks_per_beat;
|
||||
}
|
||||
} else if (dir < 0) {
|
||||
|
||||
/* round to previous (or same iff dir == RoundDownMaybe) */
|
||||
|
||||
uint32_t difference = ticks % ticks_one_subdivisions_worth;
|
||||
|
||||
if (difference == 0 && dir == RoundDownAlways) {
|
||||
/* right on the subdivision, but force-rounding down,
|
||||
so the difference is just the subdivision ticks */
|
||||
difference = ticks_one_subdivisions_worth;
|
||||
}
|
||||
|
||||
if (ticks < difference) {
|
||||
ticks = BBT_Time::ticks_per_beat - ticks;
|
||||
} else {
|
||||
ticks -= difference;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* round to nearest */
|
||||
double rem;
|
||||
|
||||
/* compute the distance to the previous and next subdivision */
|
||||
|
||||
if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
|
||||
|
||||
/* closer to the next subdivision, so shift forward */
|
||||
|
||||
ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
|
||||
|
||||
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
|
||||
|
||||
if (ticks > BBT_Time::ticks_per_beat) {
|
||||
++beats;
|
||||
ticks -= BBT_Time::ticks_per_beat;
|
||||
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
|
||||
}
|
||||
|
||||
} else if (rem > 0) {
|
||||
|
||||
/* closer to previous subdivision, so shift backward */
|
||||
|
||||
if (rem > ticks) {
|
||||
if (beats == 0) {
|
||||
/* can't go backwards past zero, so ... */
|
||||
return 0;
|
||||
}
|
||||
/* step back to previous beat */
|
||||
--beats;
|
||||
ticks = lrint (BBT_Time::ticks_per_beat - rem);
|
||||
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
|
||||
} else {
|
||||
ticks = lrint (ticks - rem);
|
||||
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
|
||||
}
|
||||
} else {
|
||||
/* on the subdivision, do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
const framepos_t ret_frame = frame_at_quarter_note_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
|
||||
|
||||
return ret_frame;
|
||||
}
|
||||
|
||||
framepos_t
|
||||
TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
|
||||
{
|
||||
@ -3904,6 +4081,13 @@ TempoMap::framepos_plus_beats (framepos_t frame, Evoral::Beats beats) const
|
||||
|
||||
return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, frame) + beats.to_double());
|
||||
}
|
||||
framepos_t
|
||||
TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats beats) const
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock);
|
||||
|
||||
return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, frame) + beats.to_double());
|
||||
}
|
||||
|
||||
/** Subtract some (fractional) beats from a frame position, and return the result in frames */
|
||||
framepos_t
|
||||
@ -3950,6 +4134,13 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
|
||||
return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
|
||||
}
|
||||
|
||||
Evoral::Beats
|
||||
TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (lock);
|
||||
|
||||
return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
|
||||
}
|
||||
struct bbtcmp {
|
||||
bool operator() (const BBT_Time& a, const BBT_Time& b) {
|
||||
return a < b;
|
||||
|
Loading…
Reference in New Issue
Block a user