X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Ftempo.cc;h=35a19b13db1119fa1dc0fe1909e13800a8739333;hb=9a66e1e2c6e952bf1cc1b78e57d462467cc64cfa;hp=05d3d89c15adbc87bf7bc62c284d9f6745a3735f;hpb=140258d8abc366ddd600a7b3079b55a730b10225;p=ardour.git diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 05d3d89c15..35a19b13db 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -33,7 +33,7 @@ #include "ardour/lmath.h" #include "ardour/tempo.h" -#include "i18n.h" +#include "pbd/i18n.h" #include using namespace std; @@ -179,13 +179,13 @@ TempoSection::get_state() const char buf[256]; LocaleGuard lg; - snprintf (buf, sizeof (buf), "%f", pulse()); + snprintf (buf, sizeof (buf), "%lf", pulse()); root->add_property ("pulse", buf); snprintf (buf, sizeof (buf), "%li", frame()); root->add_property ("frame", buf); - snprintf (buf, sizeof (buf), "%f", _beats_per_minute); + snprintf (buf, sizeof (buf), "%lf", _beats_per_minute); root->add_property ("beats-per-minute", buf); - snprintf (buf, sizeof (buf), "%f", _note_type); + snprintf (buf, sizeof (buf), "%lf", _note_type); root->add_property ("note-type", buf); snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no"); root->add_property ("movable", buf); @@ -569,12 +569,12 @@ MeterSection::get_state() const root->add_property ("bbt", buf); snprintf (buf, sizeof (buf), "%lf", beat()); root->add_property ("beat", buf); - snprintf (buf, sizeof (buf), "%f", _note_type); + snprintf (buf, sizeof (buf), "%lf", _note_type); root->add_property ("note-type", buf); snprintf (buf, sizeof (buf), "%li", frame()); root->add_property ("frame", buf); root->add_property ("lock-style", enum_2_string (position_lock_style())); - snprintf (buf, sizeof (buf), "%f", _divisions_per_bar); + snprintf (buf, sizeof (buf), "%lf", _divisions_per_bar); root->add_property ("divisions-per-bar", buf); snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no"); root->add_property ("movable", buf); @@ -994,7 +994,6 @@ TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, framepos_t frame } if (!solved && recompute) { - warning << "Adding tempo may have left the tempo map unsolved." << endmsg; recompute_map (_metrics); } @@ -1454,6 +1453,14 @@ TempoMap::metric_at (BBT_Time bbt) const return m; } +/** Returns the beat duration corresponding to the supplied frame, possibly returning a negative value. + * @param frame The session frame position. + * @return The beat duration according to the tempo map at the supplied frame. + * If the supplied frame lies before the first meter, the returned beat duration will be negative. + * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards). + * + * This function uses both tempo and meter. + */ double TempoMap::beat_at_frame (const framecnt_t& frame) const { @@ -1461,7 +1468,7 @@ TempoMap::beat_at_frame (const framecnt_t& frame) const return beat_at_frame_locked (_metrics, frame); } -/* meter / tempo section based */ +/* This function uses both tempo and meter.*/ double TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const { @@ -1478,9 +1485,7 @@ TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) prev_m = static_cast (*i); } } - if (frame < prev_m->frame()) { - return 0.0; - } + const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor(); /* audio locked meters fake their beat */ @@ -1856,6 +1861,18 @@ TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt) return pulse_at_bbt_locked (_metrics, bbt); } +double +TempoMap::pulse_at_bbt_rt (const Timecode::BBT_Time& bbt) +{ + Glib::Threads::RWLock::ReaderLock lm (lock); + + if (!lm.locked()) { + throw std::logic_error ("TempoMap::pulse_at_bbt_rt() could not lock tempo map"); + } + + return pulse_at_bbt_locked (_metrics, bbt); +} + double TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const { @@ -1970,7 +1987,7 @@ TempoMap::bbt_at_frame_rt (framepos_t frame) Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK); if (!lm.locked()) { - throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map"); + throw std::logic_error ("TempoMap::bbt_at_frame_rt() could not lock tempo map"); } return bbt_at_frame_locked (_metrics, frame); @@ -1984,7 +2001,6 @@ TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) bbt.bars = 1; bbt.beats = 1; bbt.ticks = 0; - warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg; return bbt; } @@ -2073,6 +2089,52 @@ TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) cons return ret; } +/** + * Returns the distance from 0 in quarter pulses at the supplied frame. + * + * Plugin APIs don't count ticks in the same way PROGRAM_NAME does. + * We use ticks per beat whereas the rest of the world uses ticks per quarter note. + * This is more or less the VST's ppqPos (a scalar you use to obtain tick position + * in whatever ppqn you're using). + * + * @param frame The distance in frames relative to session 0 whose quarter note distance you would like. + * @return The quarter note (quarter pulse) distance from session 0 to the supplied frame. Ignores meter. +*/ + +double +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; + + return ret; +} + +double +TempoMap::quarter_note_at_frame_rt (const framepos_t frame) +{ + Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK); + + if (!lm.locked()) { + throw std::logic_error ("TempoMap::quarter_note_at_frame_rt() could not lock tempo map"); + } + + const double ret = pulse_at_frame_locked (_metrics, frame) * 4.0; + + return ret; +} + +framepos_t +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); + + return ret; +} + bool TempoMap::check_solved (const Metrics& metrics) const { @@ -2977,6 +3039,15 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra MetricPositionChanged (); // Emit Signal } +/** Returns the exact beat subdivision closest to the supplied frame, possibly returning a negative value. + * @param frame The session frame position. + * @param sub_num The requested beat subdivision to use when rounding the frame position. + * @return The beat position of the supplied frame. + * If the supplied frame lies before the first meter, the return will be negative. + * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards). + * + * This function uses both tempo and meter. + */ double TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num) { @@ -2989,6 +3060,7 @@ double TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num) { double beat = beat_at_frame_locked (metrics, frame); + if (sub_num > 1) { beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num); } else if (sub_num == 1) { @@ -2999,8 +3071,18 @@ TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& Timecode::BBT_Time bbt = bbt_at_beat_locked (metrics, beat); bbt.beats = 1; bbt.ticks = 0; - beat = beat_at_bbt_locked (metrics, bbt); + + const double prev_b = beat_at_bbt_locked (_metrics, bbt); + ++bbt.bars; + const double next_b = beat_at_bbt_locked (_metrics, bbt); + + if ((beat - prev_b) > (next_b - prev_b) / 2.0) { + beat = next_b; + } else { + beat = prev_b; + } } + return beat; } @@ -3009,7 +3091,7 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) { Glib::Threads::RWLock::ReaderLock lm (lock); - const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat; + const double tick_at_time = max (0.0, beat_at_frame_locked (_metrics, pos)) * BBT_Time::ticks_per_beat; const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat); const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat; @@ -3032,7 +3114,7 @@ framepos_t TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir) { Glib::Threads::RWLock::ReaderLock lm (lock); - uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat); + uint32_t ticks = (uint32_t) floor (max (0.0, beat_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; @@ -3129,7 +3211,7 @@ TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type) { Glib::Threads::RWLock::ReaderLock lm (lock); - const double beat_at_framepos = beat_at_frame_locked (_metrics, frame); + const double beat_at_framepos = max (0.0, beat_at_frame_locked (_metrics, frame)); BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos)); switch (type) { @@ -3471,6 +3553,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) catch (failed_constructor& err){ error << _("Tempo map: could not set new state, restoring old one.") << endmsg; _metrics = old_metrics; + old_metrics.clear(); break; } @@ -3484,6 +3567,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) catch (failed_constructor& err) { error << _("Tempo map: could not set new state, restoring old one.") << endmsg; _metrics = old_metrics; + old_metrics.clear(); break; } } @@ -3535,6 +3619,13 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) } recompute_map (_metrics); + + Metrics::const_iterator d = old_metrics.begin(); + while (d != old_metrics.end()) { + delete (*d); + ++d; + } + old_metrics.clear (); } PropertyChanged (PropertyChange ()); @@ -3706,7 +3797,7 @@ TempoMap::insert_time (framepos_t where, framecnt_t amount) bbt.beats = 1; } } - pair start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt); + pair start = make_pair (max (0.0, beat_at_frame_locked (_metrics, m->frame())), bbt); m->set_beat (start); m->set_pulse (pulse_at_frame_locked (_metrics, m->frame())); meter = m; @@ -3790,11 +3881,11 @@ TempoMap::remove_time (framepos_t where, framecnt_t amount) * pos can be -ve, if required. */ framepos_t -TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const +TempoMap::framepos_plus_beats (framepos_t frame, Evoral::Beats beats) const { Glib::Threads::RWLock::ReaderLock lm (lock); - return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double()); + 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 */