along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
#include <sigc++/bind.h>
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
#include <pbd/xml++.h>
#include <ardour/tempo.h>
#include <ardour/utils.h>
using namespace std;
using namespace ARDOUR;
+using namespace PBD;
/* _default tempo is 4/4 qtr=120 */
const double Meter::ticks_per_beat = 1920.0;
+double Tempo::frames_per_beat (nframes_t sr, const Meter& meter) const
+{
+ return ((60.0 * sr) / (_beats_per_minute * meter.note_divisor()/_note_type));
+}
+
/***********************************************************************/
double
-Meter::frames_per_bar (const Tempo& tempo, jack_nframes_t sr) const
+Meter::frames_per_bar (const Tempo& tempo, nframes_t sr) const
{
- return ((60.0 * sr * _beats_per_bar) / tempo.beats_per_minute());
+ return ((60.0 * sr * _beats_per_bar) / (tempo.beats_per_minute() * _note_type/tempo.note_type()));
}
/***********************************************************************/
error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
throw failed_constructor();
}
+
+ if ((prop = node.property ("note-type")) == 0) {
+ /* older session, make note type be quarter by default */
+ _note_type = 4.0;
+ } else {
+ if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
+ error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
+ throw failed_constructor();
+ }
+ }
if ((prop = node.property ("movable")) == 0) {
error << _("TempoSection XML node has no \"movable\" property") << endmsg;
root->add_property ("start", buf);
snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
root->add_property ("beats-per-minute", buf);
+ snprintf (buf, sizeof (buf), "%f", _note_type);
+ root->add_property ("note-type", buf);
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
root->add_property ("movable", buf);
}
};
-TempoMap::TempoMap (jack_nframes_t fr)
+TempoMap::TempoMap (nframes_t fr)
{
metrics = new Metrics;
_frame_rate = fr;
last_bbt_valid = false;
BBT_Time start;
- in_set_state = false;
start.bars = 1;
start.beats = 1;
start.ticks = 0;
- TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute());
+ TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
MeterSection *m = new MeterSection (start, _default_meter.beats_per_bar(), _default_meter.note_divisor());
t->set_movable (false);
metrics->push_back (t);
metrics->push_back (m);
-
- save_state (_("initial"));
}
TempoMap::~TempoMap ()
return 1;
}
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
MetricSectionSorter cmp;
BBT_Time corrected (when);
section.set_start (corrected);
metrics->sort (cmp);
- timestamp_metrics ();
- save_state (_("move metric"));
+ timestamp_metrics (true);
return 0;
}
TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
{
if (move_metric_section (tempo, when) == 0) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
{
if (move_metric_section (meter, when) == 0) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
bool removed = false;
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
}
if (removed) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
bool removed = false;
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
}
}
}
-
- if (removed) {
- save_state (_("metric removed"));
- }
}
if (removed) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
void
-TempoMap::do_insert (MetricSection* section)
+TempoMap::do_insert (MetricSection* section, bool with_bbt)
{
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
- if ((*i)->start() < section->start()) {
- continue;
+ if (with_bbt) {
+ if ((*i)->start() < section->start()) {
+ continue;
+ }
+ } else {
+ if ((*i)->frame() < section->frame()) {
+ continue;
+ }
}
-
+
metrics->insert (i, section);
break;
}
metrics->insert (metrics->end(), section);
}
- timestamp_metrics ();
+ timestamp_metrics (with_bbt);
}
void
TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
{
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
/* new tempos always start on a beat */
where.ticks = 0;
- do_insert (new TempoSection (where, tempo.beats_per_minute()));
+ do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true);
+ }
+
+ StateChanged (Change (0));
+}
- save_state (_("add tempo"));
+void
+TempoMap::add_tempo (const Tempo& tempo, nframes_t where)
+{
+ {
+ Glib::RWLock::WriterLock lm (lock);
+ do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false);
}
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
void
bool replaced = false;
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
*((Tempo *) ts) = replacement;
replaced = true;
- timestamp_metrics ();
+ timestamp_metrics (true);
break;
}
}
-
- if (replaced) {
- save_state (_("replace tempo"));
- }
}
if (replaced) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
TempoMap::add_meter (const Meter& meter, BBT_Time where)
{
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
/* a new meter always starts a new bar on the first beat. so
round the start time appropriately. remember that
where.ticks = 0;
- do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()));
+ do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), true);
+ }
+
+ StateChanged (Change (0));
+}
- save_state (_("add meter"));
+void
+TempoMap::add_meter (const Meter& meter, nframes_t where)
+{
+ {
+ Glib::RWLock::WriterLock lm (lock);
+ do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), false);
}
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
void
bool replaced = false;
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
*((Meter*) ms) = replacement;
replaced = true;
- timestamp_metrics ();
+ timestamp_metrics (true);
break;
}
}
-
- if (replaced) {
- save_state (_("replaced meter"));
- }
}
if (replaced) {
- send_state_changed (Change (0));
+ StateChanged (Change (0));
}
}
+void
+TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type)
+{
+ Tempo newtempo (beats_per_minute, note_type);
+
+ TempoSection* prev;
+ TempoSection* first;
+ Metrics::iterator i;
+
+ /* find the TempoSection immediately preceding "where"
+ */
+
+ for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
+
+ if ((*i)->frame() > where) {
+ break;
+ }
+
+ TempoSection* t;
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ if (!first) {
+ first = t;
+ }
+ prev = t;
+ }
+ }
+
+ if (!prev) {
+ if (!first) {
+ error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
+ return;
+ }
+
+ prev = first;
+ }
+
+ /* reset */
+
+ *((Tempo*)prev) = newtempo;
+ StateChanged (Change (0));
+}
+
const MeterSection&
TempoMap::first_meter () const
{
}
void
-TempoMap::timestamp_metrics ()
+TempoMap::timestamp_metrics (bool use_bbt)
{
Metrics::iterator i;
const Meter* meter;
const Tempo* tempo;
Meter *m;
Tempo *t;
- jack_nframes_t current;
- jack_nframes_t section_frames;
- BBT_Time start;
- BBT_Time end;
meter = &first_meter ();
tempo = &first_tempo ();
- current = 0;
- for (i = metrics->begin(); i != metrics->end(); ++i) {
-
- end = (*i)->start();
+ if (use_bbt) {
- section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
+ nframes_t current = 0;
+ nframes_t section_frames;
+ BBT_Time start;
+ BBT_Time end;
- current += section_frames;
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+
+ end = (*i)->start();
+
+ section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
+
+ current += section_frames;
+
+ start = end;
+
+ (*i)->set_frame (current);
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+ meter = m;
+ } else {
+ fatal << _("programming error: unhandled MetricSection type") << endmsg;
+ /*NOTREACHED*/
+ }
+ }
- start = end;
+ } else {
- (*i)->set_frame (current);
+ bool first = true;
- if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
- meter = m;
- } else {
- fatal << _("programming error: unhandled MetricSection type") << endmsg;
- /*NOTREACHED*/
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+
+ BBT_Time bbt;
+
+ bbt_time_with_metric ((*i)->frame(), bbt, Metric (*meter, *tempo));
+
+ // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
+
+ if (first) {
+ first = false;
+ } else {
+ if (bbt.beats != 1 || bbt.ticks != 0) {
+ bbt.bars += 1;
+ bbt.beats = 1;
+ bbt.ticks = 0;
+ }
+ }
+
+ // cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl;
+
+ (*i)->set_start (bbt);
+
+ if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+ meter = m;
+ } else {
+ fatal << _("programming error: unhandled MetricSection type") << endmsg;
+ /*NOTREACHED*/
+ }
}
}
+
+ // dump (cerr);
}
TempoMap::Metric
-TempoMap::metric_at (jack_nframes_t frame) const
+TempoMap::metric_at (nframes_t frame) const
{
Metric m (first_meter(), first_tempo());
const Meter* meter;
}
void
-TempoMap::bbt_time (jack_nframes_t frame, BBT_Time& bbt) const
+TempoMap::bbt_time (nframes_t frame, BBT_Time& bbt) const
{
- LockMonitor lm (lock, __LINE__, __FILE__);
- bbt_time_unlocked (frame, bbt);
+ {
+ Glib::RWLock::ReaderLock lm (lock);
+ bbt_time_unlocked (frame, bbt);
+ }
}
void
-TempoMap::bbt_time_unlocked (jack_nframes_t frame, BBT_Time& bbt) const
+TempoMap::bbt_time_unlocked (nframes_t frame, BBT_Time& bbt) const
{
bbt_time_with_metric (frame, bbt, metric_at (frame));
}
void
-TempoMap::bbt_time_with_metric (jack_nframes_t frame, BBT_Time& bbt, const Metric& metric) const
+TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& metric) const
{
- jack_nframes_t frame_diff;
+ nframes_t frame_diff;
uint32_t xtra_bars = 0;
double xtra_beats = 0;
const double beats_per_bar = metric.meter().beats_per_bar();
const double frames_per_bar = metric.meter().frames_per_bar (metric.tempo(), _frame_rate);
- const double beat_frames = metric.tempo().frames_per_beat (_frame_rate);
+ const double beat_frames = metric.tempo().frames_per_beat (_frame_rate, metric.meter());
/* now compute how far beyond that point we actually are. */
}
-jack_nframes_t
+nframes_t
TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const
{
-
- /* for this to work with fractional measure types, start and end have to "legal" BBT types,
- that means that the beats and ticks should be inside a bar
+ /* for this to work with fractional measure types, start and end have to be "legal" BBT types,
+ that means that the beats and ticks should be inside a bar
*/
+ nframes_t frames = 0;
+ nframes_t start_frame = 0;
+ nframes_t end_frame = 0;
- jack_nframes_t frames = 0;
- jack_nframes_t start_frame = 0;
- jack_nframes_t end_frame = 0;
-
- Metric m = metric_at(start);
+ Metric m = metric_at (start);
uint32_t bar_offset = start.bars - m.start().bars;
+ start.ticks/Meter::ticks_per_beat;
- start_frame = m.frame() + (jack_nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate));
+ start_frame = m.frame() + (nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
m = metric_at(end);
beat_offset = bar_offset * m.meter().beats_per_bar() - (m.start().beats -1) + (end.beats - 1)
+ end.ticks/Meter::ticks_per_beat;
- end_frame = m.frame() + (jack_nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate));
+ end_frame = m.frame() + (nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
frames = end_frame - start_frame;
}
-jack_nframes_t
+nframes_t
TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
{
/*this is used in timestamping the metrics by actually counting the beats */
- jack_nframes_t frames = 0;
+ nframes_t frames = 0;
uint32_t bar = start.bars;
double beat = (double) start.beats;
double beats_counted = 0;
double beat_frames = 0;
beats_per_bar = meter.beats_per_bar();
- beat_frames = tempo.frames_per_beat (_frame_rate);
+ beat_frames = tempo.frames_per_beat (_frame_rate,meter);
frames = 0;
}
}
- frames = (jack_nframes_t) floor (beats_counted * beat_frames);
+ frames = (nframes_t) floor (beats_counted * beat_frames);
return frames;
}
-jack_nframes_t
+nframes_t
TempoMap::frame_time (const BBT_Time& bbt) const
{
BBT_Time start ; /* 1|1|0 */
return count_frames_between ( start, bbt);
}
-jack_nframes_t
-TempoMap::bbt_duration_at (jack_nframes_t pos, const BBT_Time& bbt, int dir) const
+nframes_t
+TempoMap::bbt_duration_at (nframes_t pos, const BBT_Time& bbt, int dir) const
{
- jack_nframes_t frames = 0;
+ nframes_t frames = 0;
BBT_Time when;
bbt_time(pos,when);
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::ReaderLock lm (lock);
frames = bbt_duration_at_unlocked (when, bbt,dir);
}
return frames;
}
-jack_nframes_t
+nframes_t
TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
{
- jack_nframes_t frames = 0;
+ nframes_t frames = 0;
double beats_per_bar;
BBT_Time result;
-jack_nframes_t
-
-TempoMap::round_to_bar (jack_nframes_t fr, int dir)
+nframes_t
+TempoMap::round_to_bar (nframes_t fr, int dir)
{
- LockMonitor lm (lock, __LINE__, __FILE__);
- return round_to_type (fr, dir, Bar);
+ {
+ Glib::RWLock::ReaderLock lm (lock);
+ return round_to_type (fr, dir, Bar);
+ }
}
-jack_nframes_t
-
-TempoMap::round_to_beat (jack_nframes_t fr, int dir)
+nframes_t
+TempoMap::round_to_beat (nframes_t fr, int dir)
{
- LockMonitor lm (lock, __LINE__, __FILE__);
- return round_to_type (fr, dir, Beat);
+ {
+ Glib::RWLock::ReaderLock lm (lock);
+ return round_to_type (fr, dir, Beat);
+ }
}
-jack_nframes_t
+nframes_t
-TempoMap::round_to_beat_subdivision (jack_nframes_t fr, int sub_num)
+TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
{
- LockMonitor lm (lock, __LINE__, __FILE__);
- TempoMap::BBTPointList::iterator i;
- TempoMap::BBTPointList *more_zoomed_bbt_points;
- jack_nframes_t frame_one_beats_worth;
- jack_nframes_t pos = 0;
- jack_nframes_t next_pos = 0 ;
- double tempo = 1;
- double frames_one_subdivisions_worth;
- bool fr_has_changed = false;
-
- int n;
-
- frame_one_beats_worth = (jack_nframes_t) ::floor ((double) _frame_rate * 60 / 20 ); //one beat @ 20 bpm
- more_zoomed_bbt_points = get_points((fr >= frame_one_beats_worth) ?
- fr - frame_one_beats_worth : 0, fr+frame_one_beats_worth );
-
- if (more_zoomed_bbt_points == 0 || more_zoomed_bbt_points->empty()) {
- return fr;
- }
- for (i = more_zoomed_bbt_points->begin(); i != more_zoomed_bbt_points->end(); i++) {
- if ((*i).frame <= fr) {
- pos = (*i).frame;
- tempo = (*i).tempo->beats_per_minute();
-
- } else {
- i++;
- next_pos = (*i).frame;
- break;
- }
- }
- frames_one_subdivisions_worth = ((double) _frame_rate * 60 / (sub_num * tempo));
-
- for (n = sub_num; n > 0; n--) {
- if (fr >= (pos + ((n - 0.5) * frames_one_subdivisions_worth))) {
- fr = (jack_nframes_t) round(pos + (n * frames_one_subdivisions_worth));
- if (fr > next_pos) {
- fr = next_pos; //take care of fractional beats that don't match the subdivision asked
- }
- fr_has_changed = true;
- break;
- }
- }
+ BBT_Time the_beat;
+ uint32_t ticks_one_half_subdivisions_worth;
+ uint32_t ticks_one_subdivisions_worth;
+
+ bbt_time(fr, the_beat);
- if (!fr_has_changed) {
- fr = pos;
+ ticks_one_subdivisions_worth = (uint32_t)Meter::ticks_per_beat / sub_num;
+ ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
+
+ if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
+ uint32_t difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
+ if (the_beat.ticks + difference >= (uint32_t)Meter::ticks_per_beat) {
+ the_beat.beats++;
+ the_beat.ticks += difference;
+ the_beat.ticks -= (uint32_t)Meter::ticks_per_beat;
+ } else {
+ the_beat.ticks += difference;
+ }
+ } else {
+ the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
}
- delete more_zoomed_bbt_points;
- return fr ;
+ return frame_time (the_beat);
}
-jack_nframes_t
+nframes_t
-TempoMap::round_to_type (jack_nframes_t frame, int dir, BBTPointType type)
+TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type)
{
Metric metric = metric_at (frame);
BBT_Time bbt;
}
+ /*
+ cerr << "for " << frame << " round to " << bbt << " using "
+ << metric.start()
+ << endl;
+ */
+
return metric.frame() + count_frames_between (metric.start(), bbt);
}
TempoMap::BBTPointList *
-TempoMap::get_points (jack_nframes_t lower, jack_nframes_t upper) const
+TempoMap::get_points (nframes_t lower, nframes_t upper) const
{
Metrics::const_iterator i;
const TempoSection* t;
uint32_t bar;
uint32_t beat;
+ double beats_per_bar;
+ double beat_frame;
+ double beat_frames;
+ double frames_per_bar;
+ double delta_bars;
+ double delta_beats;
+ double dummy;
+ nframes_t limit;
meter = &first_meter ();
tempo = &first_tempo ();
Now start generating points.
*/
+ beats_per_bar = meter->beats_per_bar ();
+ frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
+ beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
+
if (meter->frame() > tempo->frame()) {
bar = meter->start().bars;
beat = meter->start().beats;
current = tempo->frame();
}
- points = new BBTPointList;
+ /* initialize current to point to the bar/beat just prior to the
+ lower frame bound passed in. assumes that current is initialized
+ above to be on a beat.
+ */
+
+ delta_bars = (lower-current) / frames_per_bar;
+ delta_beats = modf(delta_bars, &dummy) * beats_per_bar;
+ current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
- do {
- double beats_per_bar;
- double beat_frame;
- double beat_frames;
- double frames_per_bar;
- jack_nframes_t limit;
+ // adjust bars and beats too
+ bar += (uint32_t) (floor(delta_bars));
+ beat += (uint32_t) (floor(delta_beats));
+
+ points = new BBTPointList;
- beats_per_bar = meter->beats_per_bar ();
- frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
- beat_frames = tempo->frames_per_beat (_frame_rate);
+ do {
if (i == metrics->end()) {
limit = upper;
if (beat == 1) {
if (current >= lower) {
- points->push_back (BBTPoint (*meter, *tempo,(jack_nframes_t)rint(current), Bar, bar, 1));
+ // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
+ points->push_back (BBTPoint (*meter, *tempo,(nframes_t)rint(current), Bar, bar, 1));
}
}
while (beat <= ceil( beats_per_bar) && beat_frame < limit) {
if (beat_frame >= lower) {
- points->push_back (BBTPoint (*meter, *tempo, (jack_nframes_t) rint(beat_frame), Beat, bar, beat));
+ // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
+ points->push_back (BBTPoint (*meter, *tempo, (nframes_t) rint(beat_frame), Beat, bar, beat));
}
beat_frame += beat_frames;
current+= beat_frames;
beat++;
}
- if (beat > ceil(beats_per_bar) ) {
+ if (beat > ceil(beats_per_bar) || i != metrics->end()) {
/* we walked an entire bar. its
important to move `current' forward
so we subtract the possible extra fraction from the current
*/
- current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
+ if (beat > ceil (beats_per_bar)) {
+ /* next bar goes where the numbers suggest */
+ current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
+ } else {
+ /* next bar goes where the next metric is */
+ current = limit;
+ }
bar++;
beat = 1;
-
}
}
beat = 1;
}
+ beats_per_bar = meter->beats_per_bar ();
+ frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
+ beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
+
++i;
}
return points;
}
+const TempoSection&
+TempoMap::tempo_section_at (nframes_t frame)
+{
+ Glib::RWLock::ReaderLock lm (lock);
+ Metrics::iterator i;
+ TempoSection* prev = 0;
+
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+ TempoSection* t;
+
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+
+ if ((*i)->frame() > frame) {
+ break;
+ }
+
+ prev = t;
+ }
+ }
+
+ if (prev == 0) {
+ fatal << endmsg;
+ }
+
+ return *prev;
+}
+
const Tempo&
-TempoMap::tempo_at (jack_nframes_t frame)
+TempoMap::tempo_at (nframes_t frame)
{
Metric m (metric_at (frame));
return m.tempo();
const Meter&
-TempoMap::meter_at (jack_nframes_t frame)
+TempoMap::meter_at (nframes_t frame)
{
Metric m (metric_at (frame));
return m.meter();
XMLNode&
TempoMap::get_state ()
{
- LockMonitor lm (lock, __LINE__, __FILE__);
Metrics::const_iterator i;
XMLNode *root = new XMLNode ("TempoMap");
- for (i = metrics->begin(); i != metrics->end(); ++i) {
- root->add_child_nocopy ((*i)->get_state());
+ {
+ Glib::RWLock::ReaderLock lm (lock);
+ for (i = metrics->begin(); i != metrics->end(); ++i) {
+ root->add_child_nocopy ((*i)->get_state());
+ }
}
return *root;
TempoMap::set_state (const XMLNode& node)
{
{
- LockMonitor lm (lock, __LINE__, __FILE__);
+ Glib::RWLock::WriterLock lm (lock);
XMLNodeList nlist;
XMLNodeConstIterator niter;
Metrics old_metrics (*metrics);
- in_set_state = true;
-
metrics->clear();
nlist = node.children();
MetricSectionSorter cmp;
metrics->sort (cmp);
- timestamp_metrics ();
+ timestamp_metrics (true);
}
-
- in_set_state = false;
}
-
- send_state_changed (Change (0));
+
+ StateChanged (Change (0));
return 0;
}
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM at " << t->start() << " frame= " << t->frame() << " (move? "
+ o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
<< t->movable() << ')' << endl;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
o << "Meter @ " << *i << ' ' << m->beats_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
}
}
-UndoAction
-TempoMap::get_memento () const
-{
- return sigc::bind (mem_fun (*(const_cast<TempoMap *> (this)), &StateManager::use_state), _current_state_id);
-}
-
-Change
-TempoMap::restore_state (StateManager::State& state)
-{
- LockMonitor lm (lock, __LINE__, __FILE__);
-
- TempoMapState* tmstate = dynamic_cast<TempoMapState*> (&state);
-
- metrics = tmstate->metrics;
- last_bbt_valid = false;
-
- return Change (0);
-}
-
-StateManager::State*
-TempoMap::state_factory (std::string why) const
-{
- TempoMapState* state = new TempoMapState (why);
-
- for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
- TempoSection *ts;
- MeterSection *ms;
-
- if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
- state->metrics->push_back (new TempoSection (*ts));
- } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
- state->metrics->push_back (new MeterSection (*ms));
- }
- }
-
- return state;
-}
-
-void
-TempoMap::save_state (std::string why)
-{
- if (!in_set_state) {
- StateManager::save_state (why);
- }
-}