26 #include <glibmm/threads.h>
29 #include "ardour/debug.h"
40 using Timecode::BBT_Time;
44 Meter TempoMap::_default_meter (4.0, 4.0);
45 Tempo TempoMap::_default_tempo (120.0);
65 return frames_per_grid (tempo, sr) * _divisions_per_bar;
70 const string TempoSection::xml_state_node_name =
"Tempo";
72 TempoSection::TempoSection (
const XMLNode& node)
79 if ((prop = node.
property (
"start")) == 0) {
80 error <<
_(
"TempoSection XML node has no \"start\" property") <<
endmsg;
84 if (sscanf (prop->
value().c_str(),
"%" PRIu32
"|%" PRIu32
"|%" PRIu32,
88 error <<
_(
"TempoSection XML node has an illegal \"start\" value") <<
endmsg;
94 if ((prop = node.
property (
"beats-per-minute")) == 0) {
95 error <<
_(
"TempoSection XML node has no \"beats-per-minute\" property") <<
endmsg;
100 error <<
_(
"TempoSection XML node has an illegal \"beats_per_minute\" value") <<
endmsg;
104 if ((prop = node.
property (
"note-type")) == 0) {
109 error <<
_(
"TempoSection XML node has an illegal \"note-type\" value") <<
endmsg;
114 if ((prop = node.
property (
"movable")) == 0) {
115 error <<
_(
"TempoSection XML node has no \"movable\" property") <<
endmsg;
121 if ((prop = node.
property (
"bar-offset")) == 0) {
125 error <<
_(
"TempoSection XML node has an illegal \"bar-offset\" value") <<
endmsg;
138 snprintf (buf,
sizeof (buf),
"%" PRIu32
"|%" PRIu32
"|%" PRIu32,
145 snprintf (buf,
sizeof (buf),
"%f",
_note_type);
149 snprintf (buf,
sizeof (buf),
"%s",
movable()?
"yes":
"no");
175 new_start.bars =
start().bars;
178 new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
182 new_start.beats += 1;
201 if ((prop = node.
property (
"start")) == 0) {
202 error <<
_(
"MeterSection XML node has no \"start\" property") <<
endmsg;
206 if (sscanf (prop->
value().c_str(),
"%" PRIu32
"|%" PRIu32
"|%" PRIu32,
210 error <<
_(
"MeterSection XML node has an illegal \"start\" value") <<
endmsg;
218 if ((prop = node.
property (
"divisions-per-bar")) == 0) {
219 if ((prop = node.
property (
"beats-per-bar")) == 0) {
220 error <<
_(
"MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") <<
endmsg;
226 error <<
_(
"MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") <<
endmsg;
230 if ((prop = node.
property (
"note-type")) == 0) {
231 error <<
_(
"MeterSection XML node has no \"note-type\" property") <<
endmsg;
236 error <<
_(
"MeterSection XML node has an illegal \"note-type\" value") <<
endmsg;
240 if ((prop = node.
property (
"movable")) == 0) {
241 error <<
_(
"MeterSection XML node has no \"movable\" property") <<
endmsg;
255 snprintf (buf,
sizeof (buf),
"%" PRIu32
"|%" PRIu32
"|%" PRIu32,
260 snprintf (buf,
sizeof (buf),
"%f",
_note_type);
264 snprintf (buf,
sizeof (buf),
"%s",
movable()?
"yes":
"no");
291 m->set_movable (
false);
306 bool removed =
false;
309 Glib::Threads::RWLock::WriterLock lm (
lock);
311 if (complete_operation) {
317 if (removed && complete_operation) {
328 if (dynamic_cast<TempoSection*> (*i) != 0) {
329 if (tempo.
frame() == (*i)->frame()) {
330 if ((*i)->movable()) {
344 bool removed =
false;
347 Glib::Threads::RWLock::WriterLock lm (
lock);
349 if (complete_operation) {
355 if (removed && complete_operation) {
366 if (dynamic_cast<MeterSection*> (*i) != 0) {
367 if (tempo.
frame() == (*i)->frame()) {
368 if ((*i)->movable()) {
382 bool need_add =
true;
384 assert (section->
start().ticks == 0);
390 if (dynamic_cast<MeterSection*>(section)) {
396 if ((section->
start().beats != 1) || (section->
start().ticks != 0)) {
398 BBT_Time corrected = section->
start();
402 warning <<
string_compose (
_(
"Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
418 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
420 bool const iter_is_tempo =
dynamic_cast<TempoSection*
> (*i) != 0;
421 bool const insert_is_tempo =
dynamic_cast<TempoSection*
> (section) != 0;
423 if (iter_is_tempo && insert_is_tempo) {
427 if ((*i)->start().bars == section->
start().bars &&
428 (*i)->start().beats == section->
start().beats) {
430 if (!(*i)->movable()) {
437 *(
dynamic_cast<Tempo*
>(*i)) = *(dynamic_cast<Tempo*>(section));
445 }
else if (!iter_is_tempo && !insert_is_tempo) {
449 if ((*i)->start().bars == section->
start().bars) {
451 if (!(*i)->movable()) {
458 *(
dynamic_cast<Meter*
>(*i)) = *(dynamic_cast<Meter*>(section));
481 if ((*i)->start() > section->
start()) {
494 Glib::Threads::RWLock::WriterLock lm (
lock);
503 *
static_cast<Tempo*
>(&first) = tempo;
516 Glib::Threads::RWLock::WriterLock lm (
lock);
545 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
549 if (where < (*i)->start()) {
553 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
573 Glib::Threads::RWLock::WriterLock lm (
lock);
581 *
static_cast<Meter*
>(&first) = meter;
593 Glib::Threads::RWLock::WriterLock lm (
lock);
617 if (where.beats != 1) {
636 Tempo newtempo (beats_per_minute, note_type);
639 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
640 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
642 Glib::Threads::RWLock::WriterLock lm (
lock);
643 *((
Tempo*) t) = newtempo;
655 Tempo newtempo (beats_per_minute, note_type);
664 for (first = 0, i =
metrics.begin(), prev = 0; i !=
metrics.end(); ++i) {
666 if ((*i)->frame() > where) {
672 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
692 Glib::Threads::RWLock::WriterLock lm (
lock);
694 *((
Tempo*)prev) = newtempo;
706 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
707 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
712 fatal <<
_(
"programming error: no tempo section in tempo map!") <<
endmsg;
724 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
725 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
730 fatal <<
_(
"programming error: no tempo section in tempo map!") <<
endmsg;
742 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
743 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
748 fatal <<
_(
"programming error: no tempo section in tempo map!") <<
endmsg;
758 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
759 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
764 fatal <<
_(
"programming error: no tempo section in tempo map!") <<
endmsg;
772 Glib::Threads::RWLock::WriterLock lm (
lock);
774 if (
_map.empty() ||
_map.back().frame < pos) {
782 Glib::Threads::RWLock::WriterLock lm (
lock);
789 int additional_minutes = 1;
792 if (!
_map.empty() &&
_map.back().bar >= (bbt.bars + 1)) {
797 additional_minutes *= 2;
808 double current_frame;
810 Metrics::iterator next_metric;
820 if (!
_map.empty ()) {
822 end = max (end,
_map.back().frame);
828 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
831 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
839 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
842 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
860 if (reassign_tempo_bbt) {
866 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
871 if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
879 }
else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
882 fatal <<
_(
"programming error: unhandled MetricSection type") <<
endmsg;
905 _extend_map (tempo, meter, next_metric, current, current_frame, end);
918 BBTPointList::const_iterator i =
_map.end();
919 Metrics::iterator next_metric;
923 BBT_Time last_metric_start;
925 if ((*i).tempo->frame() > (*i).meter->frame()) {
926 last_metric_start = (*i).tempo->start();
928 last_metric_start = (*i).meter->start();
935 for (next_metric =
metrics.begin(); next_metric !=
metrics.end(); ++next_metric) {
936 if ((*next_metric)->start() > last_metric_start) {
945 _extend_map (const_cast<TempoSection*> ((*i).tempo),
946 const_cast<MeterSection*> ((*i).meter),
947 next_metric, BBT_Time ((*i).bar, (*i).beat, 0), (*i).frame, end);
952 Metrics::iterator next_metric,
960 double current_frame_exact;
965 if (current.beats == 1) {
966 bar_start_frame = current_frame;
972 current_frame_exact = current_frame;
974 while (current_frame < end) {
977 current_frame_exact += beat_frames;
978 current_frame = llrint(current_frame_exact);
985 if (next_metric !=
metrics.end()) {
991 if (!(current < (*next_metric)->start())) {
994 if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
1013 if (tempo->
start().ticks != 0) {
1021 current_frame_exact -= beat_frames;
1022 current_frame = llrint(current_frame_exact);
1041 double offset_within_old_beat = (tempo->
frame() - current_frame) / beat_frames;
1043 current_frame_exact += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
1044 current_frame = llrint(current_frame_exact);
1055 tempo->
start(), current_frame));
1059 }
else if ((ms = dynamic_cast<MeterSection*>(*next_metric)) != 0) {
1068 meter->
start(), current, current_frame));
1070 assert (current.beats == 1);
1082 if (next_metric !=
metrics.end() && ((*next_metric)->start() == current)) {
1091 if (current.beats == 1) {
1093 _map.push_back (
BBTPoint (*meter, *tempo, current_frame, current.bars, 1));
1094 bar_start_frame = current_frame;
1097 _map.push_back (
BBTPoint (*meter, *tempo, current_frame, current.bars, current.beats));
1100 if (next_metric ==
metrics.end()) {
1104 current.bars, current.beats, current_frame));
1114 Glib::Threads::RWLock::ReaderLock lm (
lock);
1124 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1126 if ((*i)->frame() > frame) {
1143 Glib::Threads::RWLock::ReaderLock lm (
lock);
1153 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1155 BBT_Time section_start ((*i)->start());
1157 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1172 Glib::Threads::RWLock::ReaderLock lm (
lock);
1188 Glib::Threads::RWLock::ReaderLock lm (
lock, Glib::Threads::TRY_LOCK);
1191 throw std::logic_error (
"TempoMap::bbt_time_rt() could not lock tempo map");
1194 if (
_map.empty() ||
_map.back().frame < frame) {
1195 throw std::logic_error (
string_compose (
"map not long enough to reach %1", frame));
1206 bbt.bars = (*i).bar;
1207 bbt.beats = (*i).beat;
1209 if ((*i).frame == frame) {
1212 bbt.ticks = llrint (((frame - (*i).frame) / (*i).tempo->frames_per_beat(
_frame_rate)) *
1213 BBT_Time::ticks_per_beat);
1225 if (bbt.beats < 1) {
1226 throw std::logic_error (
"beats are counted from one");
1231 Glib::Threads::RWLock::ReaderLock lm (
lock);
1234 BBTPointList::const_iterator e =
bbt_before_or_at (BBT_Time (bbt.bars, bbt.beats, 0));
1236 if (bbt.ticks != 0) {
1237 return ((*e).frame - (*s).frame) +
1238 llrint ((*e).tempo->frames_per_beat (
_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat));
1240 return ((*e).frame - (*s).frame);
1250 Glib::Threads::RWLock::ReaderLock lm (
lock);
1257 if (bbt.bars == 0 && bbt.beats == 0 && bbt.ticks == 0) {
1262 BBTPointList::const_iterator wi =
bbt_before_or_at (BBT_Time (when.bars, when.beats, 0));
1263 BBTPointList::const_iterator
start (wi);
1265 assert (wi !=
_map.end());
1270 while (wi !=
_map.end() && bars < bbt.bars) {
1272 if ((*wi).is_bar()) {
1276 assert (wi !=
_map.end());
1278 while (wi !=
_map.end() && beats < bbt.beats) {
1282 assert (wi !=
_map.end());
1286 if (bbt.ticks != 0) {
1287 return ((*wi).frame - (*start).frame) +
1288 (*wi).tempo->frames_per_beat (
_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat);
1290 return ((*wi).frame - (*start).frame);
1311 Glib::Threads::RWLock::ReaderLock lm (
lock);
1314 uint32_t ticks_one_subdivisions_worth;
1319 fr, sub_num, (*i).frame, (*i).bar, (*i).beat, the_beat));
1321 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1327 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1332 }
else if (mod == 0) {
1334 the_beat.ticks += ticks_one_subdivisions_worth;
1339 the_beat.ticks += ticks_one_subdivisions_worth - mod;
1342 if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1343 assert (i !=
_map.end());
1345 assert (i !=
_map.end());
1346 the_beat.ticks -= BBT_Time::ticks_per_beat;
1350 }
else if (dir < 0) {
1354 uint32_t difference = the_beat.ticks % ticks_one_subdivisions_worth;
1359 difference = ticks_one_subdivisions_worth;
1362 if (the_beat.ticks < difference) {
1363 if (i ==
_map.begin()) {
1368 the_beat.ticks = BBT_Time::ticks_per_beat - the_beat.ticks;
1370 the_beat.ticks -= difference;
1380 if ((rem = fmod ((
double) the_beat.ticks, (
double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1384 the_beat.ticks = lrint (the_beat.ticks + (ticks_one_subdivisions_worth - rem));
1388 if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1389 assert (i !=
_map.end());
1391 assert (i !=
_map.end());
1392 the_beat.ticks -= BBT_Time::ticks_per_beat;
1396 }
else if (rem > 0) {
1400 if (rem > the_beat.ticks) {
1401 if (i ==
_map.begin()) {
1407 the_beat.ticks = lrint (BBT_Time::ticks_per_beat - rem);
1410 the_beat.ticks = lrint (the_beat.ticks - rem);
1418 return (*i).frame + (the_beat.ticks/BBT_Time::ticks_per_beat) *
1427 Glib::Threads::RWLock::ReaderLock lm (
lock);
1428 BBTPointList::const_iterator fi;
1436 assert (fi !=
_map.end());
1439 (type ==
Bar ?
"bar" :
"beat")));
1446 if (fi ==
_map.begin()) {
1450 if ((*fi).is_bar() && (*fi).frame == frame) {
1457 while (!(*fi).is_bar()) {
1458 if (fi ==
_map.begin()) {
1464 (*fi).bar, (*fi).beat, (*fi).frame));
1467 }
else if (dir > 0) {
1471 if ((*fi).is_bar() && (*fi).frame == frame) {
1478 while (!(*fi).is_bar()) {
1480 if (fi ==
_map.end()) {
1487 (*fi).bar, (*fi).beat, (*fi).frame));
1494 BBTPointList::const_iterator prev = fi;
1495 BBTPointList::const_iterator next = fi;
1497 if ((*fi).frame == frame) {
1501 while ((*prev).beat != 1) {
1502 if (prev ==
_map.begin()) {
1508 while ((next !=
_map.end()) && (*next).beat != 1) {
1512 if ((next ==
_map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1513 return (*prev).frame;
1515 return (*next).frame;
1525 if (fi ==
_map.begin()) {
1529 if ((*fi).frame > frame || ((*fi).frame == frame && dir ==
RoundDownAlways)) {
1534 (*fi).bar, (*fi).beat, (*fi).frame));
1536 }
else if (dir > 0) {
1537 if ((*fi).frame < frame || ((*fi).frame == frame && dir ==
RoundUpAlways)) {
1542 (*fi).bar, (*fi).beat, (*fi).frame));
1546 if ((*fi).frame == frame) {
1550 BBTPointList::const_iterator prev = fi;
1551 BBTPointList::const_iterator next = fi;
1559 if ((next ==
_map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1560 return (*prev).frame;
1562 return (*next).frame;
1574 TempoMap::BBTPointList::const_iterator& end,
1578 Glib::Threads::RWLock::WriterLock lm (
lock);
1591 Glib::Threads::RWLock::ReaderLock lm (
lock);
1592 Metrics::const_iterator i;
1598 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1600 if ((*i)->frame() > frame) {
1626 Glib::Threads::RWLock::ReaderLock lm (
lock);
1627 Metrics::const_iterator i;
1633 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1635 if ((*i)->frame() > frame) {
1661 Metrics::const_iterator i;
1665 Glib::Threads::RWLock::ReaderLock lm (
lock);
1678 Glib::Threads::RWLock::WriterLock lm (
lock);
1688 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1705 error <<
_(
"Tempo map: could not set new state, restoring old one.") <<
endmsg;
1719 error <<
_(
"Tempo map: could not set new state, restoring old one.") <<
endmsg;
1726 if (niter == nlist.end()) {
1735 Metrics::iterator prev =
metrics.end();
1736 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1738 if (dynamic_cast<MeterSection*>(*prev) &&
dynamic_cast<MeterSection*
>(*i)) {
1739 if ((*prev)->start() == (*i)->start()) {
1743 }
else if (dynamic_cast<TempoSection*>(*prev) &&
dynamic_cast<TempoSection*
>(*i)) {
1744 if ((*prev)->start() == (*i)->start()) {
1764 Glib::Threads::RWLock::ReaderLock lm (
lock, Glib::Threads::TRY_LOCK);
1768 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1770 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1772 << t->
movable() <<
')' << endl;
1773 }
else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1775 <<
" (movable? " << m->
movable() <<
')' << endl;
1783 Glib::Threads::RWLock::ReaderLock lm (
lock);
1786 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1787 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1798 Glib::Threads::RWLock::ReaderLock lm (
lock);
1801 for (Metrics::const_iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1802 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1814 Glib::Threads::RWLock::WriterLock lm (
lock);
1815 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1816 if ((*i)->frame() >= where && (*i)->movable ()) {
1817 (*i)->set_frame ((*i)->frame() + amount);
1826 Metrics::iterator i;
1865 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
1872 if (bbt.beats != 1) {
1881 (*i)->set_start (bbt);
1883 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1886 }
else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
1890 fatal <<
_(
"programming error: unhandled MetricSection type") <<
endmsg;
1908 std::list<MetricSection*> metric_kill_list;
1913 Glib::Threads::RWLock::WriterLock lm (
lock);
1914 for (Metrics::iterator i =
metrics.begin(); i !=
metrics.end(); ++i) {
1915 if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
1916 metric_kill_list.push_back(*i);
1924 else if ((*i)->frame() >= where) {
1925 (*i)->
set_frame ((*i)->frame() - amount);
1932 metric_kill_list.remove(last_tempo);
1937 metric_kill_list.remove(last_meter);
1943 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
1962 Glib::Threads::RWLock::ReaderLock lm (
lock);
1963 Metrics::const_iterator next_tempo;
1968 for (next_tempo =
metrics.begin(); next_tempo !=
metrics.end(); ++next_tempo) {
1972 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
1981 if (pos < 0 && f == 0) {
2001 string_compose (
"frame %1 plus %2 beats, start with tempo = %3 @ %4\n",
2002 pos, beats, *((
const Tempo*)tempo), tempo->
frame()));
2018 distance_frames, distance_beats));
2028 if (next_tempo !=
metrics.end()) {
2030 tempo =
dynamic_cast<const TempoSection*
>(*next_tempo);
2036 while (next_tempo !=
metrics.end ()) {
2054 Glib::Threads::RWLock::ReaderLock lm (
lock);
2055 Metrics::const_reverse_iterator prev_tempo;
2060 for (prev_tempo =
metrics.rbegin(); prev_tempo !=
metrics.rend(); ++prev_tempo) {
2064 if ((t = dynamic_cast<const TempoSection*>(*prev_tempo)) != 0) {
2073 if (pos < 0 && f == 0) {
2091 }
else if (f < pos) {
2103 string_compose (
"frame %1 minus %2 beats, start with tempo = %3 @ %4 prev at beg? %5\n",
2104 pos, beats, *((
const Tempo*)tempo), tempo->
frame(),
2105 prev_tempo ==
metrics.rend()));
2126 tempo->
frame(), distance_frames, distance_beats));
2133 (prev_tempo ==
metrics.rend())));
2137 if (prev_tempo !=
metrics.rend()) {
2139 tempo =
dynamic_cast<const TempoSection*
>(*prev_tempo);
2146 while (prev_tempo !=
metrics.rend ()) {
2150 if (prev_tempo !=
metrics.rend() &&
dynamic_cast<const TempoSection*
>(*prev_tempo) != 0) {
2167 Glib::Threads::RWLock::ReaderLock lm (
lock);
2168 Metrics::const_iterator i;
2173 double frames_per_beat;
2186 if ((*i)->frame() > effective_pos) {
2190 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2192 }
else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2222 if ((*i)->frame() <= pos) {
2233 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2235 }
else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2262 if ((*i)->frame() <= pos) {
2270 pos += llrint (beats * frames_per_beat);
2273 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2275 }
else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2284 pos += llrint (beats * frames_per_beat);
2287 if (op.ticks >= BBT_Time::ticks_per_beat) {
2288 pos += llrint (frames_per_beat +
2289 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) /
2290 (
double) BBT_Time::ticks_per_beat)));
2292 pos += llrint (frames_per_beat * (op.ticks / (
double) BBT_Time::ticks_per_beat));
2305 Glib::Threads::RWLock::ReaderLock lm (
lock);
2306 Metrics::const_iterator next_tempo;
2312 for (next_tempo =
metrics.begin(); next_tempo !=
metrics.end(); ++next_tempo) {
2316 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
2318 if ((*next_tempo)->frame() > effective_pos) {
2334 string_compose (
"frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
2335 pos, distance, *((
const Tempo*)tempo), tempo->
frame()));
2346 if (next_tempo ==
metrics.end ()) {
2351 end = (*next_tempo)->frame ();
2352 distance_to_end = end - pos;
2356 framecnt_t const sub = min (distance, distance_to_end);
2359 distance_to_end, sub));
2368 pos, beats, distance));
2372 if (next_tempo !=
metrics.end()) {
2374 tempo =
dynamic_cast<const TempoSection*
>(*next_tempo);
2381 while (next_tempo !=
metrics.end ()) {
2390 if (next_tempo ==
metrics.end()) {
2394 **next_tempo, (*next_tempo)->frame()));
2404 TempoMap::BBTPointList::const_iterator
2409 BBTPointList::const_iterator i;
2415 return _map.begin();
2418 i = lower_bound (
_map.begin(),
_map.end(), pos);
2419 assert (i !=
_map.end());
2420 if ((*i).frame > pos) {
2421 assert (i !=
_map.begin());
2428 bool operator() (
const BBT_Time& a,
const BBT_Time& b) {
2433 TempoMap::BBTPointList::const_iterator
2436 BBTPointList::const_iterator i;
2439 i = lower_bound (
_map.begin(),
_map.end(), bbt, cmp);
2440 assert (i !=
_map.end());
2441 if ((*i).bar > bbt.bars || (*i).beat > bbt.beats) {
2442 assert (i !=
_map.begin());
2448 TempoMap::BBTPointList::const_iterator
2453 BBTPointList::const_iterator i;
2455 if (
_map.back().frame == pos) {
2457 assert (i !=
_map.begin());
2462 i = upper_bound (
_map.begin(),
_map.end(), pos);
2463 assert (i !=
_map.end());
2480 o <<
"MetricSection @ " << section.
frame() <<
" aka " << section.
start() <<
' ';
2485 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2486 o << *((
const Tempo*) ts);
2487 }
else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2488 o << *((
const Meter*) ms);
void add_meter_locked(const Meter &, Timecode::BBT_Time where, bool recompute)
Evoral::Beats framewalk_to_beats(framepos_t pos, framecnt_t distance) const
static Meter _default_meter
void dump(std::ostream &) const
LIBPBD_API Transmitter fatal
void extend_map(framepos_t end)
void change_existing_tempo_at(framepos_t, double bpm, double note_type)
Glib::Threads::RWLock lock
bool remove_meter_locked(const MeterSection &)
void bbt_time(framepos_t when, Timecode::BBT_Time &)
const std::string & value() const
PBD::Signal1< void, const PropertyChange & > PropertyChanged
framecnt_t bbt_duration_at_unlocked(const Timecode::BBT_Time &when, const Timecode::BBT_Time &bbt, int dir)
const Meter & meter() const
int set_state(const XMLNode &, int version)
void add_tempo(const Tempo &, Timecode::BBT_Time where)
void do_insert(MetricSection *section)
LIBARDOUR_API uint64_t SnapBBT
std::list< MetricSection * > Metrics
void set_metric(const MetricSection *section)
const std::string & name() const
Always round up, even if on a division.
std::ostream & operator<<(std::ostream &o, const Meter &m)
const TempoSection & first_tempo() const
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
void get_grid(BBTPointList::const_iterator &, BBTPointList::const_iterator &, framepos_t start, framepos_t end)
const XMLNodeList & children(const std::string &str=std::string()) const
double bar_offset() const
LIBARDOUR_API uint64_t TempoMath
std::ostream & endmsg(std::ostream &ostr)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
framepos_t frame_time(const Timecode::BBT_Time &)
framepos_t round_to_bar(framepos_t frame, RoundMode dir)
double _divisions_per_bar
BBTPointList::const_iterator bbt_after_or_at(framepos_t)
MeterSection(const Timecode::BBT_Time &start, double bpb, double note_type)
void update_bar_offset_from_bbt(const Meter &)
const Meter & meter_at(framepos_t) const
framepos_t framepos_minus_beats(framepos_t, Evoral::Beats) const
LIBARDOUR_API uint64_t TempoMap
std::list< XMLNode * > XMLNodeList
const Timecode::BBT_Time & start() const
double frames_per_beat(framecnt_t sr) const
const TempoSection & tempo_section_at(framepos_t) const
void set_start(const Timecode::BBT_Time &t)
framepos_t framepos_plus_bbt(framepos_t pos, Timecode::BBT_Time b) const
void replace_meter(const MeterSection &, const Meter &, const Timecode::BBT_Time &where)
void update_bbt_time_from_bar_offset(const Meter &)
BBTPointList::const_iterator bbt_before_or_at(framepos_t)
static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn)
XMLProperty * property(const char *)
void add_meter(const Meter &, Timecode::BBT_Time where)
void _extend_map(TempoSection *tempo, MeterSection *meter, Metrics::iterator next_metric, Timecode::BBT_Time current, framepos_t current_frame, framepos_t end)
void change_initial_tempo(double bpm, double note_type)
static const std::string xml_state_node_name
uint64_t to_ticks() const
XMLNode & get_state() const
virtual void set_start(const Timecode::BBT_Time &w)
bool string_is_affirmative(const std::string &str)
XMLNode & get_state(void)
Round down only if necessary.
#define DEBUG_ENABLED(bits)
framepos_t framepos_plus_beats(framepos_t, Evoral::Beats) const
void remove_meter(const MeterSection &, bool send_signal)
#define DEBUG_TRACE(bits, str)
bool cut_time(framepos_t where, framecnt_t amount)
double note_divisor() const
const MeterSection & first_meter() const
void bbt_time_rt(framepos_t when, Timecode::BBT_Time &)
framecnt_t bbt_duration_at(framepos_t, const Timecode::BBT_Time &, int dir)
double beats_per_minute() const
virtual void set_frame(framepos_t f)
XMLProperty * add_property(const char *name, const std::string &value)
framepos_t round_to_beat_subdivision(framepos_t fr, int sub_num, RoundMode dir)
void add_tempo_locked(const Tempo &, Timecode::BBT_Time where, bool recompute)
void add_child_nocopy(XMLNode &)
void recompute_map(bool reassign_tempo_bbt, framepos_t end=-1)
void set_frame(framepos_t f)
void require_map_to(framepos_t pos)
XMLNode & get_state() const
const Tempo & tempo() const
double divisions_per_bar() const
TempoMetric metric_at(Timecode::BBT_Time bbt) const
LIBEVORAL_API uint64_t Beats
const MeterSection & meter_section_at(framepos_t) const
framepos_t round_to_beat(framepos_t frame, RoundMode dir)
static const framepos_t max_framepos
Round up only if necessary.
TempoMap(framecnt_t frame_rate)
void remove_tempo(const TempoSection &, bool send_signal)
XMLNodeList::const_iterator XMLNodeConstIterator
double frames_per_grid(const Tempo &, framecnt_t sr) const
const Tempo & tempo_at(framepos_t) const
void replace_tempo(const TempoSection &, const Tempo &, const Timecode::BBT_Time &where)
void set_movable(bool yn)
Always round down, even if on a division.
framepos_t round_to_type(framepos_t fr, RoundMode dir, BBTPointType)
static Tempo _default_tempo
std::string string_compose(const std::string &fmt, const T1 &o1)
bool remove_tempo_locked(const TempoSection &)
void insert_time(framepos_t, framecnt_t)
static const std::string xml_state_node_name