+
+ recompute_tempi (future_map);
+
+ if (check_solved (future_map)) {
+ for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
+ if ((*i)->is_tempo() && (*i)->minute() > ts->minute()) {
+ next_t = static_cast<TempoSection*> (*i);
+ break;
+ }
+ }
+
+ if (!next_t) {
+ return false;
+ }
+
+ if (next_t->clamped()) {
+ next_t->set_note_types_per_minute (new_copy_end_bpm);
+ } else {
+ next_t->set_note_types_per_minute (new_next_bpm);
+ }
+
+ ts->set_end_note_types_per_minute (new_copy_end_bpm);
+ recompute_map (_metrics);
+ can_solve = true;
+ }
+ }
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ 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;