#include <algorithm>
#include <stdexcept>
+#include <cmath>
#include <unistd.h>
-#include <cmath>
-
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include "pbd/xml++.h"
#include "evoral/types.hpp"
#include "ardour/debug.h"
#include "ardour/tempo.h"
-#include "ardour/utils.h"
#include "i18n.h"
#include <locale.h>
Meter TempoMap::_default_meter (4.0, 4.0);
Tempo TempoMap::_default_tempo (120.0);
-double
-Tempo::frames_per_beat (framecnt_t sr) const
-{
- return (60.0 * sr) / _beats_per_minute;
-}
-
/***********************************************************************/
double
bool removed = false;
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics.begin(); i != metrics.end(); ++i) {
bool removed = false;
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics.begin(); i != metrics.end(); ++i) {
add_tempo (tempo, where);
} else {
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* cannot move the first tempo section */
*((Tempo*)&first) = tempo;
recompute_map (false);
TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* new tempos always start on a beat */
where.ticks = 0;
add_meter (meter, where);
} else {
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* cannot move the first meter section */
*((Meter*)&first) = meter;
recompute_map (true);
TempoMap::add_meter (const Meter& meter, BBT_Time where)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* a new meter always starts a new bar on the first beat. so
round the start time appropriately. remember that
for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
*((Tempo*) t) = newtempo;
recompute_map (false);
}
/* reset */
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* cannot move the first tempo section */
*((Tempo*)prev) = newtempo;
recompute_map (false);
void
TempoMap::require_map_to (framepos_t pos)
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
if (_map.empty() || _map.back().frame < pos) {
extend_map (pos);
void
TempoMap::require_map_to (const BBT_Time& bbt)
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
/* since we have no idea where BBT is if its off the map, see the last
* point in the map is past BBT, and if not add an arbitrary amount of
TempoSection* ts;
MeterSection* ms;
double beat_frames;
+ double current_frame_exact;
framepos_t bar_start_frame;
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Extend map to %1 from %2 = %3\n", end, current, current_frame));
}
beat_frames = meter->frames_per_grid (*tempo,_frame_rate);
+ current_frame_exact = current_frame;
while (current_frame < end) {
current.beats++;
- current_frame += beat_frames;
+ current_frame_exact += beat_frames;
+ current_frame = llrint(current_frame_exact);
if (current.beats > meter->divisions_per_bar()) {
current.bars++;
if (!(current < (*next_metric)->start())) {
- set_metrics:
+ set_metrics:
if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
tempo = ts;
double next_beat_frames = tempo->frames_per_beat (_frame_rate);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
- tempo->start(), current_frame, tempo->bar_offset()));
+ tempo->start(), current_frame, tempo->bar_offset()));
/* back up to previous beat */
- current_frame -= beat_frames;
+ current_frame_exact -= beat_frames;
+ current_frame = llrint(current_frame_exact);
/* set tempo section location
* based on offset from last
* bar start
*/
tempo->set_frame (bar_start_frame +
- llrint ((ts->bar_offset() * meter->divisions_per_bar() * beat_frames)));
+ llrint ((ts->bar_offset() * meter->divisions_per_bar() * beat_frames)));
/* advance to the location of
* the new (adjusted) beat. do
double offset_within_old_beat = (tempo->frame() - current_frame) / beat_frames;
- current_frame += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+ current_frame_exact += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+ current_frame = llrint(current_frame_exact);
/* next metric doesn't have to
* match this precisely to
} else {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into beat-aligned tempo metric at %1 = %2\n",
- tempo->start(), current_frame));
+ tempo->start(), current_frame));
tempo->set_frame (current_frame);
}
*/
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into meter section at %1 vs %2 (%3)\n",
- meter->start(), current, current_frame));
+ meter->start(), current, current_frame));
assert (current.beats == 1);
beat_frames = meter->frames_per_grid (*tempo, _frame_rate);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 dpb %2 meter %3 tempo %4\n",
- beat_frames, meter->divisions_per_bar(), *((Meter*)meter), *((Tempo*)tempo)));
+ beat_frames, meter->divisions_per_bar(), *((Meter*)meter), *((Tempo*)tempo)));
++next_metric;
if (next_metric != metrics.end() && ((*next_metric)->start() == current)) {
/* same position so go back and set this one up before advancing
- */
+ */
goto set_metrics;
}
+
}
}
if (current.beats == 1) {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
- _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
+ _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, 1));
bar_start_frame = current_frame;
} else {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
- _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
+ _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, current.beats));
}
if (next_metric == metrics.end()) {
/* no more metrics - we've timestamped them all, stop here */
if (end == max_framepos) {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stop extending map now that we've reach the end @ %1|%2 = %3\n",
- current.bars, current.beats, current_frame));
+ current.bars, current.beats, current_frame));
break;
}
}
}
TempoMetric
-TempoMap::metric_at (framepos_t frame) const
+TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
TempoMetric m (first_meter(), first_tempo());
- const Meter* meter;
- const Tempo* tempo;
/* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
at something, because we insert the default tempo and meter during
break;
}
- if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
- m.set_tempo (*tempo);
- } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
- m.set_meter (*meter);
- }
+ m.set_metric(*i);
- m.set_frame ((*i)->frame ());
- m.set_start ((*i)->start ());
+ if (last) {
+ *last = i;
+ }
}
return m;
TempoMetric
TempoMap::metric_at (BBT_Time bbt) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
TempoMetric m (first_meter(), first_tempo());
- const Meter* meter;
- const Tempo* tempo;
/* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
at something, because we insert the default tempo and meter during
break;
}
- if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
- m.set_tempo (*tempo);
- } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
- m.set_meter (*meter);
- }
-
- m.set_frame ((*i)->frame ());
- m.set_start (section_start);
+ m.set_metric (*i);
}
return m;
{
require_map_to (frame);
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
if (frame < 0) {
bbt.bars = 1;
void
TempoMap::bbt_time_rt (framepos_t frame, BBT_Time& bbt)
{
- Glib::RWLock::ReaderLock lm (lock, Glib::TRY_LOCK);
+ 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");
bbt.ticks = 0;
} else {
bbt.ticks = llrint (((frame - (*i).frame) / (*i).tempo->frames_per_beat(_frame_rate)) *
- BBT_Time::ticks_per_beat);
+ BBT_Time::ticks_per_beat);
}
}
require_map_to (bbt);
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
BBTPointList::const_iterator s = bbt_before_or_at (BBT_Time (1, 1, 0));
BBTPointList::const_iterator e = bbt_before_or_at (BBT_Time (bbt.bars, bbt.beats, 0));
BBT_Time when;
bbt_time (pos, when);
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
return bbt_duration_at_unlocked (when, bbt, dir);
}
framecnt_t
-TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir)
+TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int /*dir*/)
{
if (bbt.bars == 0 && bbt.beats == 0 && bbt.ticks == 0) {
return 0;
/* round back to the previous precise beat */
BBTPointList::const_iterator wi = bbt_before_or_at (BBT_Time (when.bars, when.beats, 0));
BBTPointList::const_iterator start (wi);
- double tick_frames = 0;
assert (wi != _map.end());
- /* compute how much rounding we did because of non-zero ticks */
-
- if (when.ticks != 0) {
- tick_frames = (*wi).tempo->frames_per_beat (_frame_rate) * (when.ticks/BBT_Time::ticks_per_beat);
- }
-
uint32_t bars = 0;
uint32_t beats = 0;
/* add any additional frames related to ticks in the added value */
if (bbt.ticks != 0) {
- tick_frames += (*wi).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat);
+ return ((*wi).frame - (*start).frame) +
+ (*wi).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat);
+ } else {
+ return ((*wi).frame - (*start).frame);
}
-
- return ((*wi).frame - (*start).frame) + llrint (tick_frames);
}
framepos_t
{
require_map_to (fr);
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
BBTPointList::const_iterator i = bbt_before_or_at (fr);
BBT_Time the_beat;
uint32_t ticks_one_subdivisions_worth;
{
require_map_to (frame);
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
BBTPointList::const_iterator fi;
if (dir > 0) {
framepos_t lower, framepos_t upper)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
if (_map.empty() || (_map.back().frame < upper)) {
recompute_map (false, upper);
}
const TempoSection&
TempoMap::tempo_section_at (framepos_t frame) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
Metrics::const_iterator i;
TempoSection* prev = 0;
XMLNode *root = new XMLNode ("TempoMap");
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
for (i = metrics.begin(); i != metrics.end(); ++i) {
root->add_child_nocopy ((*i)->get_state());
}
TempoMap::set_state (const XMLNode& node, int /*version*/)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
XMLNodeList nlist;
XMLNodeConstIterator niter;
metrics.sort (cmp);
}
+ /* check for multiple tempo/meters at the same location, which
+ ardour2 somehow allowed.
+ */
+
+ Metrics::iterator prev = metrics.end();
+ for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
+ if (prev != metrics.end()) {
+ if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
+ if ((*prev)->start() == (*i)->start()) {
+ error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
+ return -1;
+ }
+ } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
+ if ((*prev)->start() == (*i)->start()) {
+ error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
+ return -1;
+ }
+ }
+ }
+ prev = i;
+ }
+
recompute_map (true, -1);
}
void
TempoMap::dump (std::ostream& o) const
{
- Glib::RWLock::ReaderLock lm (lock, Glib::TRY_LOCK);
+ Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
const MeterSection* m;
const TempoSection* t;
int
TempoMap::n_tempos() const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
int
TempoMap::n_meters() const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
TempoMap::insert_time (framepos_t where, framecnt_t amount)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::Threads::RWLock::WriterLock lm (lock);
for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
if ((*i)->frame() >= where && (*i)->movable ()) {
(*i)->set_frame ((*i)->frame() + amount);
framepos_t
TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
Metrics::const_iterator next_tempo;
const TempoSection* tempo = 0;
next_tempo -> first tempo after "pos", possibly metrics.end()
*/
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 plus %2 beats, start with tempo = %3 @ %4\n",
- pos, beats, *((Tempo*)tempo), tempo->frame()));
+ DEBUG_TRACE (DEBUG::TempoMath,
+ string_compose ("frame %1 plus %2 beats, start with tempo = %3 @ %4\n",
+ pos, beats, *((const Tempo*)tempo), tempo->frame()));
while (beats) {
tempo = dynamic_cast<const TempoSection*>(*next_tempo);
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
- *((Tempo*)tempo), tempo->frame(),
+ *((const Tempo*)tempo), tempo->frame(),
tempo->frames_per_beat (_frame_rate)));
while (next_tempo != metrics.end ()) {
framepos_t
TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
Metrics::const_reverse_iterator prev_tempo;
const TempoSection* tempo = 0;
}
}
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 minus %2 beats, start with tempo = %3 @ %4 prev at beg? %5\n",
- pos, beats, *((Tempo*)tempo), tempo->frame(),
- prev_tempo == metrics.rend()));
+ DEBUG_TRACE (DEBUG::TempoMath,
+ string_compose ("frame %1 minus %2 beats, start with tempo = %3 @ %4 prev at beg? %5\n",
+ pos, beats, *((const Tempo*)tempo), tempo->frame(),
+ prev_tempo == metrics.rend()));
/* We now have:
tempo = dynamic_cast<const TempoSection*>(*prev_tempo);
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
- *((Tempo*)tempo), tempo->frame(),
- tempo->frames_per_beat (_frame_rate)));
+ DEBUG_TRACE (DEBUG::TempoMath,
+ string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
+ *((const Tempo*)tempo), tempo->frame(),
+ tempo->frames_per_beat (_frame_rate)));
while (prev_tempo != metrics.rend ()) {
framepos_t
TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
Metrics::const_iterator i;
const MeterSection* meter;
const MeterSection* m;
Evoral::MusicalTime
TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock);
Metrics::const_iterator next_tempo;
const TempoSection* tempo = 0;
framepos_t effective_pos = max (pos, (framepos_t) 0);
assert (tempo);
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
- pos, distance, *((Tempo*)tempo), tempo->frame()));
+ DEBUG_TRACE (DEBUG::TempoMath,
+ string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
+ pos, distance, *((const Tempo*)tempo), tempo->frame()));
Evoral::MusicalTime beats = 0;
tempo = dynamic_cast<const TempoSection*>(*next_tempo);
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
- *((Tempo*)tempo), tempo->frame(),
- tempo->frames_per_beat (_frame_rate)));
+ DEBUG_TRACE (DEBUG::TempoMath,
+ string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
+ *((const Tempo*)tempo), tempo->frame(),
+ tempo->frames_per_beat (_frame_rate)));
while (next_tempo != metrics.end ()) {
const MeterSection* ms;
if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
- o << *((Tempo*) ts);
+ o << *((const Tempo*) ts);
} else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
- o << *((Meter*) ms);
+ o << *((const Meter*) ms);
}
return o;