+int
+TempoMap::n_tempos() const
+{
+ Glib::RWLock::ReaderLock lm (lock);
+ int cnt = 0;
+
+ for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
+ if (dynamic_cast<const TempoSection*>(*i) != 0) {
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+int
+TempoMap::n_meters() const
+{
+ Glib::RWLock::ReaderLock lm (lock);
+ int cnt = 0;
+
+ for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
+ if (dynamic_cast<const MeterSection*>(*i) != 0) {
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+void
+TempoMap::insert_time (nframes64_t where, nframes64_t amount)
+{
+ for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
+ if ((*i)->frame() >= where) {
+ (*i)->set_frame ((*i)->frame() + amount);
+ }
+ }
+
+ timestamp_metrics (false);
+
+ PropertyChanged (PropertyChange ());
+}
+
+BBT_Time
+TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
+{
+ TempoMetric metric = metric_at (start);
+ return bbt_add (start, other, metric);
+}
+
+/**
+ * add the BBT interval @param increment to @param start and return the result
+ */
+BBT_Time
+TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
+{
+ BBT_Time result = start;
+ BBT_Time op = increment; /* argument is const, but we need to modify it */
+ uint32_t ticks = result.ticks + op.ticks;
+
+ if (ticks >= Meter::ticks_per_beat) {
+ op.beats++;
+ result.ticks = ticks % (uint32_t) Meter::ticks_per_beat;
+ } else {
+ result.ticks += op.ticks;
+ }
+
+ /* now comes the complicated part. we have to add one beat a time,
+ checking for a new metric on every beat.
+ */
+
+ /* grab all meter sections */
+
+ list<const MeterSection*> meter_sections;
+
+ for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
+ const MeterSection* ms;
+ if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
+ meter_sections.push_back (ms);
+ }
+ }
+
+ assert (!meter_sections.empty());
+
+ list<const MeterSection*>::const_iterator next_meter;
+ const Meter* meter = 0;
+
+ /* go forwards through the meter sections till we get to the one
+ covering the current value of result. this positions i to point to
+ the next meter section too, or the end.
+ */
+
+ for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
+
+ if (result < (*next_meter)->start()) {
+ /* this metric is past the result time. stop looking, we have what we need */
+ break;
+ }
+
+ if (result == (*next_meter)->start()) {
+ /* this meter section starts at result, push i beyond it so that it points
+ to the NEXT section, opwise we will get stuck later, and use this meter section.
+ */
+ meter = *next_meter;
+ ++next_meter;
+ break;
+ }
+
+ meter = *next_meter;
+ }
+
+ assert (meter != 0);
+
+ /* OK, now have the meter for the bar start we are on, and i is an iterator
+ that points to the metric after the one we are currently dealing with
+ (or to metrics->end(), of course)
+ */
+
+ while (op.beats) {
+
+ /* given the current meter, have we gone past the end of the bar ? */
+
+ if (result.beats >= meter->beats_per_bar()) {
+ /* move to next bar, first beat */
+ result.bars++;
+ result.beats = 1;
+ } else {
+ result.beats++;
+ }
+
+ /* one down ... */
+
+ op.beats--;
+
+ /* check if we need to use a new meter section: has adding beats to result taken us
+ to or after the start of the next meter section? in which case, use it.
+ */
+
+ if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
+ meter = *next_meter;
+ ++next_meter;
+ }
+ }
+
+ /* finally, add bars */
+
+ result.bars += op.bars++;
+
+ return result;
+}
+
+/**
+ * subtract the BBT interval @param decrement from @param start and return the result
+ */
+BBT_Time
+TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
+{
+ BBT_Time result = start;
+ BBT_Time op = decrement; /* argument is const, but we need to modify it */
+
+ if (op.ticks > result.ticks) {
+ /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
+ op.beats++;
+ result.ticks = Meter::ticks_per_beat - (op.ticks - result.ticks);
+ } else {
+ result.ticks -= op.ticks;
+ }
+
+ /* now comes the complicated part. we have to subtract one beat a time,
+ checking for a new metric on every beat.
+ */
+
+ /* grab all meter sections */
+
+ list<const MeterSection*> meter_sections;
+
+ for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
+ const MeterSection* ms;
+ if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
+ meter_sections.push_back (ms);
+ }
+ }
+
+ assert (!meter_sections.empty());
+
+ /* go backwards through the meter sections till we get to the one
+ covering the current value of result. this positions i to point to
+ the next (previous) meter section too, or the end.
+ */
+
+ const MeterSection* meter = 0;
+ list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
+ // support const_reverse_iterator::operator!=()
+
+ for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
+
+ /* when we find the first meter section that is before or at result, use it,
+ and set next_meter to the previous one
+ */
+
+ if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
+ meter = *next_meter;
+ ++next_meter;
+ break;
+ }
+ }
+
+ assert (meter != 0);
+
+ /* OK, now have the meter for the bar start we are on, and i is an iterator
+ that points to the metric after the one we are currently dealing with
+ (or to metrics->end(), of course)
+ */
+
+ while (op.beats) {
+
+ /* have we reached the start of the bar? if so, move to the last beat of the previous
+ bar. opwise, just step back 1 beat.
+ */
+
+ if (result.beats == 1) {
+
+ /* move to previous bar, last beat */
+
+ if (result.bars <= 1) {
+ /* i'm sorry dave, i can't do that */
+ throw std::out_of_range ("illegal BBT subtraction");
+ }
+
+ result.bars--;
+ result.beats = meter->beats_per_bar();
+ } else {
+
+ /* back one beat */
+
+ result.beats--;
+ }
+
+ /* one down ... */
+ op.beats--;
+
+ /* check if we need to use a new meter section: has subtracting beats to result taken us
+ to before the start of the current meter section? in which case, use the prior one.
+ */
+
+ if (result < meter->start() && next_meter != meter_sections.rend()) {
+ meter = *next_meter;
+ ++next_meter;
+ }
+ }
+
+ /* finally, subtract bars */
+
+ if (op.bars >= result.bars) {
+ /* i'm sorry dave, i can't do that */
+ throw std::out_of_range ("illegal BBT subtraction");
+ }
+
+ result.bars -= op.bars;
+ return result;
+}
+
+/** Compare the time of this with that of another MetricSection.
+ * @param with_bbt True to compare using ::start(), false to use ::frame().
+ * @return -1 for less than, 0 for equal, 1 for greater than.
+ */
+
+int
+MetricSection::compare (MetricSection* other, bool with_bbt) const
+{
+ if (with_bbt) {
+ if (start() == other->start()) {
+ return 0;
+ } else if (start() < other->start()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } else {
+ if (frame() == other->frame()) {
+ return 0;
+ } else if (frame() < other->frame()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ /* NOTREACHED */
+ return 0;
+}