+ MetricPositionChanged (PropertyChange ()); // Emit Signal
+
+ return can_solve;
+}
+
+/** Returns the sample position of the musical position zero */
+samplepos_t
+TempoMap::music_origin ()
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return first_tempo().sample();
+}
+
+/** Returns the exact bbt-based beat corresponding to the bar, beat or quarter note subdivision nearest to
+ * the supplied sample, possibly returning a negative value.
+ *
+ * @param sample The session sample position.
+ * @param sub_num The subdivision to use when rounding the beat.
+ * A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
+ * Positive integers indicate quarter note (non BBT) divisions.
+ * 0 indicates that the returned beat should not be rounded (equivalent to quarter_note_at_sample()).
+ * @return The beat position of the supplied sample.
+ *
+ * when working to a musical grid, the use of sub_nom indicates that
+ * the position should be interpreted musically.
+ *
+ * it effectively snaps to meter bars, meter beats or quarter note divisions
+ * (as per current gui convention) and returns a musical position independent of frame rate.
+ *
+ * If the supplied sample lies before the first meter, the return will be negative,
+ * in which case the returned beat uses the first meter (for BBT subdivisions) and
+ * the continuation of the tempo curve (backwards).
+ *
+ * This function is sensitive to tempo and meter.
+ */
+double
+TempoMap::exact_beat_at_sample (const samplepos_t sample, const int32_t sub_num) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return exact_beat_at_sample_locked (_metrics, sample, sub_num);
+}
+
+double
+TempoMap::exact_beat_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t divisions) const
+{
+ return beat_at_pulse_locked (_metrics, exact_qn_at_sample_locked (metrics, sample, divisions) / 4.0);
+}
+
+/** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
+ * the supplied sample, possibly returning a negative value.
+ *
+ * @param sample The session sample position.
+ * @param sub_num The subdivision to use when rounding the quarter note.
+ * A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
+ * Positive integers indicate quarter note (non BBT) divisions.
+ * 0 indicates that the returned quarter note should not be rounded (equivalent to quarter_note_at_sample()).
+ * @return The quarter note position of the supplied sample.
+ *
+ * When working to a musical grid, the use of sub_nom indicates that
+ * the sample position should be interpreted musically.
+ *
+ * it effectively snaps to meter bars, meter beats or quarter note divisions
+ * (as per current gui convention) and returns a musical position independent of frame rate.
+ *
+ * If the supplied sample lies before the first meter, the return will be negative,
+ * in which case the returned quarter note uses the first meter (for BBT subdivisions) and
+ * the continuation of the tempo curve (backwards).
+ *
+ * This function is tempo-sensitive.
+ */
+double
+TempoMap::exact_qn_at_sample (const samplepos_t sample, const int32_t sub_num) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return exact_qn_at_sample_locked (_metrics, sample, sub_num);
+}
+
+double
+TempoMap::exact_qn_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const
+{
+ double qn = pulse_at_minute_locked (metrics, minute_at_sample (sample)) * 4.0;
+
+ if (sub_num > 1) {
+ qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
+ } else if (sub_num == 1) {
+ /* the gui requested exact musical (BBT) beat */
+ qn = pulse_at_beat_locked (metrics, (floor (beat_at_minute_locked (metrics, minute_at_sample (sample)) + 0.5))) * 4.0;
+ } 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;