const string TempoSection::xml_state_node_name = "Tempo";
TempoSection::TempoSection (const XMLNode& node)
- : MetricSection (0.0)
+ : MetricSection (0.0, 0, MusicTime)
, Tempo (TempoMap::default_tempo())
, _c_func (0.0)
, _active (true)
, _locked_to_meter (false)
{
- const XMLProperty *prop;
+ XMLProperty const * prop;
LocaleGuard lg;
BBT_Time bbt;
double pulse;
const string MeterSection::xml_state_node_name = "Meter";
MeterSection::MeterSection (const XMLNode& node)
- : MetricSection (0.0), Meter (TempoMap::default_meter())
+ : MetricSection (0.0, 0, MusicTime), Meter (TempoMap::default_meter())
{
XMLProperty const * prop;
- BBT_Time start;
LocaleGuard lg;
- const XMLProperty *prop;
BBT_Time bbt;
double pulse = 0.0;
double beat = 0.0;
_frame_rate = fr;
BBT_Time start (1, 1, 0);
- TempoSection *t = new TempoSection ((framepos_t) 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant);
- MeterSection *m = new MeterSection ((framepos_t) 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
+ TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant, AudioTime);
+ MeterSection *m = new MeterSection (0.0, 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime);
t->set_movable (false);
m->set_movable (false);
}
}
-void
-TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, TempoSection::Type type)
+TempoSection*
+TempoMap::add_tempo (const Tempo& tempo, const double& pulse, const framepos_t& frame, ARDOUR::TempoSection::Type type, PositionLockStyle pls)
{
+ TempoSection* ts = 0;
{
Glib::Threads::RWLock::WriterLock lm (lock);
- TempoSection& first (first_tempo());
- if (ts.pulse() != first.pulse()) {
- remove_tempo_locked (ts);
- add_tempo_locked (tempo, pulse, true, type);
- } else {
- first.set_type (type);
- {
- /* cannot move the first tempo section */
- *static_cast<Tempo*>(&first) = tempo;
- recompute_map (_metrics);
- }
- }
+ ts = add_tempo_locked (tempo, pulse, frame, type, pls, true);
}
+
PropertyChanged (PropertyChange ());
+
+ return ts;
}
void
-TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const framepos_t& frame, TempoSection::Type type)
+TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls)
{
+ const bool locked_to_meter = ts.locked_to_meter();
+
{
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection& first (first_tempo());
if (ts.frame() != first.frame()) {
remove_tempo_locked (ts);
- add_tempo_locked (tempo, frame, true, type);
+ add_tempo_locked (tempo, pulse, frame, type, pls, true, locked_to_meter);
} else {
first.set_type (type);
first.set_pulse (0.0);
+ first.set_frame (frame);
first.set_position_lock_style (AudioTime);
{
/* cannot move the first tempo section */
}
TempoSection*
-TempoMap::add_tempo (const Tempo& tempo, const double& pulse, ARDOUR::TempoSection::Type type)
-{
- TempoSection* ts = 0;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- ts = add_tempo_locked (tempo, pulse, true, type);
- }
-
- PropertyChanged (PropertyChange ());
-
- return ts;
-}
-
-TempoSection*
-TempoMap::add_tempo (const Tempo& tempo, const framepos_t& frame, ARDOUR::TempoSection::Type type)
-{
- TempoSection* ts = 0;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- ts = add_tempo_locked (tempo, frame, true, type);
- }
-
-
- PropertyChanged (PropertyChange ());
-
- return ts;
-}
-
-TempoSection*
-TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, bool recompute, ARDOUR::TempoSection::Type type)
+TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, framepos_t frame
+ , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter)
{
- TempoSection* t = new TempoSection (pulse, tempo.beats_per_minute(), tempo.note_type(), type);
+ TempoSection* t = new TempoSection (pulse, frame, tempo.beats_per_minute(), tempo.note_type(), type, pls);
+ t->set_locked_to_meter (locked_to_meter);
do_insert (t);
if (recompute) {
- solve_map (_metrics, t, t->pulse());
- recompute_meters (_metrics);
- }
-
- return t;
-}
-
-TempoSection*
-TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute, ARDOUR::TempoSection::Type type)
-{
- TempoSection* t = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
-
- do_insert (t);
-
- if (recompute) {
- solve_map (_metrics, t, t->frame());
+ if (pls == AudioTime) {
+ solve_map_frame (_metrics, t, t->frame());
+ } else {
+ solve_map_pulse (_metrics, t, t->pulse());
+ }
recompute_meters (_metrics);
}
return t;
}
-void
-TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
+MeterSection*
+TempoMap::add_meter (const Meter& meter, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
{
+ MeterSection* m = 0;
{
Glib::Threads::RWLock::WriterLock lm (lock);
+ m = add_meter_locked (meter, beat, where, frame, pls, true);
+ }
- if (ms.movable()) {
- remove_meter_locked (ms);
- add_meter_locked (meter, bbt_to_beats_locked (_metrics, where), where, true);
- } else {
- MeterSection& first (first_meter());
- /* cannot move the first meter section */
- *static_cast<Meter*>(&first) = meter;
- first.set_position_lock_style (AudioTime);
- }
- recompute_map (_metrics);
+
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(DEBUG::TempoMap)) {
+ dump (_metrics, std::cerr);
}
+#endif
PropertyChanged (PropertyChange ());
+ return m;
}
void
-TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const framepos_t& frame)
+TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
{
{
Glib::Threads::RWLock::WriterLock lm (lock);
-
- const double beat = ms.beat();
- const BBT_Time bbt = ms.bbt();
+ const double beat = bbt_to_beats_locked (_metrics, where);
if (ms.movable()) {
remove_meter_locked (ms);
- add_meter_locked (meter, frame, beat, bbt, true);
+ add_meter_locked (meter, beat, where, frame, pls, true);
} else {
MeterSection& first (first_meter());
TempoSection& first_t (first_tempo());
PropertyChanged (PropertyChange ());
}
-
-MeterSection*
-TempoMap::add_meter (const Meter& meter, const double& beat, const BBT_Time& where)
-{
- MeterSection* m = 0;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- m = add_meter_locked (meter, beat, where, true);
- }
-
-
-#ifndef NDEBUG
- if (DEBUG_ENABLED(DEBUG::TempoMap)) {
- dump (_metrics, std::cerr);
- }
-#endif
-
- PropertyChanged (PropertyChange ());
-
- return m;
-}
-
MeterSection*
-TempoMap::add_meter (const Meter& meter, const framepos_t& frame, const double& beat, const Timecode::BBT_Time& where)
+TempoMap::add_meter_locked (const Meter& meter, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
{
- MeterSection* m = 0;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- m = add_meter_locked (meter, frame, beat, where, true);
- }
-
+ const MeterSection& prev_m = meter_section_at_locked (_metrics, frame - 1);
+ const double pulse = ((where.bars - prev_m.bbt().bars) * (prev_m.divisions_per_bar() / prev_m.note_divisor())) + prev_m.pulse();
-#ifndef NDEBUG
- if (DEBUG_ENABLED(DEBUG::TempoMap)) {
- dump (_metrics, std::cerr);
+ if (pls == AudioTime) {
+ /* add meter-locked tempo */
+ add_tempo_locked (tempo_at_locked (_metrics, frame), pulse, frame, TempoSection::Ramp, AudioTime, true, true);
}
-#endif
- PropertyChanged (PropertyChange ());
-
- return m;
-}
-
-MeterSection*
-TempoMap::add_meter_locked (const Meter& meter, double beat, const BBT_Time& where, bool recompute)
-{
- /* a new meter always starts a new bar on the first beat. so
- round the start time appropriately. remember that
- `where' is based on the existing tempo map, not
- the result after we insert the new meter.
-
- */
-
- const double pulse = pulse_at_beat_locked (_metrics, beat);
- MeterSection* new_meter = new MeterSection (pulse, beat, where, meter.divisions_per_bar(), meter.note_divisor());
+ MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
do_insert (new_meter);
if (recompute) {
- solve_map (_metrics, new_meter, where);
- }
-
- return new_meter;
-}
-MeterSection*
-TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, const Timecode::BBT_Time& where, bool recompute)
-{
- /* add meter-locked tempo */
- TempoSection* t = add_tempo_locked (tempo_at_locked (_metrics, frame), frame, true, TempoSection::Ramp);
- if (t) {
- t->set_locked_to_meter (true);
- }
-
- MeterSection* new_meter = new MeterSection (frame, beat, where, meter.divisions_per_bar(), meter.note_divisor());
- new_meter->set_pulse (pulse_at_frame_locked (_metrics, frame));
-
- do_insert (new_meter);
-
- if (recompute) {
- solve_map (_metrics, new_meter, frame);
+ if (pls == AudioTime) {
+ solve_map_frame (_metrics, new_meter, frame);
+ } else {
+ solve_map_bbt (_metrics, new_meter, where);
+ }
}
return new_meter;
return m;
}
+double
+TempoMap::pulse_at_beat (const double& beat) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ return pulse_at_beat_locked (_metrics, beat);
+}
+
double
TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
{
}
double
-TempoMap::pulse_at_beat (const double& beat) const
+TempoMap::beat_at_pulse (const double& pulse) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return pulse_at_beat_locked (_metrics, beat);
+ return beat_at_pulse_locked (_metrics, pulse);
}
double
}
double
-TempoMap::beat_at_pulse (const double& pulse) const
+TempoMap::pulse_at_frame (const framecnt_t& frame) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return beat_at_pulse_locked (_metrics, pulse);
+ return pulse_at_frame_locked (_metrics, frame);
}
/* tempo section based */
return pulses_in_section + prev_t->pulse();
}
-double
-TempoMap::pulse_at_frame (const framecnt_t& frame) const
+framecnt_t
+TempoMap::frame_at_pulse (const double& pulse) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return pulse_at_frame_locked (_metrics, frame);
+ return frame_at_pulse_locked (_metrics, pulse);
}
/* tempo section based */
return ret;
}
-framecnt_t
-TempoMap::frame_at_pulse (const double& pulse) const
+double
+TempoMap::beat_at_frame (const framecnt_t& frame) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return frame_at_pulse_locked (_metrics, pulse);
+ return beat_at_frame_locked (_metrics, frame);
}
/* meter section based */
return beat;
}
-double
-TempoMap::beat_at_frame (const framecnt_t& frame) const
+framecnt_t
+TempoMap::frame_at_beat (const double& beat) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return beat_at_frame_locked (_metrics, frame);
+ return frame_at_beat_locked (_metrics, beat);
}
/* meter section based */
return prev_t.frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
}
-framecnt_t
-TempoMap::frame_at_beat (const double& beat) const
+double
+TempoMap::bbt_to_beats (const Timecode::BBT_Time& bbt)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return frame_at_beat_locked (_metrics, beat);
+ return bbt_to_beats_locked (_metrics, bbt);
}
+
double
TempoMap::bbt_to_beats_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
{
return ret;
}
-double
-TempoMap::bbt_to_beats (const Timecode::BBT_Time& bbt)
+Timecode::BBT_Time
+TempoMap::beats_to_bbt (const double& beats)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return bbt_to_beats_locked (_metrics, bbt);
+ return beats_to_bbt_locked (_metrics, beats);
}
Timecode::BBT_Time
{
/* CALLER HOLDS READ LOCK */
MeterSection* prev_m = 0;
- const double beats = (b < 0.0) ? 0.0 : b;
+ const double beats = max (0.0, b);
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
return ret;
}
-Timecode::BBT_Time
-TempoMap::beats_to_bbt (const double& beats)
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return beats_to_bbt_locked (_metrics, beats);
-}
-
Timecode::BBT_Time
TempoMap::pulse_to_bbt (const double& pulse)
{
bbt = beats_to_bbt_locked (_metrics, beat);
}
-/* meter section based */
-framepos_t
-TempoMap::frame_time_locked (const Metrics& metrics, const BBT_Time& bbt) const
-{
- /* HOLD THE READER LOCK */
-
- const framepos_t ret = frame_at_beat_locked (metrics, bbt_to_beats_locked (metrics, bbt));
- return ret;
-}
-
framepos_t
TempoMap::frame_time (const BBT_Time& bbt)
{
return frame_time_locked (_metrics, bbt);
}
+/* meter section based */
+framepos_t
+TempoMap::frame_time_locked (const Metrics& metrics, const BBT_Time& bbt) const
+{
+ /* HOLD THE READER LOCK */
+
+ const framepos_t ret = frame_at_beat_locked (metrics, bbt_to_beats_locked (metrics, bbt));
+ return ret;
+}
+
bool
-TempoMap::check_solved (const Metrics& metrics, bool by_frame) const
+TempoMap::check_solved (const Metrics& metrics) const
{
TempoSection* prev_t = 0;
MeterSection* prev_m = 0;
continue;
}
if (prev_t) {
- if ((by_frame && t->frame() < prev_t->frame()) || (!by_frame && t->pulse() < prev_t->pulse())) {
- return false;
- }
-
- if (t->frame() == prev_t->frame()) {
+ if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
return false;
}
}
bool
-TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
+TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
{
TempoSection* prev_t = 0;
TempoSection* section_prev = 0;
}
}
- if (section->position_lock_style() == MusicTime) {
- /* we're setting the frame */
- section->set_position_lock_style (AudioTime);
- recompute_tempos (imaginary);
- section->set_position_lock_style (MusicTime);
- } else {
- recompute_tempos (imaginary);
- }
+ recompute_tempos (imaginary);
- if (check_solved (imaginary, true)) {
+ if (check_solved (imaginary)) {
return true;
}
MetricSectionFrameSorter fcmp;
imaginary.sort (fcmp);
- if (section->position_lock_style() == MusicTime) {
- /* we're setting the frame */
- section->set_position_lock_style (AudioTime);
- recompute_tempos (imaginary);
- section->set_position_lock_style (MusicTime);
- } else {
- recompute_tempos (imaginary);
- }
- if (check_solved (imaginary, true)) {
+ recompute_tempos (imaginary);
+
+ if (check_solved (imaginary)) {
return true;
}
}
bool
-TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pulse)
+TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
{
TempoSection* prev_t = 0;
TempoSection* section_prev = 0;
prev_t = t;
}
}
+
if (section_prev) {
section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
}
- if (section->position_lock_style() == AudioTime) {
- /* we're setting the pulse */
- section->set_position_lock_style (MusicTime);
- recompute_tempos (imaginary);
- section->set_position_lock_style (AudioTime);
- } else {
- recompute_tempos (imaginary);
- }
+ recompute_tempos (imaginary);
- if (check_solved (imaginary, false)) {
+ if (check_solved (imaginary)) {
return true;
}
MetricSectionSorter cmp;
imaginary.sort (cmp);
- if (section->position_lock_style() == AudioTime) {
- /* we're setting the pulse */
- section->set_position_lock_style (MusicTime);
- recompute_tempos (imaginary);
- section->set_position_lock_style (AudioTime);
- } else {
- recompute_tempos (imaginary);
- }
- if (check_solved (imaginary, false)) {
+ recompute_tempos (imaginary);
+ /* Reordering
+ * XX need a restriction here, but only for this case,
+ * as audio locked tempos don't interact in the same way.
+ *
+ * With music-locked tempos, the solution to cross-dragging can fly off the screen
+ * e.g.
+ * |50 bpm |250 bpm |60 bpm
+ * drag 250 to the pulse after 60->
+ * a clue: dragging the second 60 <- past the 250 would cause no such problem.
+ */
+ if (check_solved (imaginary)) {
return true;
}
}
bool
-TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
+TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
{
/* disallow moving first meter past any subsequent one, and any movable meter before the first one */
const MeterSection* other = &meter_section_at_locked (imaginary, frame);
}
}
+ if (!meter_locked_tempo) {
+ return false;
+ }
+
MeterSection* prev_m = 0;
+ Metrics future_map;
+ bool solved = false;
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MeterSection* m;
if (prev_m && section->movable()) {
const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
if (beats + prev_m->beat() < section->beat()) {
- /* disallow position change if it will alter our beat
- we allow tempo changes to do this in recompute_meters().
- blocking this is an option, but i'm not convinced that
- this is what the user would actually want.
- here we set the frame/pulse corresponding to its musical position.
+ /* set the frame/pulse corresponding to its musical position,
+ * as an earlier time than this has been requested.
*/
- if (meter_locked_tempo) {
- Metrics future_map;
- bool solved = false;
- TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
- const double new_pulse = ((section->beat() - prev_m->beat())
- / prev_m->note_divisor()) + prev_m->pulse();
- const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
- if ((solved = solve_map (future_map, tempo_copy, smallest_frame))) {
- meter_locked_tempo->set_pulse (new_pulse);
- solve_map (imaginary, meter_locked_tempo, smallest_frame);
- section->set_frame (smallest_frame);
- section->set_pulse (new_pulse);
- } else {
- solved = false;
- }
-
- Metrics::const_iterator d = future_map.begin();
- while (d != future_map.end()) {
- delete (*d);
- ++d;
- }
-
- if (!solved) {
- return false;
- }
+ TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
+ const double new_pulse = ((section->beat() - prev_m->beat())
+ / prev_m->note_divisor()) + prev_m->pulse();
+ const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
+ if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
+ meter_locked_tempo->set_pulse (new_pulse);
+ solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
+ section->set_frame (smallest_frame);
+ section->set_pulse (new_pulse);
+ } else {
+ solved = false;
}
- return false;
- } else {
- if (meter_locked_tempo) {
- Metrics future_map;
- bool solved = false;
- TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
- MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_locked (future_map, section->frame()));
- meter_copy->set_frame (frame);
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
- if ((solved = solve_map (future_map, tempo_copy, frame))) {
- section->set_frame (frame);
- meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
- / prev_m->note_divisor()) + prev_m->pulse());
- solve_map (imaginary, meter_locked_tempo, frame);
- } else {
- solved = false;
- }
-
- Metrics::const_iterator d = future_map.begin();
- while (d != future_map.end()) {
- delete (*d);
- ++d;
- }
-
- if (!solved) {
- return false;
- }
+ if (!solved) {
+ return false;
}
- }
- } else {
- /* not movable (first meter atm) */
- if (meter_locked_tempo) {
- Metrics future_map;
- bool solved = false;
- TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
+ } else {
- tempo_copy->set_frame (frame);
- tempo_copy->set_pulse (0.0);
+ TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
+ MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_locked (future_map, section->frame()));
+ meter_copy->set_frame (frame);
- if ((solved = solve_map (future_map, tempo_copy, frame))) {
+ if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
section->set_frame (frame);
- meter_locked_tempo->set_frame (frame);
- meter_locked_tempo->set_pulse (0.0);
- solve_map (imaginary, meter_locked_tempo, frame);
+ meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
+ / prev_m->note_divisor()) + prev_m->pulse());
+ solve_map_frame (imaginary, meter_locked_tempo, frame);
} else {
solved = false;
}
if (!solved) {
return false;
}
+ }
+ } else {
+ /* not movable (first meter atm) */
+
+ TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
+ tempo_copy->set_frame (frame);
+ tempo_copy->set_pulse (0.0);
+
+ if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
+ section->set_frame (frame);
+ meter_locked_tempo->set_frame (frame);
+ meter_locked_tempo->set_pulse (0.0);
+ solve_map_frame (imaginary, meter_locked_tempo, frame);
} else {
+ solved = false;
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ if (!solved) {
return false;
}
+
pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
section->set_beat (b_bbt);
section->set_pulse (0.0);
MetricSectionFrameSorter fcmp;
imaginary.sort (fcmp);
- if (section->position_lock_style() == MusicTime) {
- /* we're setting the frame */
- section->set_position_lock_style (AudioTime);
- recompute_meters (imaginary);
- section->set_position_lock_style (MusicTime);
- } else {
- recompute_meters (imaginary);
- }
+
+ recompute_meters (imaginary);
return true;
}
bool
-TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
+TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
{
/* disallow setting section to an existing meter's bbt */
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MetricSectionSorter cmp;
imaginary.sort (cmp);
- if (section->position_lock_style() == AudioTime) {
- /* we're setting the pulse */
- section->set_position_lock_style (MusicTime);
- recompute_meters (imaginary);
- section->set_position_lock_style (AudioTime);
- } else {
- recompute_meters (imaginary);
- }
+ recompute_meters (imaginary);
return true;
}
}
const double beat = bbt_to_beats_locked (copy, bbt);
- const bool ret = solve_map (copy, tempo_copy, pulse_at_beat_locked (copy, beat));
+ const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_beat_locked (copy, beat));
Metrics::const_iterator d = copy.begin();
while (d != copy.end()) {
}
const double beat = bbt_to_beats_locked (future_map, bbt);
- if (solve_map (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
+ if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
ret = tempo_copy->frame();
} else {
ret = section->frame();
double ret = 0.0;
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
- if (solve_map (future_map, tempo_copy, frame)) {
+ if (solve_map_frame (future_map, tempo_copy, frame)) {
ret = tempo_copy->pulse();
} else {
ret = section->pulse();
{
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map (future_map, tempo_copy, frame)) {
- solve_map (_metrics, ts, frame);
+ if (solve_map_frame (future_map, tempo_copy, frame)) {
+ solve_map_frame (_metrics, ts, frame);
recompute_meters (_metrics);
}
}
{
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
- solve_map (_metrics, ts, pulse_at_beat_locked (_metrics, beat));
+ if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
+ solve_map_pulse (_metrics, ts, pulse_at_beat_locked (_metrics, beat));
recompute_meters (_metrics);
}
}
}
void
-TempoMap::gui_move_tempo_pulse (TempoSection* ts, const double& pulse)
-{
- Metrics future_map;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map (future_map, tempo_copy, pulse)) {
- solve_map (_metrics, ts, pulse);
- recompute_meters (_metrics);
- }
- }
-
- Metrics::const_iterator d = future_map.begin();
- while (d != future_map.end()) {
- delete (*d);
- ++d;
- }
-
- MetricPositionChanged (); // Emit Signal
-}
-
-void
-TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
+TempoMap::gui_move_meter_frame (MeterSection* ms, const framepos_t& frame)
{
Metrics future_map;
{
Glib::Threads::RWLock::WriterLock lm (lock);
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
- if (solve_map (future_map, copy, frame)) {
- solve_map (_metrics, ms, frame);
+ if (solve_map_frame (future_map, copy, frame)) {
+ solve_map_frame (_metrics, ms, frame);
recompute_tempos (_metrics);
}
}
}
void
-TempoMap::gui_move_meter (MeterSection* ms, const Timecode::BBT_Time& bbt)
+TempoMap::gui_move_meter_bbt (MeterSection* ms, const Timecode::BBT_Time& bbt)
{
Metrics future_map;
{
Glib::Threads::RWLock::WriterLock lm (lock);
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
- if (solve_map (future_map, copy, bbt)) {
- solve_map (_metrics, ms, bbt);
+ if (solve_map_bbt (future_map, copy, bbt)) {
+ solve_map_bbt (_metrics, ms, bbt);
recompute_tempos (_metrics);
}
}
tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
recompute_tempos (future_map);
- if (check_solved (future_map, true)) {
+ if (check_solved (future_map)) {
ts->set_beats_per_minute (bpm.beats_per_minute());
recompute_map (_metrics);
can_solve = true;
new_bpm = prev_t->tempo_at_frame (prev_t->frame() + fr_off, _frame_rate) * (double) prev_t->note_type();
}
- const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
- if (diff > -0.1 && diff < 0.1) {
- new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
- / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
- }
-
} else if (prev_t->c_func() > 0.0) {
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
new_bpm = prev_t->tempo_at_frame (prev_t->frame() - frame_contribution, _frame_rate) * (double) prev_t->note_type();
/* prev_to_prev_t is irrelevant */
new_bpm = prev_t->tempo_at_frame (prev_t->frame() - fr_off, _frame_rate) * (double) prev_t->note_type();
}
+ }
- /* limits - a bit clunky, but meh */
- const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
- if (diff > -0.1 && diff < 0.1) {
- new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
- / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
- }
+ /* limits - a bit clunky, but meh */
+ const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
+ if (diff > -1.0 && diff < 1.0) {
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
+ / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
}
prev_t->set_beats_per_minute (new_bpm);
recompute_tempos (future_map);
recompute_meters (future_map);
- if (check_solved (future_map, true)) {
+ if (check_solved (future_map)) {
prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, ms->frame() - 1));
prev_t->set_beats_per_minute (new_bpm);
}
void
-TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame)
-{
+TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
+{
+ /*
+ Ts (future prev_t) Tnext
+ | |
+ | [drag^] |
+ |----------|----------
+ e_f pulse(frame)
+ */
+
Metrics future_map;
- TempoSection* ts = 0;
{
Glib::Threads::RWLock::WriterLock lm (lock);
- ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
-
if (!ts) {
return;
}
prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
}
+ TempoSection* next_t = 0;
+ for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
+ TempoSection* t = 0;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (t->frame() > ts->frame()) {
+ next_t = t;
+ break;
+ }
+ }
+ }
/* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
*/
double contribution = 0.0;
+ double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
- if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
- /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */
- contribution = prev_to_prev_t->beats_per_minute() / (prev_to_prev_t->beats_per_minute() + prev_t->beats_per_minute());
+ if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
}
frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
-
- const double start_tempo = prev_t->tempo_at_frame (frame, _frame_rate);
- const double end_tempo = prev_t->tempo_at_frame (frame + prev_t_frame_contribution, _frame_rate);
- const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
- const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+ double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
double new_bpm;
if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
if (prev_t->position_lock_style() == MusicTime) {
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
- new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
- / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
+
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+ / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
} else {
/* prev to prev is irrelevant */
}
}
} else {
- const double end_minute = (((frame + prev_t_frame_contribution) - prev_t->frame()) / (double) _frame_rate) / 60.0;
- new_bpm = (((start_pulse - prev_t->pulse()) * prev_t->c_func())
- / (exp (end_minute * prev_t->c_func()) - 1)) * (double) prev_t->note_type();
+ double frame_ratio;
+ double pulse_ratio;
+ const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
+ if (prev_to_prev_t) {
+
+ frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
+ pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
+ } else {
+
+ frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+ pulse_ratio = (start_pulse / end_pulse);
+ }
+ new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
}
prev_t->set_beats_per_minute (new_bpm);
recompute_tempos (future_map);
recompute_meters (future_map);
- if (check_solved (future_map, true)) {
-
- prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
- prev_t->set_beats_per_minute (new_bpm);
+ if (check_solved (future_map)) {
+ ts->set_beats_per_minute (new_bpm);
recompute_tempos (_metrics);
recompute_meters (_metrics);
}