}
if (!solved && recompute) {
- warning << "Adding tempo may have left the tempo map unsolved." << endmsg;
recompute_map (_metrics);
}
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
{
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);
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;
}
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
{
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;
}
{
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) {