Tempo ramps - amend previous commit.
[ardour.git] / libs / ardour / tempo.cc
1 /*
2     Copyright (C) 2000-2002 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <algorithm>
21 #include <stdexcept>
22 #include <cmath>
23
24 #include <unistd.h>
25
26 #include <glibmm/threads.h>
27 #include "pbd/xml++.h"
28 #include "evoral/Beats.hpp"
29 #include "ardour/debug.h"
30 #include "ardour/lmath.h"
31 #include "ardour/tempo.h"
32
33 #include "i18n.h"
34 #include <locale.h>
35
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace PBD;
39
40 using Timecode::BBT_Time;
41
42 /* _default tempo is 4/4 qtr=120 */
43
44 Meter    TempoMap::_default_meter (4.0, 4.0);
45 Tempo    TempoMap::_default_tempo (120.0);
46
47 /***********************************************************************/
48
49 double
50 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
51 {
52         /* This is tempo- and meter-sensitive. The number it returns
53            is based on the interval between any two lines in the
54            grid that is constructed from tempo and meter sections.
55
56            The return value IS NOT interpretable in terms of "beats".
57         */
58
59         return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
60 }
61
62 double
63 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
64 {
65         return frames_per_grid (tempo, sr) * _divisions_per_bar;
66 }
67
68
69 /***********************************************************************/
70
71 const string TempoSection::xml_state_node_name = "Tempo";
72
73 TempoSection::TempoSection (const XMLNode& node)
74         : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
75 {
76         const XMLProperty *prop;
77         BBT_Time start;
78         LocaleGuard lg;
79
80         if ((prop = node.property ("start")) == 0) {
81                 error << _("TempoSection XML node has no \"start\" property") << endmsg;
82                 throw failed_constructor();
83         }
84
85         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
86                     &start.bars,
87                     &start.beats,
88                     &start.ticks) < 3) {
89                 error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
90                 throw failed_constructor();
91         }
92
93         set_start (start);
94
95         if ((prop = node.property ("beats-per-minute")) == 0) {
96                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
97                 throw failed_constructor();
98         }
99
100         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
101                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
102                 throw failed_constructor();
103         }
104
105         if ((prop = node.property ("note-type")) == 0) {
106                 /* older session, make note type be quarter by default */
107                 _note_type = 4.0;
108         } else {
109                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
110                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
111                         throw failed_constructor();
112                 }
113         }
114
115         if ((prop = node.property ("movable")) == 0) {
116                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
117                 throw failed_constructor();
118         }
119
120         set_movable (string_is_affirmative (prop->value()));
121
122         if ((prop = node.property ("bar-offset")) == 0) {
123                 _bar_offset = -1.0;
124         } else {
125                 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
126                         error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
127                         throw failed_constructor();
128                 }
129         }
130
131         if ((prop = node.property ("tempo-type")) == 0) {
132                 _type = Type::Constant;
133         } else {
134                 if (strstr(prop->value().c_str(),"Constant")) {
135                         _type = Type::Constant;
136                 } else {
137                         _type = Type::Ramp;
138                 }
139         }
140 }
141
142 XMLNode&
143 TempoSection::get_state() const
144 {
145         XMLNode *root = new XMLNode (xml_state_node_name);
146         char buf[256];
147         LocaleGuard lg;
148
149         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
150                   start().bars,
151                   start().beats,
152                   start().ticks);
153         root->add_property ("start", buf);
154         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
155         root->add_property ("beats-per-minute", buf);
156         snprintf (buf, sizeof (buf), "%f", _note_type);
157         root->add_property ("note-type", buf);
158         // snprintf (buf, sizeof (buf), "%f", _bar_offset);
159         // root->add_property ("bar-offset", buf);
160         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
161         root->add_property ("movable", buf);
162
163         snprintf (buf, sizeof (buf), "%s", _type == Constant?"Constant":"Ramp");
164         root->add_property ("tempo-type", buf);
165
166         return *root;
167 }
168
169 void
170
171 TempoSection::update_bar_offset_from_bbt (const Meter& m)
172 {
173         _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) /
174                 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
175
176         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
177 }
178
179 void
180 TempoSection::set_type (Type type)
181 {
182         _type = type;
183 }
184
185 double
186 TempoSection::tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
187 {
188
189         if (_type == Constant) {
190                 return beats_per_minute();
191         }
192
193         return tick_tempo_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)) / BBT_Time::ticks_per_beat;
194 }
195
196 framepos_t
197 TempoSection::frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
198 {
199         if (_type == Constant) {
200                 return 0;
201         }
202
203         return minute_to_frame (time_at_tick_tempo (tempo *  BBT_Time::ticks_per_beat,  end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
204 }
205
206 double
207 TempoSection::tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
208 {
209         if (_type == Constant) {
210                 return (frame / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat;
211         }
212
213         return tick_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate));
214 }
215
216 framepos_t
217 TempoSection::frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
218 {
219         if (_type == Constant) {
220                 return (framepos_t) floor ((tick  / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate));
221         }
222
223         return minute_to_frame (time_at_tick (tick, end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
224 }
225
226 double TempoSection::beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
227 {
228         return tick_at_frame (frame, end_bpm, end_frame, frame_rate) / BBT_Time::ticks_per_beat;
229 }
230
231 framepos_t TempoSection::frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
232 {
233         return frame_at_tick (beat * BBT_Time::ticks_per_beat, end_bpm, end_frame, frame_rate);
234 }
235
236 framecnt_t
237 TempoSection::minute_to_frame (double time, framecnt_t frame_rate) const
238 {
239         return time * 60.0 * frame_rate;
240 }
241
242 double
243 TempoSection::frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const
244 {
245         return (frame / (double) frame_rate) / 60.0;
246 }
247
248 /* constant for exp */
249 double
250 TempoSection::a_func (double begin_tpm, double end_tpm, double end_time) const
251 {
252         return log (end_tpm / ticks_per_minute()) /  c_func (end_tpm, end_time);
253 }
254 double
255 TempoSection::c_func (double end_tpm, double end_time) const
256 {
257         return log (end_tpm / ticks_per_minute()) /  end_time;
258 }
259
260 /* tempo in tpm at time in minutes */
261 double
262 TempoSection::tick_tempo_at_time (double time, double end_tpm, double end_time) const
263 {
264         return exp (c_func (end_tpm, end_time) * time) * ticks_per_minute();
265 }
266
267 /* time in minutes at tempo in tpm */
268 double
269 TempoSection::time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const
270 {
271         return log (tick_tempo / ticks_per_minute()) / c_func (end_tpm, end_time);
272 }
273
274 /* tempo in bpm at time in minutes */
275 double
276 TempoSection::tempo_at_time (double time, double end_bpm, double end_time) const
277 {
278         return tick_tempo_at_time (time, end_bpm *  BBT_Time::ticks_per_beat, end_time) / BBT_Time::ticks_per_beat;
279 }
280
281 /* time in minutes at tempo in bpm */
282 double
283 TempoSection::time_at_tempo (double tempo, double end_bpm, double end_time) const
284 {
285         return time_at_tick_tempo (tempo * BBT_Time::ticks_per_beat, end_bpm * BBT_Time::ticks_per_beat, end_time);
286 }
287
288 /* tick at time in minutes */
289 double
290 TempoSection::tick_at_time (double time, double end_tpm, double end_time) const
291 {
292         return ((exp (c_func (end_tpm, end_time) * time)) - 1) * ticks_per_minute() / c_func (end_tpm, end_time);
293 }
294
295 /* time in minutes at tick */
296 double
297 TempoSection::time_at_tick (double tick, double end_tpm, double end_time) const
298 {
299         return log (((c_func (end_tpm, end_time) * tick) / ticks_per_minute()) + 1) / c_func (end_tpm, end_time);
300 }
301
302 /* beat at time in minutes */
303 double
304 TempoSection::beat_at_time (double time, double end_tpm, double end_time) const
305 {
306         return tick_at_time (time, end_tpm, end_time) / BBT_Time::ticks_per_beat;
307 }
308
309 /* time in munutes at beat */
310 double
311 TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const
312 {
313         return time_at_tick (beat * BBT_Time::ticks_per_beat, end_tpm, end_time);
314 }
315
316 void
317 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
318 {
319         BBT_Time new_start;
320
321         if (_bar_offset < 0.0) {
322                 /* not set yet */
323                 return;
324         }
325
326         new_start.bars = start().bars;
327
328         double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
329         new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
330         //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
331         new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat);
332
333         /* remember the 1-based counting properties of beats */
334         new_start.beats += 1;
335         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
336                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
337
338         set_start (new_start);
339 }
340
341 /***********************************************************************/
342
343 const string MeterSection::xml_state_node_name = "Meter";
344
345 MeterSection::MeterSection (const XMLNode& node)
346         : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
347 {
348         XMLProperty const * prop;
349         BBT_Time start;
350         LocaleGuard lg;
351
352         if ((prop = node.property ("start")) == 0) {
353                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
354                 throw failed_constructor();
355         }
356
357         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
358                     &start.bars,
359                     &start.beats,
360                     &start.ticks) < 3) {
361                 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
362                 throw failed_constructor();
363         }
364
365         set_start (start);
366
367         /* beats-per-bar is old; divisions-per-bar is new */
368
369         if ((prop = node.property ("divisions-per-bar")) == 0) {
370                 if ((prop = node.property ("beats-per-bar")) == 0) {
371                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
372                         throw failed_constructor();
373                 }
374         }
375
376         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
377                 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
378                 throw failed_constructor();
379         }
380
381         if ((prop = node.property ("note-type")) == 0) {
382                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
383                 throw failed_constructor();
384         }
385
386         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
387                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
388                 throw failed_constructor();
389         }
390
391         if ((prop = node.property ("movable")) == 0) {
392                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
393                 throw failed_constructor();
394         }
395
396         set_movable (string_is_affirmative (prop->value()));
397 }
398
399 XMLNode&
400 MeterSection::get_state() const
401 {
402         XMLNode *root = new XMLNode (xml_state_node_name);
403         char buf[256];
404         LocaleGuard lg;
405
406         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
407                   start().bars,
408                   start().beats,
409                   start().ticks);
410         root->add_property ("start", buf);
411         snprintf (buf, sizeof (buf), "%f", _note_type);
412         root->add_property ("note-type", buf);
413         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
414         root->add_property ("divisions-per-bar", buf);
415         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
416         root->add_property ("movable", buf);
417
418         return *root;
419 }
420
421 /***********************************************************************/
422
423 struct MetricSectionSorter {
424     bool operator() (const MetricSection* a, const MetricSection* b) {
425             return a->start() < b->start();
426     }
427 };
428
429 struct MetricSectionFrameSorter {
430     bool operator() (const MetricSection* a, const MetricSection* b) {
431             return a->frame() < b->frame();
432     }
433 };
434
435 TempoMap::TempoMap (framecnt_t fr)
436 {
437         _frame_rate = fr;
438         BBT_Time start;
439
440         start.bars = 1;
441         start.beats = 1;
442         start.ticks = 0;
443
444         TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp);
445         MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
446
447         t->set_movable (false);
448         m->set_movable (false);
449
450         /* note: frame time is correct (zero) for both of these */
451
452         metrics.push_back (t);
453         metrics.push_back (m);
454
455 }
456
457 TempoMap::~TempoMap ()
458 {
459 }
460
461 void
462 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
463 {
464         bool removed = false;
465
466         {
467                 Glib::Threads::RWLock::WriterLock lm (lock);
468                 if ((removed = remove_tempo_locked (tempo))) {
469                         if (complete_operation) {
470                                 recompute_map (true);
471                         }
472                 }
473         }
474
475         if (removed && complete_operation) {
476                 PropertyChanged (PropertyChange ());
477         }
478 }
479
480 bool
481 TempoMap::remove_tempo_locked (const TempoSection& tempo)
482 {
483         Metrics::iterator i;
484
485         for (i = metrics.begin(); i != metrics.end(); ++i) {
486                 if (dynamic_cast<TempoSection*> (*i) != 0) {
487                         if (tempo.frame() == (*i)->frame()) {
488                                 if ((*i)->movable()) {
489                                         metrics.erase (i);
490                                         return true;
491                                 }
492                         }
493                 }
494         }
495
496         return false;
497 }
498
499 void
500 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
501 {
502         bool removed = false;
503
504         {
505                 Glib::Threads::RWLock::WriterLock lm (lock);
506                 if ((removed = remove_meter_locked (tempo))) {
507                         if (complete_operation) {
508                                 recompute_map (true);
509                         }
510                 }
511         }
512
513         if (removed && complete_operation) {
514                 PropertyChanged (PropertyChange ());
515         }
516 }
517
518 bool
519 TempoMap::remove_meter_locked (const MeterSection& tempo)
520 {
521         Metrics::iterator i;
522
523         for (i = metrics.begin(); i != metrics.end(); ++i) {
524                 if (dynamic_cast<MeterSection*> (*i) != 0) {
525                         if (tempo.frame() == (*i)->frame()) {
526                                 if ((*i)->movable()) {
527                                         metrics.erase (i);
528                                         return true;
529                                 }
530                         }
531                 }
532         }
533
534         return false;
535 }
536
537 void
538 TempoMap::do_insert (MetricSection* section)
539 {
540         bool need_add = true;
541
542         /* we only allow new meters to be inserted on beat 1 of an existing
543          * measure.
544          */
545
546         if (dynamic_cast<MeterSection*>(section)) {
547                 assert (section->start().ticks == 0);
548
549                 /* we need to (potentially) update the BBT times of tempo
550                    sections based on this new meter.
551                 */
552
553                 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
554
555                         BBT_Time corrected = section->start();
556                         corrected.beats = 1;
557                         corrected.ticks = 0;
558
559                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
560                                                    section->start(), corrected) << endmsg;
561
562                         section->set_start (corrected);
563                 }
564         }
565
566
567
568         /* Look for any existing MetricSection that is of the same type and
569            in the same bar as the new one, and remove it before adding
570            the new one. Note that this means that if we find a matching,
571            existing section, we can break out of the loop since we're
572            guaranteed that there is only one such match.
573         */
574
575         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
576
577                 bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
578                 bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
579
580                 if (iter_is_tempo && insert_is_tempo) {
581
582                         /* Tempo sections */
583
584                         if ((*i)->start().bars == section->start().bars &&
585                             (*i)->start().beats == section->start().beats) {
586
587                                 if (!(*i)->movable()) {
588
589                                         /* can't (re)move this section, so overwrite
590                                          * its data content (but not its properties as
591                                          * a section).
592                                          */
593
594                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
595                                         need_add = false;
596                                 } else {
597                                         metrics.erase (i);
598                                 }
599                                 break;
600                         }
601
602                 } else if (!iter_is_tempo && !insert_is_tempo) {
603
604                         /* Meter Sections */
605
606                         if ((*i)->start().bars == section->start().bars) {
607
608                                 if (!(*i)->movable()) {
609
610                                         /* can't (re)move this section, so overwrite
611                                          * its data content (but not its properties as
612                                          * a section
613                                          */
614
615                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
616                                         need_add = false;
617                                 } else {
618                                         metrics.erase (i);
619
620                                 }
621
622                                 break;
623                         }
624                 } else {
625                         /* non-matching types, so we don't care */
626                 }
627         }
628
629         /* Add the given MetricSection, if we didn't just reset an existing
630          * one above
631          */
632
633         if (need_add) {
634
635                 Metrics::iterator i;
636
637                 for (i = metrics.begin(); i != metrics.end(); ++i) {
638                         if ((*i)->start() > section->start()) {
639                                 break;
640                         }
641                 }
642
643                 metrics.insert (i, section);
644         }
645 }
646
647 void
648 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type)
649 {
650         {
651                 Glib::Threads::RWLock::WriterLock lm (lock);
652                 TempoSection& first (first_tempo());
653
654                 if (ts.start() != first.start()) {
655                         remove_tempo_locked (ts);
656                         add_tempo_locked (tempo, where, true, type);
657                 } else {
658                         first.set_type (type);
659                         {
660                                 /* cannot move the first tempo section */
661                                 *static_cast<Tempo*>(&first) = tempo;
662                                 recompute_map (false);
663                         }
664                 }
665         }
666
667         PropertyChanged (PropertyChange ());
668 }
669
670 void
671 TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
672 {
673         {
674                 TempoSection& first (first_tempo());
675                 if (ts.frame() != first.frame()) {
676                         BBT_Time bbt;
677                         {
678                                 Glib::Threads::RWLock::WriterLock lm (lock);
679
680                                 ts.set_frame (frame);
681
682                                 MetricSectionFrameSorter fcmp;
683                                 metrics.sort (fcmp);
684
685                                 Metrics::const_iterator i;
686                                 TempoSection* prev_ts = 0;
687                                 MeterSection* meter = 0;
688
689                                 for (i = metrics.begin(); i != metrics.end(); ++i) {
690                                         TempoSection* t;
691                                         MeterSection* m;
692
693                                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
694
695                                                 if ((*i)->frame() > frame - 1) {
696                                                         break;
697                                                 }
698
699                                                 prev_ts = t;
700                                         }
701
702                                         if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
703
704                                                 if ((*i)->frame() > frame) {
705                                                         break;
706                                                 }
707
708                                                 meter = m;
709                                         }
710                                 }
711
712                                 if (prev_ts && meter) {
713
714                                         /* set the start bbt */
715                                         double const ticks_to_ts = prev_ts->tick_at_frame (frame - prev_ts->frame(), ts.beats_per_minute(), frame - prev_ts->frame(), _frame_rate);
716                                         double beats = ticks_to_ts / BBT_Time::ticks_per_beat;
717                                         Timecode::BBT_Time bbt;
718
719                                         bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar());
720                                         beats -= bbt.bars * meter->divisions_per_bar();
721                                         bbt.beats = (uint32_t) floor (beats);
722                                         beats -= bbt.beats;
723                                         bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat);
724
725                                         /* now add the prev ts bbt */
726                                         bbt.bars += prev_ts->start().bars;
727                                         bbt.beats += prev_ts->start().beats;
728
729                                         if (bbt.beats > meter->divisions_per_bar()) {
730                                                 ++bbt.bars;
731                                                 bbt.beats -= meter->divisions_per_bar();
732                                         }
733                                         bbt.ticks += prev_ts->start().ticks;
734                                         if (bbt.ticks > BBT_Time::ticks_per_beat) {
735                                                 ++bbt.beats;
736                                                 bbt.ticks -= BBT_Time::ticks_per_beat;
737                                         }
738                                         ts.set_start (bbt);
739                                 }
740
741                                 MetricSectionSorter cmp;
742                                 metrics.sort (cmp);
743                                 recompute_map (false);
744                         }
745                 }
746         }
747
748         MetricPositionChanged (); // Emit Signal
749 }
750
751 void
752 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
753 {
754         {
755                 Glib::Threads::RWLock::WriterLock lm (lock);
756                 add_tempo_locked (tempo, where, true, type);
757         }
758
759
760         PropertyChanged (PropertyChange ());
761 }
762
763 void
764 TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type)
765 {
766         TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
767
768         /* find the meter to use to set the bar offset of this
769          * tempo section.
770          */
771
772         const Meter* meter = &first_meter();
773
774         /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
775            at something, because we insert the default tempo and meter during
776            TempoMap construction.
777
778            now see if we can find better candidates.
779         */
780
781         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
782
783                 const MeterSection* m;
784
785                 if (where < (*i)->start()) {
786                         break;
787                 }
788
789                 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
790                         meter = m;
791                 }
792         }
793
794         //ts->update_bar_offset_from_bbt (*meter);
795
796         /* and insert it */
797
798         do_insert (ts);
799
800         if (recompute) {
801                 recompute_map (false);
802         }
803 }
804
805 void
806 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
807 {
808         {
809                 Glib::Threads::RWLock::WriterLock lm (lock);
810                 MeterSection& first (first_meter());
811
812                 if (ms.start() != first.start()) {
813                         remove_meter_locked (ms);
814                         add_meter_locked (meter, where, true);
815                 } else {
816                         /* cannot move the first meter section */
817                         *static_cast<Meter*>(&first) = meter;
818                         recompute_map (true);
819                 }
820         }
821
822         PropertyChanged (PropertyChange ());
823 }
824
825 void
826 TempoMap::add_meter (const Meter& meter, BBT_Time where)
827 {
828         {
829                 Glib::Threads::RWLock::WriterLock lm (lock);
830                 add_meter_locked (meter, where, true);
831         }
832
833
834 #ifndef NDEBUG
835         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
836                 dump (std::cerr);
837         }
838 #endif
839
840         PropertyChanged (PropertyChange ());
841 }
842
843 void
844 TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
845 {
846         /* a new meter always starts a new bar on the first beat. so
847            round the start time appropriately. remember that
848            `where' is based on the existing tempo map, not
849            the result after we insert the new meter.
850
851         */
852
853         if (where.beats != 1) {
854                 where.beats = 1;
855                 where.bars++;
856         }
857
858         /* new meters *always* start on a beat. */
859         where.ticks = 0;
860
861         do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
862
863         if (recompute) {
864                 recompute_map (true);
865         }
866
867 }
868
869 void
870 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
871 {
872         Tempo newtempo (beats_per_minute, note_type);
873         TempoSection* t;
874
875         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
876                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
877                         {
878                                 Glib::Threads::RWLock::WriterLock lm (lock);
879                                 *((Tempo*) t) = newtempo;
880                                 recompute_map (false);
881                         }
882                         PropertyChanged (PropertyChange ());
883                         break;
884                 }
885         }
886 }
887
888 void
889 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
890 {
891         Tempo newtempo (beats_per_minute, note_type);
892
893         TempoSection* prev;
894         TempoSection* first;
895         Metrics::iterator i;
896
897         /* find the TempoSection immediately preceding "where"
898          */
899
900         for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
901
902                 if ((*i)->frame() > where) {
903                         break;
904                 }
905
906                 TempoSection* t;
907
908                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
909                         if (!first) {
910                                 first = t;
911                         }
912                         prev = t;
913                 }
914         }
915
916         if (!prev) {
917                 if (!first) {
918                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
919                         return;
920                 }
921
922                 prev = first;
923         }
924
925         /* reset */
926
927         {
928                 Glib::Threads::RWLock::WriterLock lm (lock);
929                 /* cannot move the first tempo section */
930                 *((Tempo*)prev) = newtempo;
931                 recompute_map (false);
932         }
933
934         PropertyChanged (PropertyChange ());
935 }
936
937 const MeterSection&
938 TempoMap::first_meter () const
939 {
940         const MeterSection *m = 0;
941
942         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
943                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
944                         return *m;
945                 }
946         }
947
948         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
949         abort(); /*NOTREACHED*/
950         return *m;
951 }
952
953 MeterSection&
954 TempoMap::first_meter ()
955 {
956         MeterSection *m = 0;
957
958         /* CALLER MUST HOLD LOCK */
959
960         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
961                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
962                         return *m;
963                 }
964         }
965
966         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
967         abort(); /*NOTREACHED*/
968         return *m;
969 }
970
971 const TempoSection&
972 TempoMap::first_tempo () const
973 {
974         const TempoSection *t = 0;
975
976         /* CALLER MUST HOLD LOCK */
977
978         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
979                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
980                         return *t;
981                 }
982         }
983
984         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
985         abort(); /*NOTREACHED*/
986         return *t;
987 }
988
989 TempoSection&
990 TempoMap::first_tempo ()
991 {
992         TempoSection *t = 0;
993
994         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
995                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
996                         return *t;
997                 }
998         }
999
1000         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1001         abort(); /*NOTREACHED*/
1002         return *t;
1003 }
1004
1005 void
1006 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
1007 {
1008         /* CALLER MUST HOLD WRITE LOCK */
1009
1010         MeterSection* meter = 0;
1011         TempoSection* tempo = 0;
1012         double current_frame;
1013         BBT_Time current;
1014         Metrics::iterator next_metric;
1015
1016         if (end < 0) {
1017
1018                 /* we will actually stop once we hit
1019                    the last metric.
1020                 */
1021                 end = max_framepos;
1022
1023         }
1024
1025         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1026
1027         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1028                 MeterSection* ms;
1029
1030                 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
1031                         meter = ms;
1032                         break;
1033                 }
1034         }
1035
1036         assert(meter);
1037
1038         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1039                 TempoSection* ts;
1040
1041                 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
1042                         tempo = ts;
1043                         break;
1044                 }
1045         }
1046
1047         assert(tempo);
1048
1049         /* assumes that the first meter & tempo are at frame zero */
1050         current_frame = 0;
1051         meter->set_frame (0);
1052         tempo->set_frame (0);
1053
1054         /* assumes that the first meter & tempo are at 1|1|0 */
1055         current.bars = 1;
1056         current.beats = 1;
1057         current.ticks = 0;
1058         if (reassign_tempo_bbt) {
1059
1060                 MeterSection* rmeter = meter;
1061
1062                 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
1063
1064                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1065
1066                         TempoSection* ts;
1067                         MeterSection* ms;
1068
1069                         if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
1070
1071                                 /* reassign the BBT time of this tempo section
1072                                  * based on its bar offset position.
1073                                  */
1074
1075                                 //ts->update_bbt_time_from_bar_offset (*rmeter);
1076
1077                         } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
1078                                 rmeter = ms;
1079                         } else {
1080                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
1081                                 abort(); /*NOTREACHED*/
1082                         }
1083                 }
1084         }
1085
1086         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
1087
1088         next_metric = metrics.begin();
1089         ++next_metric; // skip meter (or tempo)
1090         ++next_metric; // skip tempo (or meter)
1091
1092         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
1093
1094         if (end == 0) {
1095                 /* silly call from Session::process() during startup
1096                  */
1097                 return;
1098         }
1099
1100         _extend_map (tempo, meter, next_metric, current, current_frame, end);
1101 }
1102
1103 void
1104 TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
1105                        Metrics::iterator next_metric,
1106                        BBT_Time current, framepos_t current_frame, framepos_t end)
1107 {
1108         /* CALLER MUST HOLD WRITE LOCK */
1109
1110         uint32_t first_tick_in_new_meter = 0;
1111         Metrics::const_iterator i;
1112         Metrics::const_iterator mi;
1113
1114         TempoSection* prev_ts = tempo;
1115
1116         for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
1117                 MeterSection* m = 0;
1118
1119                 if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) {
1120
1121                         if (m->start() >= prev_ts->start()) {
1122                                 first_tick_in_new_meter = ((((m->start().bars - 1) * meter->divisions_per_bar()) + (m->start().beats - 1)) * BBT_Time::ticks_per_beat) + m->start().ticks; // expressed in ticks from the previous meter
1123                                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1124                                         TempoSection* t;
1125
1126                                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1127                                                 if (t->position_lock_style() == AudioTime) {
1128                                                         /* set the start bbt */
1129                                                         double const ticks_at_ts = prev_ts->tick_at_frame (t->frame(), t->beats_per_minute(), t->frame(), _frame_rate);
1130                                                         double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1))  * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
1131
1132                                                         double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
1133                                                         double beats = ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat;
1134
1135                                                         Timecode::BBT_Time bbt;
1136                                                         bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar());
1137                                                         beats -= bbt.bars * meter->divisions_per_bar();
1138                                                         bbt.beats = (uint32_t) floor (beats);
1139                                                         beats -= bbt.beats;
1140                                                         bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat);
1141                                                         /* now add the prev ts bbt */
1142                                                         bbt.bars += prev_ts->start().bars;
1143                                                         bbt.beats += prev_ts->start().beats;
1144
1145                                                         if (bbt.beats > meter->divisions_per_bar()) {
1146                                                                 ++bbt.bars;
1147                                                                 bbt.beats -= meter->divisions_per_bar();
1148                                                         }
1149                                                         bbt.ticks += prev_ts->start().ticks;
1150                                                         if (bbt.ticks > BBT_Time::ticks_per_beat) {
1151                                                                 ++bbt.beats;
1152                                                                 bbt.ticks -= BBT_Time::ticks_per_beat;
1153                                                         }
1154                                                         t->set_start (bbt);
1155
1156                                                         if (m->start() < t->start() && m->start() == prev_ts->start()) {
1157                                                                 m->set_frame (prev_ts->frame());
1158                                                         } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
1159                                                                 m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), t->frame(), _frame_rate) + prev_ts->frame());
1160                                                         }
1161
1162                                                 } else if (t->start() >= m->start() && t->start() > prev_ts->start()) {
1163                                                         //cerr << "new ts start bars = " << t->start().bars << " beats = " << t->start().beats << " ticks = " << t->start().ticks << endl;
1164                                                         //cerr << "prev ts start bars = " << prev_ts->start().bars << " beats = " << prev_ts->start().beats << " ticks = " << prev_ts->start().ticks << endl;
1165
1166                                                         /*tempo section (t) lies in the previous meter */
1167                                                         double const ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) )  * BBT_Time::ticks_per_beat) + t->start().ticks;
1168                                                         double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1))  * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
1169                                                         double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
1170                                                         /* assume (falsely) that the target tempo is constant */
1171                                                         double length_estimate = (ticks_relative_to_prev_ts /  BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1172                                                         if (prev_ts->type() == TempoSection::Type::Constant) {
1173                                                                 length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
1174                                                         }
1175                                                         cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl;
1176                                                         double const system_precision_at_target_tempo =  (_frame_rate / t->ticks_per_minute());
1177                                                         cerr << " system_precision_at_target_tempo = " << system_precision_at_target_tempo << endl;
1178                                                         double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf
1179
1180                                                         while (fabs (tick_error) >= system_precision_at_target_tempo) {
1181
1182                                                                 double const actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate);
1183                                                                 tick_error = ticks_relative_to_prev_ts - actual_ticks;
1184                                                                 length_estimate += (tick_error / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1185                                                         }
1186                                                         t->set_frame (length_estimate + prev_ts->frame());
1187
1188                                                         if (m->start() < t->start() && m->start() == prev_ts->start()) {
1189                                                                 m->set_frame (prev_ts->frame());
1190                                                         } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
1191                                                                 cerr << "recompute map - music lock style setting meter frame to " << prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) << " ticks = " << first_tick_in_new_meter - ticks_at_prev_ts  << endl;
1192
1193                                                                 m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) + prev_ts->frame());
1194                                                         }
1195                                                 }
1196                                                 prev_ts = t;
1197                                         }
1198                                 }
1199                         }
1200                         meter = m;
1201                 }
1202         }
1203 }
1204
1205
1206 TempoMetric
1207 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1208 {
1209         Glib::Threads::RWLock::ReaderLock lm (lock);
1210         TempoMetric m (first_meter(), first_tempo());
1211
1212         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1213            at something, because we insert the default tempo and meter during
1214            TempoMap construction.
1215
1216            now see if we can find better candidates.
1217         */
1218
1219         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1220
1221                 if ((*i)->frame() > frame) {
1222                         break;
1223                 }
1224
1225                 m.set_metric(*i);
1226
1227                 if (last) {
1228                         *last = i;
1229                 }
1230         }
1231
1232         return m;
1233 }
1234
1235 TempoMetric
1236 TempoMap::metric_at (BBT_Time bbt) const
1237 {
1238         Glib::Threads::RWLock::ReaderLock lm (lock);
1239         TempoMetric m (first_meter(), first_tempo());
1240
1241         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1242            at something, because we insert the default tempo and meter during
1243            TempoMap construction.
1244
1245            now see if we can find better candidates.
1246         */
1247
1248         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1249
1250                 BBT_Time section_start ((*i)->start());
1251
1252                 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1253                         break;
1254                 }
1255
1256                 m.set_metric (*i);
1257         }
1258
1259         return m;
1260 }
1261
1262 void
1263 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1264 {
1265         Glib::Threads::RWLock::ReaderLock lm (lock);
1266
1267         if (frame < 0) {
1268                 bbt.bars = 1;
1269                 bbt.beats = 1;
1270                 bbt.ticks = 0;
1271                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1272                 return;
1273         }
1274         bbt = beats_to_bbt (beat_at_frame (frame));
1275 }
1276
1277 int32_t
1278 TempoMap::bars_in_meter_section (MeterSection* ms) const
1279 {
1280         /* YOU MUST HAVE THE READ LOCK */
1281         Metrics::const_iterator i;
1282
1283         MeterSection* next_ms = 0;
1284         const MeterSection* prev_ms = &first_meter();
1285
1286         for (i = metrics.begin(); i != metrics.end(); ++i) {
1287                 MeterSection* m;
1288                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1289                         if (ms->frame() < m->frame()) {
1290                                 next_ms = m;
1291                                 break;
1292                         }
1293                         prev_ms = m;
1294                 }
1295         }
1296         if (next_ms) {
1297                 double ticks_at_next = tick_at_frame (next_ms->frame());
1298                 double ticks_at_prev = tick_at_frame (prev_ms->frame());
1299                 double ticks_in_meter = ticks_at_next - ticks_at_prev;
1300
1301                 return (int32_t) floor ((ticks_in_meter / BBT_Time::ticks_per_beat) / prev_ms->note_divisor());
1302         }
1303         return -1;
1304 }
1305
1306 Timecode::BBT_Time
1307 TempoMap::beats_to_bbt (double beats)
1308 {
1309         /* CALLER HOLDS READ LOCK */
1310         BBT_Time ret;
1311         MeterSection* prev_ms = &first_meter();
1312
1313         framecnt_t frame = frame_at_beat (beats);
1314         uint32_t cnt = 0;
1315         /* XX most of this is utter crap */
1316         if (n_meters() == 1) {
1317                 uint32_t bars = (uint32_t) floor (beats / prev_ms->note_divisor());
1318                 double remaining_beats = beats - (bars *  prev_ms->note_divisor());
1319                 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1320
1321                 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1322                 ret.beats = (uint32_t) floor (remaining_beats);
1323                 ret.bars = bars;
1324
1325                 /* 0 0 0 to 1 1 0 - based mapping*/
1326                 ++ret.bars;
1327                 ++ret.beats;
1328
1329                 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1330                         ++ret.beats;
1331                         ret.ticks -= BBT_Time::ticks_per_beat;
1332                 }
1333
1334                 if (ret.beats > prev_ms->note_divisor()) {
1335                         ++ret.bars;
1336                         ret.beats = 1;
1337                 }
1338
1339                 return ret;
1340         }
1341
1342         uint32_t first_beat_in_meter = 0;
1343         uint32_t accumulated_bars = 0;
1344         Metrics::const_iterator i;
1345
1346         for (i = metrics.begin(); i != metrics.end(); ++i) {
1347                 MeterSection* m = 0;
1348
1349                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1350                         first_beat_in_meter = beat_at_frame (m->frame());
1351
1352                         if (beats < first_beat_in_meter) {
1353                                 /* this is the meter after the one our beat is on*/
1354                                 break;
1355                         }
1356                         int32_t const bars_in_ms = bars_in_meter_section (m);
1357
1358                         if (bars_in_ms > 0) {
1359                                 accumulated_bars += bars_in_ms;
1360                         }
1361
1362                         prev_ms = m;
1363                         ++cnt;
1364                 }
1365         }
1366         //cerr << "beats to bbr with beats = " << beats << " first_beat_in_meter =  " << first_beat_in_meter << " accumulated_bars = " << accumulated_bars <<  endl;
1367
1368         if (beats > first_beat_in_meter) {
1369                 /* prev_ms is the relevant one here */
1370
1371                 /* now get the ticks at frame */
1372                 double ticks_at_frame = tick_at_frame (frame);
1373
1374                 /* find the number of ticks at the beginning of the meter section (bar 1)*/
1375                 double ticks_at_ms = tick_at_frame (prev_ms->frame());
1376
1377                 double beats_used_by_ms = (ticks_at_frame - ticks_at_ms) / BBT_Time::ticks_per_beat;
1378
1379                 uint32_t bars = (uint32_t) floor (beats_used_by_ms / prev_ms->note_divisor());
1380                 double remaining_beats = beats_used_by_ms - (bars *  prev_ms->note_divisor());
1381                 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1382
1383                 ret.bars = bars + accumulated_bars;
1384                 ret.beats = (uint32_t) floor (remaining_beats);
1385                 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1386
1387                 /* now ensure we srtart at 1 1 0 */
1388                 ++ret.bars;
1389                 ++ret.beats;
1390                 //cerr << "part 1 ret bars = " << ret.bars << " ret beats = " << ret.beats << " ret ticks = " << ret.ticks << endl;
1391                 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1392                         ++ret.beats;
1393                         ret.ticks -= BBT_Time::ticks_per_beat;
1394                 }
1395
1396                 if (ret.beats > prev_ms->note_divisor()) {
1397                         ++ret.bars;
1398                         ret.beats = 1;
1399                 }
1400
1401                 return ret;
1402         }
1403
1404         /* find the number of ticks at the beginning of the meter section (bar 1)*/
1405         double ticks_at_ms = tick_at_frame (prev_ms->frame());
1406
1407         /* now get the ticks at frame */
1408         double ticks_at_frame = tick_at_frame (frame);
1409
1410         double ticks_within_ms = ticks_at_frame - ticks_at_ms;
1411
1412         ret.bars = (uint32_t) floor (((ticks_within_ms / BBT_Time::ticks_per_beat) / prev_ms->note_divisor())) + accumulated_bars;
1413         uint32_t remaining_ticks = ticks_within_ms - (ret.bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat);
1414         ret.beats = (uint32_t) floor (remaining_ticks);
1415         remaining_ticks -= ret.beats * BBT_Time::ticks_per_beat;
1416
1417         /* only round ticks */
1418         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1419
1420         /* now ensure we srtart at 1 1 0 */
1421         ++ret.bars;
1422         ++ret.beats;
1423         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1424                 ++ret.beats;
1425                 ret.ticks -= BBT_Time::ticks_per_beat;
1426         }
1427
1428         if (ret.beats > prev_ms->note_divisor()) {
1429                 ++ret.bars;
1430                 ret.beats = 1;
1431         }
1432
1433         return ret;
1434 }
1435
1436 double
1437 TempoMap::tick_at_frame (framecnt_t frame) const
1438 {
1439
1440         Metrics::const_iterator i;
1441         const TempoSection* prev_ts = &first_tempo();
1442         double accumulated_ticks = 0.0;
1443         uint32_t cnt = 0;
1444
1445         for (i = metrics.begin(); i != metrics.end(); ++i) {
1446                 TempoSection* t;
1447
1448                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1449
1450                         if (frame < t->frame()) {
1451                                 /*the previous ts is the one containing the frame */
1452
1453                                 framepos_t time = frame - prev_ts->frame();
1454                                 framepos_t last_frame = t->frame() - prev_ts->frame();
1455                                 double last_beats_per_minute = t->beats_per_minute();
1456
1457                                 return prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate) + accumulated_ticks;
1458                         }
1459
1460                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1461                                 framepos_t time = t->frame() - prev_ts->frame();
1462                                 framepos_t last_frame = t->frame() - prev_ts->frame();
1463                                 double last_beats_per_minute = t->beats_per_minute();
1464                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate);
1465                         }
1466
1467                         prev_ts = t;
1468                         ++cnt;
1469                 }
1470         }
1471
1472         /* treated s linear for this ts */
1473         framecnt_t frames_in_section = frame - prev_ts->frame();
1474         double ticks_in_section = (frames_in_section / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
1475
1476         return ticks_in_section + accumulated_ticks;
1477
1478 }
1479
1480 framecnt_t
1481 TempoMap::frame_at_tick (double tick) const
1482 {
1483         /* HOLD THE READER LOCK */
1484
1485         double accumulated_ticks = 0.0;
1486         double accumulated_ticks_to_prev = 0.0;
1487
1488         const TempoSection* prev_ts =  &first_tempo();
1489         uint32_t cnt = 0;
1490
1491         Metrics::const_iterator i;
1492
1493         for (i = metrics.begin(); i != metrics.end(); ++i) {
1494                 TempoSection* t;
1495                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1496
1497                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1498                                 framepos_t time = t->frame() - prev_ts->frame();
1499                                 framepos_t last_time = t->frame() - prev_ts->frame();
1500                                 double last_beats_per_minute = t->beats_per_minute();
1501                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1502                         }
1503
1504                         if (tick < accumulated_ticks) {
1505                                 /* prev_ts is the one affecting us. */
1506
1507                                 double ticks_in_section = tick - accumulated_ticks_to_prev;
1508                                 framepos_t section_start = prev_ts->frame();
1509                                 framepos_t last_time = t->frame() - prev_ts->frame();
1510                                 double last_beats_per_minute = t->beats_per_minute();
1511                                 return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start;
1512                         }
1513                         accumulated_ticks_to_prev = accumulated_ticks;
1514
1515                         prev_ts = t;
1516                         ++cnt;
1517                 }
1518         }
1519         double ticks_in_section = tick - accumulated_ticks_to_prev;
1520         double dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1521         framecnt_t ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1522
1523         return ret;
1524 }
1525
1526 double
1527 TempoMap::beat_at_frame (framecnt_t frame) const
1528 {
1529         Glib::Threads::RWLock::ReaderLock lm (lock);
1530
1531         return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
1532 }
1533
1534 framecnt_t
1535 TempoMap::frame_at_beat (double beat) const
1536 {
1537         Glib::Threads::RWLock::ReaderLock lm (lock);
1538
1539         return frame_at_tick (beat * BBT_Time::ticks_per_beat);
1540 }
1541
1542 framepos_t
1543 TempoMap::frame_time (const BBT_Time& bbt)
1544 {
1545         if (bbt.bars < 1) {
1546                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1547                 return 0;
1548         }
1549
1550         if (bbt.beats < 1) {
1551                 throw std::logic_error ("beats are counted from one");
1552         }
1553
1554         Glib::Threads::RWLock::ReaderLock lm (lock);
1555
1556         Metrics::const_iterator i;
1557         uint32_t accumulated_bars = 0;
1558
1559         MeterSection* prev_ms = &first_meter();
1560
1561         for (i = metrics.begin(); i != metrics.end(); ++i) {
1562                 MeterSection* m;
1563                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1564                         int32_t const bims = bars_in_meter_section (m);
1565
1566                         if (bims < 0 || bbt.bars <= (accumulated_bars + bims)) {
1567                                 break;
1568                         }
1569                         if (bims > 0 ) {
1570                                 accumulated_bars += bims;
1571                         }
1572                         prev_ms = m;
1573                 }
1574         }
1575
1576         uint32_t remaining_bars = bbt.bars - accumulated_bars - 1; // back to zero - based bars
1577         double const ticks_within_prev_taken_by_remaining_bars = remaining_bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat;
1578         double const ticks_after_space_used_by_bars = ((bbt.beats - 1) * BBT_Time::ticks_per_beat) + bbt.ticks; // back to zero - based beats
1579         double const ticks_target = ticks_within_prev_taken_by_remaining_bars + ticks_after_space_used_by_bars;
1580
1581         TempoSection* prev_ts = &first_tempo();
1582         double accumulated_ticks = 0.0;
1583         double accumulated_ticks_to_prev = 0.0;
1584
1585         uint32_t cnt = 0;
1586
1587         for (i = metrics.begin(); i != metrics.end(); ++i) {
1588                 TempoSection* t;
1589                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1590                         if (t->frame() < prev_ms->frame()) {
1591                                 continue;
1592                         }
1593
1594                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1595                                 /*find the number of ticke in this section */
1596                                 framepos_t const time = t->frame() - prev_ts->frame();
1597                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1598                                 double const last_beats_per_minute = t->beats_per_minute();
1599                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1600                         }
1601
1602                         if (ticks_target < accumulated_ticks) {
1603                                 double const ticks_in_section = ticks_target - accumulated_ticks_to_prev;
1604                                 framepos_t const section_start_time = prev_ts->frame();
1605                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1606                                 double const last_beats_per_minute = t->beats_per_minute();
1607                                 framepos_t const ret = prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start_time;
1608                                 return ret;
1609                         }
1610                         accumulated_ticks_to_prev = accumulated_ticks;
1611                         prev_ts = t;
1612                         ++cnt;
1613                 }
1614         }
1615
1616         /*treat this ts as constant tempo */
1617         double const ticks_in_this_ts = ticks_target - accumulated_ticks_to_prev;
1618         double const dtime = (ticks_in_this_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1619         framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1620         return ret;
1621 }
1622
1623
1624 framecnt_t
1625 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1626 {
1627
1628         Glib::Threads::RWLock::ReaderLock lm (lock);
1629
1630         Metrics::const_iterator i;
1631         TempoSection* first = 0;
1632         TempoSection* second = 0;
1633
1634         for (i = metrics.begin(); i != metrics.end(); ++i) {
1635                 TempoSection* t;
1636
1637                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1638
1639                         if ((*i)->frame() > pos) {
1640                                 second = t;
1641                                 break;
1642                         }
1643
1644                         first = t;
1645                 }
1646         }
1647         if (first && second) {
1648                 framepos_t const last_time = second->frame() - first->frame();
1649                 double const last_beats_per_minute = second->beats_per_minute();
1650
1651                 framepos_t const time = pos - first->frame();
1652                 double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1653                 double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1654
1655                 double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
1656
1657                 return time_at_bbt - time;
1658         }
1659
1660         double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1661         return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
1662 }
1663
1664 framepos_t
1665 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1666 {
1667         return round_to_type (fr, dir, Bar);
1668 }
1669
1670 framepos_t
1671 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1672 {
1673         return round_to_type (fr, dir, Beat);
1674 }
1675
1676 framepos_t
1677 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1678 {
1679         Glib::Threads::RWLock::ReaderLock lm (lock);
1680
1681         uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
1682         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
1683         uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1684
1685         ticks -= beats * BBT_Time::ticks_per_beat;
1686
1687         if (dir > 0) {
1688                 /* round to next (or same iff dir == RoundUpMaybe) */
1689
1690                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
1691
1692                 if (mod == 0 && dir == RoundUpMaybe) {
1693                         /* right on the subdivision, which is fine, so do nothing */
1694
1695                 } else if (mod == 0) {
1696                         /* right on the subdivision, so the difference is just the subdivision ticks */
1697                         ticks += ticks_one_subdivisions_worth;
1698
1699                 } else {
1700                         /* not on subdivision, compute distance to next subdivision */
1701
1702                         ticks += ticks_one_subdivisions_worth - mod;
1703                 }
1704
1705                 if (ticks >= BBT_Time::ticks_per_beat) {
1706                         ticks -= BBT_Time::ticks_per_beat;
1707                 }
1708         } else if (dir < 0) {
1709
1710                 /* round to previous (or same iff dir == RoundDownMaybe) */
1711
1712                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
1713
1714                 if (difference == 0 && dir == RoundDownAlways) {
1715                         /* right on the subdivision, but force-rounding down,
1716                            so the difference is just the subdivision ticks */
1717                         difference = ticks_one_subdivisions_worth;
1718                 }
1719
1720                 if (ticks < difference) {
1721                         ticks = BBT_Time::ticks_per_beat - ticks;
1722                 } else {
1723                         ticks -= difference;
1724                 }
1725
1726         } else {
1727                 /* round to nearest */
1728                 double rem;
1729
1730                 /* compute the distance to the previous and next subdivision */
1731
1732                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1733
1734                         /* closer to the next subdivision, so shift forward */
1735
1736                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
1737
1738                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
1739
1740                         if (ticks > BBT_Time::ticks_per_beat) {
1741                                 ++beats;
1742                                 ticks -= BBT_Time::ticks_per_beat;
1743                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
1744                         }
1745
1746                 } else if (rem > 0) {
1747
1748                         /* closer to previous subdivision, so shift backward */
1749
1750                         if (rem > ticks) {
1751                                 if (beats == 0) {
1752                                         /* can't go backwards past zero, so ... */
1753                                         return 0;
1754                                 }
1755                                 /* step back to previous beat */
1756                                 --beats;
1757                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
1758                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
1759                         } else {
1760                                 ticks = lrint (ticks - rem);
1761                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
1762                         }
1763                 } else {
1764                         /* on the subdivision, do nothing */
1765                 }
1766         }
1767         return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
1768 }
1769
1770 framepos_t
1771 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1772 {
1773         Glib::Threads::RWLock::ReaderLock lm (lock);
1774
1775         double const beat_at_framepos = beat_at_frame (frame);
1776
1777         BBT_Time bbt (beats_to_bbt (beat_at_framepos));
1778
1779         switch (type) {
1780         case Bar:
1781                 if (dir < 0) {
1782                         /* find bar previous to 'frame' */
1783                         bbt.beats = 1;
1784                         bbt.ticks = 0;
1785                         return frame_time (bbt);
1786
1787                 } else if (dir > 0) {
1788                         /* find bar following 'frame' */
1789                         ++bbt.bars;
1790                         bbt.beats = 1;
1791                         bbt.ticks = 0;
1792                         return frame_time (bbt);
1793                 } else {
1794                         /* true rounding: find nearest bar */
1795                         framepos_t raw_ft = frame_time (bbt);
1796                         bbt.beats = 1;
1797                         bbt.ticks = 0;
1798                         framepos_t prev_ft = frame_time (bbt);
1799                         ++bbt.bars;
1800                         framepos_t next_ft = frame_time (bbt);
1801
1802                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
1803                                 return next_ft;
1804                         } else {
1805                                 return prev_ft;
1806                         }
1807                 }
1808
1809                 break;
1810
1811         case Beat:
1812                 if (dir < 0) {
1813                         return frame_at_beat (floor (beat_at_framepos));
1814                 } else if (dir > 0) {
1815                         return frame_at_beat (ceil (beat_at_framepos));
1816                 } else {
1817                         return frame_at_beat (floor (beat_at_framepos + 0.5));
1818                 }
1819                 break;
1820         }
1821
1822         return 0;
1823 }
1824
1825 void
1826 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
1827                     framepos_t lower, framepos_t upper)
1828 {
1829         Glib::Threads::RWLock::ReaderLock lm (lock);
1830         uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
1831         uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
1832
1833         while (cnt <= upper_beat) {
1834                 framecnt_t const pos = frame_at_beat (cnt);
1835                 MeterSection const meter = meter_section_at (pos);
1836                 Tempo const tempo = tempo_at (pos);
1837                 BBT_Time const bbt = beats_to_bbt ((double) cnt);
1838
1839                 points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
1840                 ++cnt;
1841         }
1842 }
1843
1844 TempoSection*
1845 TempoMap::tempo_section_after (framepos_t frame) const
1846 {
1847         Glib::Threads::RWLock::ReaderLock lm (lock);
1848
1849         Metrics::const_iterator i;
1850         TempoSection* next = 0;
1851
1852         for (i = metrics.begin(); i != metrics.end(); ++i) {
1853                 TempoSection* t;
1854
1855                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1856
1857                         if ((*i)->frame() > frame) {
1858                                 next = t;
1859                                 break;
1860                         }
1861                 }
1862         }
1863
1864         return next;
1865 }
1866
1867
1868 const TempoSection&
1869 TempoMap::tempo_section_at (framepos_t frame) const
1870 {
1871         Glib::Threads::RWLock::ReaderLock lm (lock);
1872
1873         Metrics::const_iterator i;
1874         TempoSection* prev = 0;
1875
1876         for (i = metrics.begin(); i != metrics.end(); ++i) {
1877                 TempoSection* t;
1878
1879                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1880
1881                         if ((*i)->frame() > frame) {
1882                                 break;
1883                         }
1884
1885                         prev = t;
1886                 }
1887         }
1888
1889         if (prev == 0) {
1890                 fatal << endmsg;
1891                 abort(); /*NOTREACHED*/
1892         }
1893
1894         return *prev;
1895 }
1896
1897 /* don't use this to calculate length (the tempo is only correct for this frame).
1898    do that stuff based on the beat_at_frame and frame_at_beat api
1899 */
1900 double
1901 TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
1902 {
1903         Glib::Threads::RWLock::ReaderLock lm (lock);
1904
1905         const TempoSection* ts_at = &tempo_section_at (frame);
1906         const TempoSection* ts_after = tempo_section_after (frame);
1907
1908         if (ts_after) {
1909                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
1910         }
1911         /* must be treated as constant tempo */
1912         return ts_at->frames_per_beat (_frame_rate);
1913 }
1914
1915 const Tempo
1916 TempoMap::tempo_at (framepos_t frame) const
1917 {
1918         Glib::Threads::RWLock::ReaderLock lm (lock);
1919
1920         TempoMetric m (metric_at (frame));
1921         TempoSection* prev_ts = 0;
1922
1923         Metrics::const_iterator i;
1924
1925         for (i = metrics.begin(); i != metrics.end(); ++i) {
1926                 TempoSection* t;
1927                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1928                         if ((prev_ts) && t->frame() > frame) {
1929                                 /* this is the one past frame */
1930                                 framepos_t const time = frame - prev_ts->frame();
1931                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1932                                 double const last_beats_per_minute = t->beats_per_minute();
1933                                 double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1934                                 Tempo const ret_tempo (ret, m.tempo().note_type ());
1935                                 return ret_tempo;
1936                         }
1937                         prev_ts = t;
1938                 }
1939         }
1940
1941         return m.tempo();
1942
1943 }
1944
1945 const MeterSection&
1946 TempoMap::meter_section_at (framepos_t frame) const
1947 {
1948         Glib::Threads::RWLock::ReaderLock lm (lock);
1949         Metrics::const_iterator i;
1950         MeterSection* prev = 0;
1951
1952         for (i = metrics.begin(); i != metrics.end(); ++i) {
1953                 MeterSection* t;
1954
1955                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1956
1957                         if ((*i)->frame() > frame) {
1958                                 break;
1959                         }
1960
1961                         prev = t;
1962                 }
1963         }
1964
1965         if (prev == 0) {
1966                 fatal << endmsg;
1967                 abort(); /*NOTREACHED*/
1968         }
1969
1970         return *prev;
1971 }
1972
1973 const Meter&
1974 TempoMap::meter_at (framepos_t frame) const
1975 {
1976         TempoMetric m (metric_at (frame));
1977         return m.meter();
1978 }
1979
1980 XMLNode&
1981 TempoMap::get_state ()
1982 {
1983         Metrics::const_iterator i;
1984         XMLNode *root = new XMLNode ("TempoMap");
1985
1986         {
1987                 Glib::Threads::RWLock::ReaderLock lm (lock);
1988                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1989                         root->add_child_nocopy ((*i)->get_state());
1990                 }
1991         }
1992
1993         return *root;
1994 }
1995
1996 int
1997 TempoMap::set_state (const XMLNode& node, int /*version*/)
1998 {
1999         {
2000                 Glib::Threads::RWLock::WriterLock lm (lock);
2001
2002                 XMLNodeList nlist;
2003                 XMLNodeConstIterator niter;
2004                 Metrics old_metrics (metrics);
2005                 MeterSection* last_meter = 0;
2006                 metrics.clear();
2007
2008                 nlist = node.children();
2009
2010                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2011                         XMLNode* child = *niter;
2012
2013                         if (child->name() == TempoSection::xml_state_node_name) {
2014
2015                                 try {
2016                                         TempoSection* ts = new TempoSection (*child);
2017                                         metrics.push_back (ts);
2018
2019                                         if (ts->bar_offset() < 0.0) {
2020                                                 if (last_meter) {
2021                                                         //ts->update_bar_offset_from_bbt (*last_meter);
2022                                                 }
2023                                         }
2024                                 }
2025
2026                                 catch (failed_constructor& err){
2027                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2028                                         metrics = old_metrics;
2029                                         break;
2030                                 }
2031
2032                         } else if (child->name() == MeterSection::xml_state_node_name) {
2033
2034                                 try {
2035                                         MeterSection* ms = new MeterSection (*child);
2036                                         metrics.push_back (ms);
2037                                         last_meter = ms;
2038                                 }
2039
2040                                 catch (failed_constructor& err) {
2041                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2042                                         metrics = old_metrics;
2043                                         break;
2044                                 }
2045                         }
2046                 }
2047
2048                 if (niter == nlist.end()) {
2049                         MetricSectionSorter cmp;
2050                         metrics.sort (cmp);
2051                 }
2052
2053                 /* check for multiple tempo/meters at the same location, which
2054                    ardour2 somehow allowed.
2055                 */
2056
2057                 Metrics::iterator prev = metrics.end();
2058                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2059                         if (prev != metrics.end()) {
2060                                 if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
2061                                         if ((*prev)->start() == (*i)->start()) {
2062                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
2063                                                 error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
2064                                                 return -1;
2065                                         }
2066                                 } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
2067                                         if ((*prev)->start() == (*i)->start()) {
2068                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
2069                                                 error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
2070                                                 return -1;
2071                                         }
2072                                 }
2073                         }
2074                         prev = i;
2075                 }
2076
2077                 recompute_map (true, -1);
2078         }
2079
2080         PropertyChanged (PropertyChange ());
2081
2082         return 0;
2083 }
2084
2085 void
2086 TempoMap::dump (std::ostream& o) const
2087 {
2088         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2089         const MeterSection* m;
2090         const TempoSection* t;
2091
2092         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2093
2094                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2095                         o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (movable? "
2096                           << t->movable() << ')' << endl;
2097                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2098                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
2099                           << " (movable? " << m->movable() << ')' << endl;
2100                 }
2101         }
2102 }
2103
2104 int
2105 TempoMap::n_tempos() const
2106 {
2107         Glib::Threads::RWLock::ReaderLock lm (lock);
2108         int cnt = 0;
2109
2110         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2111                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2112                         cnt++;
2113                 }
2114         }
2115
2116         return cnt;
2117 }
2118
2119 int
2120 TempoMap::n_meters() const
2121 {
2122         Glib::Threads::RWLock::ReaderLock lm (lock);
2123         int cnt = 0;
2124
2125         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2126                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2127                         cnt++;
2128                 }
2129         }
2130
2131         return cnt;
2132 }
2133
2134 void
2135 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2136 {
2137         {
2138                 Glib::Threads::RWLock::WriterLock lm (lock);
2139                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2140                         if ((*i)->frame() >= where && (*i)->movable ()) {
2141                                 (*i)->set_frame ((*i)->frame() + amount);
2142                         }
2143                 }
2144
2145                 /* now reset the BBT time of all metrics, based on their new
2146                  * audio time. This is the only place where we do this reverse
2147                  * timestamp.
2148                  */
2149
2150                 Metrics::iterator i;
2151                 const MeterSection* meter;
2152                 const TempoSection* tempo;
2153                 MeterSection *m;
2154                 TempoSection *t;
2155
2156                 meter = &first_meter ();
2157                 tempo = &first_tempo ();
2158
2159                 BBT_Time start;
2160                 BBT_Time end;
2161
2162                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2163
2164                 bool first = true;
2165                 MetricSection* prev = 0;
2166
2167                 for (i = metrics.begin(); i != metrics.end(); ++i) {
2168
2169                         BBT_Time bbt;
2170                         TempoMetric metric (*meter, *tempo);
2171
2172                         if (prev) {
2173                                 metric.set_start (prev->start());
2174                                 metric.set_frame (prev->frame());
2175                         } else {
2176                                 // metric will be at frames=0 bbt=1|1|0 by default
2177                                 // which is correct for our purpose
2178                         }
2179
2180                         bbt_time ((*i)->frame(), bbt);
2181
2182                         // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
2183
2184                         if (first) {
2185                                 first = false;
2186                         } else {
2187
2188                                 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2189                                         /* round up to next beat */
2190                                         bbt.beats += 1;
2191                                 }
2192
2193                                 bbt.ticks = 0;
2194
2195                                 if (bbt.beats != 1) {
2196                                         /* round up to next bar */
2197                                         bbt.bars += 1;
2198                                         bbt.beats = 1;
2199                                 }
2200                         }
2201
2202                         // cerr << bbt << endl;
2203
2204                         (*i)->set_start (bbt);
2205
2206                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2207                                 tempo = t;
2208                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2209                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2210                                 meter = m;
2211                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2212                         } else {
2213                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2214                                 abort(); /*NOTREACHED*/
2215                         }
2216
2217                         prev = (*i);
2218                 }
2219
2220                 recompute_map (true);
2221         }
2222
2223
2224         PropertyChanged (PropertyChange ());
2225 }
2226 bool
2227 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2228 {
2229         bool moved = false;
2230
2231         std::list<MetricSection*> metric_kill_list;
2232
2233         TempoSection* last_tempo = NULL;
2234         MeterSection* last_meter = NULL;
2235         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2236         bool meter_after = false; // is there a meter marker likewise?
2237         {
2238                 Glib::Threads::RWLock::WriterLock lm (lock);
2239                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2240                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2241                                 metric_kill_list.push_back(*i);
2242                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2243                                 if (lt)
2244                                         last_tempo = lt;
2245                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2246                                 if (lm)
2247                                         last_meter = lm;
2248                         }
2249                         else if ((*i)->frame() >= where) {
2250                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2251                                 (*i)->set_frame ((*i)->frame() - amount);
2252                                 if ((*i)->frame() == where) {
2253                                         // marker was immediately after end of range
2254                                         tempo_after = dynamic_cast<TempoSection*> (*i);
2255                                         meter_after = dynamic_cast<MeterSection*> (*i);
2256                                 }
2257                                 moved = true;
2258                         }
2259                 }
2260
2261                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2262                 if (last_tempo && !tempo_after) {
2263                         metric_kill_list.remove(last_tempo);
2264                         last_tempo->set_frame(where);
2265                         moved = true;
2266                 }
2267                 if (last_meter && !meter_after) {
2268                         metric_kill_list.remove(last_meter);
2269                         last_meter->set_frame(where);
2270                         moved = true;
2271                 }
2272
2273                 //remove all the remaining metrics
2274                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2275                         metrics.remove(*i);
2276                         moved = true;
2277                 }
2278
2279                 if (moved) {
2280                         recompute_map (true);
2281                 }
2282         }
2283         PropertyChanged (PropertyChange ());
2284         return moved;
2285 }
2286
2287 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2288  *  pos can be -ve, if required.
2289  */
2290 framepos_t
2291 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2292 {
2293         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2294 }
2295
2296 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2297 framepos_t
2298 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2299 {
2300         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2301 }
2302
2303 /** Add the BBT interval op to pos and return the result */
2304 framepos_t
2305 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2306 {
2307         cerr << "framepos_plus_bbt - untested" << endl;
2308         Glib::Threads::RWLock::ReaderLock lm (lock);
2309
2310         Metrics::const_iterator i;
2311         const MeterSection* meter;
2312         const MeterSection* m;
2313         const TempoSection* tempo;
2314         const TempoSection* next_tempo = 0;
2315         const TempoSection* t;
2316         double frames_per_beat;
2317         framepos_t effective_pos = max (pos, (framepos_t) 0);
2318
2319         meter = &first_meter ();
2320         tempo = &first_tempo ();
2321
2322         assert (meter);
2323         assert (tempo);
2324
2325         /* find the starting metrics for tempo & meter */
2326
2327         for (i = metrics.begin(); i != metrics.end(); ++i) {
2328
2329                 if ((*i)->frame() > effective_pos) {
2330                         break;
2331                 }
2332
2333                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2334                         tempo = t;
2335                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2336                         meter = m;
2337                 }
2338         }
2339
2340         for (i = metrics.begin(); i != metrics.end(); ++i) {
2341                 if ((*i)->frame() > effective_pos) {
2342                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2343                                 next_tempo = t;
2344                         }
2345                         break;
2346                 }
2347         }
2348
2349         /* We now have:
2350
2351            meter -> the Meter for "pos"
2352            tempo -> the Tempo for "pos"
2353            next_tempo -> the Tempo after "pos" or 0
2354            i     -> for first new metric after "pos", possibly metrics.end()
2355         */
2356
2357         /* now comes the complicated part. we have to add one beat a time,
2358            checking for a new metric on every beat.
2359         */
2360
2361         uint64_t bars = 0;
2362         /* fpb is used for constant tempo */
2363         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2364
2365         while (op.bars) {
2366
2367                 bars++;
2368                 op.bars--;
2369
2370                 /* check if we need to use a new metric section: has adding frames moved us
2371                    to or after the start of the next metric section? in which case, use it.
2372                 */
2373
2374                 if (i != metrics.end()) {
2375                         if ((*i)->frame() <= pos) {
2376
2377                                 /* about to change tempo or meter, so add the
2378                                  * number of frames for the bars we've just
2379                                  * traversed before we change the
2380                                  * frames_per_beat value.
2381                                  */
2382
2383                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2384                                         next_tempo = t;
2385                                 }
2386
2387                                 if (next_tempo) {
2388                                         pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2389                                 } else {
2390                                         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2391                                 }
2392
2393                                 bars = 0;
2394
2395                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2396                                         tempo = t;
2397                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2398                                         meter = m;
2399                                 }
2400                                 ++i;
2401                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2402                         }
2403                 }
2404
2405         }
2406
2407         if (next_tempo) {
2408                 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2409         } else {
2410                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2411         }
2412
2413         uint64_t beats = 0;
2414
2415         while (op.beats) {
2416
2417                 /* given the current meter, have we gone past the end of the bar ? */
2418
2419                 beats++;
2420                 op.beats--;
2421
2422                 /* check if we need to use a new metric section: has adding frames moved us
2423                    to or after the start of the next metric section? in which case, use it.
2424                 */
2425
2426                 if (i != metrics.end()) {
2427                         if ((*i)->frame() <= pos) {
2428
2429                                 /* about to change tempo or meter, so add the
2430                                  * number of frames for the beats we've just
2431                                  * traversed before we change the
2432                                  * frames_per_beat value.
2433                                  */
2434
2435                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2436                                         next_tempo = t;
2437                                 }
2438
2439                                 if (next_tempo) {
2440                                         pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2441                                 } else {
2442                                         pos += llrint (beats * frames_per_beat);
2443                                 }
2444
2445                                 beats = 0;
2446
2447                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2448                                         tempo = t;
2449                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2450                                         meter = m;
2451                                 }
2452                                 ++i;
2453                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2454                         }
2455                 }
2456         }
2457
2458         if (next_tempo) {
2459                 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2460         } else {
2461                 pos += llrint (beats * frames_per_beat);
2462         }
2463
2464         if (op.ticks) {
2465                 pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2466         }
2467
2468         return pos;
2469
2470 }
2471
2472 /** Count the number of beats that are equivalent to distance when going forward,
2473     starting at pos.
2474 */
2475 Evoral::Beats
2476 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2477 {
2478         return Evoral::Beats(beat_at_frame (pos + distance) - beat_at_frame (pos));
2479 }
2480
2481 struct bbtcmp {
2482     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2483             return a < b;
2484     }
2485 };
2486
2487 std::ostream&
2488 operator<< (std::ostream& o, const Meter& m) {
2489         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2490 }
2491
2492 std::ostream&
2493 operator<< (std::ostream& o, const Tempo& t) {
2494         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2495 }
2496
2497 std::ostream&
2498 operator<< (std::ostream& o, const MetricSection& section) {
2499
2500         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2501
2502         const TempoSection* ts;
2503         const MeterSection* ms;
2504
2505         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2506                 o << *((const Tempo*) ts);
2507         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2508                 o << *((const Meter*) ms);
2509         }
2510
2511         return o;
2512 }