#include "ardour/lmath.h"
#include "ardour/tempo.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
#include <locale.h>
using namespace std;
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);
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);
bool
TempoMap::remove_meter_locked (const MeterSection& meter)
{
- Metrics::iterator i;
- for (i = _metrics.begin(); i != _metrics.end(); ++i) {
- TempoSection* t = 0;
- if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
- if (meter.frame() == (*i)->frame()) {
- if (t->locked_to_meter()) {
+ if (meter.position_lock_style() == AudioTime) {
+ /* remove meter-locked tempo */
+ for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
+ TempoSection* t = 0;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (t->locked_to_meter() && meter.frame() == (*i)->frame()) {
delete (*i);
_metrics.erase (i);
break;
}
}
- for (i = _metrics.begin(); i != _metrics.end(); ++i) {
+ for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
if (dynamic_cast<MeterSection*> (*i) != 0) {
if (meter.frame() == (*i)->frame()) {
if ((*i)->movable()) {
{
TempoSection* t = new TempoSection (pulse, frame, tempo.beats_per_minute(), tempo.note_type(), type, pls);
t->set_locked_to_meter (locked_to_meter);
+ bool solved = false;
do_insert (t);
if (recompute) {
if (pls == AudioTime) {
- solve_map_frame (_metrics, t, t->frame());
+ solved = solve_map_frame (_metrics, t, t->frame());
} else {
- solve_map_pulse (_metrics, t, t->pulse());
+ solved = solve_map_pulse (_metrics, t, t->pulse());
}
recompute_meters (_metrics);
}
+ if (!solved && recompute) {
+ warning << "Adding tempo may have left the tempo map unsolved." << endmsg;
+ recompute_map (_metrics);
+ }
+
return t;
}
}
MeterSection*
-TempoMap::add_meter_locked (const Meter& meter, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
+TempoMap::add_meter_locked (const Meter& meter, double beat, const BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
{
const MeterSection& prev_m = meter_section_at_frame_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();
+ TempoSection* mlt = 0;
if (pls == AudioTime) {
/* add meter-locked tempo */
- add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse, frame, TempoSection::Ramp, AudioTime, true, true);
+ mlt = add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse, frame, TempoSection::Ramp, AudioTime, true, true);
+
+ if (!mlt) {
+ return 0;
+ }
+
}
MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
+ bool solved = false;
do_insert (new_meter);
if (recompute) {
if (pls == AudioTime) {
- solve_map_frame (_metrics, new_meter, frame);
+ solved = solve_map_frame (_metrics, new_meter, frame);
} else {
- solve_map_bbt (_metrics, new_meter, where);
+ solved = solve_map_bbt (_metrics, new_meter, where);
+ /* required due to resetting the pulse of meter-locked tempi above.
+ Arguably solve_map_bbt() should use solve_map_pulse (_metrics, TempoSection) instead,
+ but afaict this cannot cause the map to be left unsolved (these tempi are all audio locked).
+ */
+ recompute_map (_metrics);
}
}
+ if (!solved && recompute) {
+ /* if this has failed to solve, there is little we can do other than to ensure that
+ the new map is recalculated.
+ */
+ warning << "Adding meter may have left the tempo map unsolved." << endmsg;
+ recompute_map (_metrics);
+ }
+
return new_meter;
}
return *t;
}
void
-TempoMap::recompute_tempos (Metrics& metrics)
+TempoMap::recompute_tempi (Metrics& metrics)
{
TempoSection* prev_t = 0;
return;
}
- recompute_tempos (metrics);
+ recompute_tempi (metrics);
recompute_meters (metrics);
}
m = static_cast<MeterSection*> (*i);
if (prev_m && m->position_lock_style() == AudioTime) {
const TempoSection* t = &tempo_section_at_frame_locked (metrics, m->frame() - 1);
- const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
- const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
-
- if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
+ const framepos_t nascent_m_frame = t->frame_at_pulse (m->pulse(), _frame_rate);
+ /* Here we check that a preceding section of music doesn't overlap a subsequent one.
+ It is complicated by the fact that audio locked meters represent a discontinuity in the pulse
+ (they place an exact pulse at a particular time expressed only in frames).
+ This has the effect of shifting the calculated frame at the meter pulse (wrt the previous section of music)
+ away from its actual frame (which is now the frame location of the exact pulse).
+ This can result in the calculated frame (from the previous musical section)
+ differing from the exact frame by one sample.
+ Allow for that.
+ */
+ if (t && (nascent_m_frame > m->frame() + 1 || nascent_m_frame < 0)) {
return false;
}
}
}
#if (0)
- recompute_tempos (imaginary);
+ recompute_tempi (imaginary);
if (check_solved (imaginary)) {
return true;
MetricSectionFrameSorter fcmp;
imaginary.sort (fcmp);
- recompute_tempos (imaginary);
+ recompute_tempi (imaginary);
if (check_solved (imaginary)) {
return true;
}
#if (0)
- recompute_tempos (imaginary);
+ recompute_tempi (imaginary);
if (check_solved (imaginary)) {
return true;
MetricSectionSorter cmp;
imaginary.sort (cmp);
- recompute_tempos (imaginary);
+ recompute_tempi (imaginary);
/* Reordering
* XX need a restriction here, but only for this case,
* as audio locked tempos don't interact in the same way.
for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
TempoSection* t;
- if ((*i)->is_tempo()) {
+ if ((*ii)->is_tempo()) {
t = static_cast<TempoSection*> (*ii);
if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
meter_locked_tempo = t;
if (solve_map_frame (future_map, copy, frame)) {
solve_map_frame (_metrics, ms, frame);
- recompute_tempos (_metrics);
+ recompute_tempi (_metrics);
}
}
} else {
if (solve_map_bbt (future_map, copy, bbt)) {
solve_map_bbt (_metrics, ms, bbt);
- recompute_tempos (_metrics);
+ recompute_tempi (_metrics);
}
}
}
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
- recompute_tempos (future_map);
+ recompute_tempi (future_map);
if (check_solved (future_map)) {
ts->set_beats_per_minute (bpm.beats_per_minute());
}
new_bpm = min (new_bpm, (double) 1000.0);
prev_t->set_beats_per_minute (new_bpm);
- recompute_tempos (future_map);
+ recompute_tempi (future_map);
recompute_meters (future_map);
if (check_solved (future_map)) {
ts->set_beats_per_minute (new_bpm);
- recompute_tempos (_metrics);
+ recompute_tempi (_metrics);
recompute_meters (_metrics);
}
}
}
double
-TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t& sub_num)
+TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
}
double
-TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t& sub_num)
+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) {
catch (failed_constructor& err){
error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
_metrics = old_metrics;
+ old_metrics.clear();
break;
}
catch (failed_constructor& err) {
error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
_metrics = old_metrics;
+ old_metrics.clear();
break;
}
}
}
recompute_map (_metrics);
+
+ Metrics::const_iterator d = old_metrics.begin();
+ while (d != old_metrics.end()) {
+ delete (*d);
+ ++d;
+ }
+ old_metrics.clear ();
}
PropertyChanged (PropertyChange ());