|
|
|
|
@@ -45,7 +45,8 @@ using Timecode::BBT_Time;
|
|
|
|
|
Meter TempoMap::_default_meter (4.0, 4.0);
|
|
|
|
|
Tempo TempoMap::_default_tempo (120.0);
|
|
|
|
|
|
|
|
|
|
double Tempo::frames_per_beat (framecnt_t sr, const Meter& meter) const
|
|
|
|
|
double
|
|
|
|
|
Tempo::frames_per_beat (framecnt_t sr) const
|
|
|
|
|
{
|
|
|
|
|
return (60.0 * sr) / _beats_per_minute;
|
|
|
|
|
}
|
|
|
|
|
@@ -55,13 +56,13 @@ double Tempo::frames_per_beat (framecnt_t sr, const Meter& meter) const
|
|
|
|
|
double
|
|
|
|
|
Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
|
|
|
|
|
{
|
|
|
|
|
return ((60.0 * sr * _beats_per_bar) / (tempo.beats_per_minute() * _note_type/tempo.note_type()));
|
|
|
|
|
return (60.0 * sr * _divisions_per_bar) / tempo.beats_per_minute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
Meter::frames_per_division (const Tempo& tempo, framecnt_t sr) const
|
|
|
|
|
{
|
|
|
|
|
return ((60.0 * sr) / (tempo.beats_per_minute() * _note_type/tempo.note_type()));
|
|
|
|
|
return (60.0 * sr) / (tempo.beats_per_minute() * _note_type/tempo.note_type());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
|
@@ -171,7 +172,7 @@ MeterSection::MeterSection (const XMLNode& node)
|
|
|
|
|
throw failed_constructor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sscanf (prop->value().c_str(), "%lf", &_beats_per_bar) != 1 || _beats_per_bar < 0.0) {
|
|
|
|
|
if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
|
|
|
|
|
error << _("MeterSection XML node has an illegal \"beats-per-bar\" value") << endmsg;
|
|
|
|
|
throw failed_constructor();
|
|
|
|
|
}
|
|
|
|
|
@@ -208,7 +209,7 @@ MeterSection::get_state() const
|
|
|
|
|
root->add_property ("start", buf);
|
|
|
|
|
snprintf (buf, sizeof (buf), "%f", _note_type);
|
|
|
|
|
root->add_property ("note-type", buf);
|
|
|
|
|
snprintf (buf, sizeof (buf), "%f", _beats_per_bar);
|
|
|
|
|
snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
|
|
|
|
|
root->add_property ("beats-per-bar", buf);
|
|
|
|
|
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
|
|
|
|
|
root->add_property ("movable", buf);
|
|
|
|
|
@@ -236,7 +237,7 @@ TempoMap::TempoMap (framecnt_t fr)
|
|
|
|
|
start.ticks = 0;
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
|
|
|
|
|
|
|
|
|
|
t->set_movable (false);
|
|
|
|
|
m->set_movable (false);
|
|
|
|
|
@@ -374,40 +375,23 @@ TempoMap::remove_meter (const MeterSection& tempo)
|
|
|
|
|
void
|
|
|
|
|
TempoMap::do_insert (MetricSection* section, bool with_bbt)
|
|
|
|
|
{
|
|
|
|
|
/* First of all, check to see if the new MetricSection is in the
|
|
|
|
|
middle of a bar. If so, we need to fix the bar that we are in
|
|
|
|
|
to have a different meter.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
assert (section->start().ticks == 0);
|
|
|
|
|
|
|
|
|
|
if (section->start().beats != 1) {
|
|
|
|
|
/* we only allow new meters to be inserted on beat 1 of an existing
|
|
|
|
|
* measure.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Here's the tempo and metric where we are proposing to insert `section' */
|
|
|
|
|
TempoMetric tm = metric_at (section->start ());
|
|
|
|
|
if (dynamic_cast<MeterSection*>(section) &&
|
|
|
|
|
(section->start().beats != 1 || section->start().ticks != 0)) {
|
|
|
|
|
|
|
|
|
|
/* This is where we will put the `corrective' new meter; at the start of
|
|
|
|
|
the bar that we are inserting into the middle of.
|
|
|
|
|
*/
|
|
|
|
|
BBT_Time where_correction = section->start();
|
|
|
|
|
where_correction.beats = 1;
|
|
|
|
|
where_correction.ticks = 0;
|
|
|
|
|
BBT_Time corrected = section->start();
|
|
|
|
|
corrected.beats = 1;
|
|
|
|
|
corrected.ticks = 0;
|
|
|
|
|
|
|
|
|
|
warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
|
|
|
|
|
section->start(), corrected) << endmsg;
|
|
|
|
|
|
|
|
|
|
/* Put in the meter change to make the bar before our `section' the right
|
|
|
|
|
length.
|
|
|
|
|
*/
|
|
|
|
|
do_insert (new MeterSection (where_correction, section->start().beats, tm.meter().note_divisor ()), true);
|
|
|
|
|
|
|
|
|
|
/* This is where the new stuff will now go; the start of the next bar
|
|
|
|
|
(after the one whose meter we just fixed).
|
|
|
|
|
*/
|
|
|
|
|
BBT_Time where_new (where_correction.bars + 1, 1, 0);
|
|
|
|
|
|
|
|
|
|
/* Change back to the original meter */
|
|
|
|
|
do_insert (new MeterSection (where_new, tm.meter().beats_per_bar(), tm.meter().note_divisor()), true);
|
|
|
|
|
|
|
|
|
|
/* And set up `section' for where it should be, ready to be inserted */
|
|
|
|
|
section->set_start (where_new);
|
|
|
|
|
section->set_start (corrected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Metrics::iterator i;
|
|
|
|
|
@@ -541,7 +525,7 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
|
|
|
|
|
/* new meters *always* start on a beat. */
|
|
|
|
|
where.ticks = 0;
|
|
|
|
|
|
|
|
|
|
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), true);
|
|
|
|
|
do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyChanged (PropertyChange ());
|
|
|
|
|
@@ -552,7 +536,7 @@ TempoMap::add_meter (const Meter& meter, framepos_t where)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
Glib::RWLock::WriterLock lm (lock);
|
|
|
|
|
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), false);
|
|
|
|
|
do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyChanged (PropertyChange ());
|
|
|
|
|
@@ -688,7 +672,7 @@ TempoMap::timestamp_metrics (bool use_bbt)
|
|
|
|
|
tempo = &first_tempo ();
|
|
|
|
|
|
|
|
|
|
if (use_bbt) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cerr << "\n\n\n ######################\nTIMESTAMP via BBT ##############\n" << endl;
|
|
|
|
|
|
|
|
|
|
framepos_t current = 0;
|
|
|
|
|
@@ -739,10 +723,9 @@ TempoMap::timestamp_metrics (bool use_bbt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bbt_time_with_metric ((*i)->frame(), bbt, metric);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
|
first = false;
|
|
|
|
|
} else {
|
|
|
|
|
@@ -761,10 +744,10 @@ TempoMap::timestamp_metrics (bool use_bbt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//s cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl;
|
|
|
|
|
// cerr << bbt << endl;
|
|
|
|
|
|
|
|
|
|
(*i)->set_start (bbt);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
|
|
|
|
tempo = t;
|
|
|
|
|
// cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
|
|
|
|
|
@@ -801,6 +784,8 @@ TempoMap::metric_at (framepos_t frame) const
|
|
|
|
|
|
|
|
|
|
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
|
|
|
|
|
|
|
|
|
|
// cerr << "Looking at a metric section " << **i << endl;
|
|
|
|
|
|
|
|
|
|
if ((*i)->frame() > frame) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -815,6 +800,7 @@ TempoMap::metric_at (framepos_t frame) const
|
|
|
|
|
m.set_start ((*i)->start ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << endl;
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -873,8 +859,13 @@ TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetr
|
|
|
|
|
{
|
|
|
|
|
framecnt_t frame_diff;
|
|
|
|
|
|
|
|
|
|
const double beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
const double ticks_per_frame = metric.tempo().frames_per_beat (_frame_rate, metric.meter()) / BBT_Time::ticks_per_beat;
|
|
|
|
|
const double divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
const double ticks_per_frame = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
|
|
|
|
|
|
|
|
|
|
// cerr << "*** Compute BBT time for " << frame
|
|
|
|
|
// << " from metric at " << metric.frame() << " tempo = " << metric.tempo().beats_per_minute () << " meter "
|
|
|
|
|
// << metric.meter().divisions_per_bar() << '/' << metric.meter().note_divisor()
|
|
|
|
|
// << endl;
|
|
|
|
|
|
|
|
|
|
/* now compute how far beyond that point we actually are. */
|
|
|
|
|
|
|
|
|
|
@@ -885,13 +876,15 @@ TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetr
|
|
|
|
|
bbt.ticks %= (uint32_t)BBT_Time::ticks_per_beat;
|
|
|
|
|
|
|
|
|
|
bbt.beats = metric.start().beats + xtra_beats - 1; // correction for 1-based counting, see below for matching operation.
|
|
|
|
|
bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / beats_per_bar);
|
|
|
|
|
bbt.beats = (uint32_t)fmod((double)bbt.beats, beats_per_bar);
|
|
|
|
|
bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / divisions_per_bar);
|
|
|
|
|
bbt.beats = (uint32_t)fmod((double)bbt.beats, divisions_per_bar);
|
|
|
|
|
|
|
|
|
|
/* if we have a fractional number of beats per bar, we see if
|
|
|
|
|
we're in the last beat (the fractional one). if so, we
|
|
|
|
|
round ticks appropriately and bump to the next bar. */
|
|
|
|
|
double beat_fraction = beats_per_bar - floor(beats_per_bar);
|
|
|
|
|
round ticks appropriately and bump to the next bar.
|
|
|
|
|
*/
|
|
|
|
|
double beat_fraction = divisions_per_bar - floor(divisions_per_bar);
|
|
|
|
|
|
|
|
|
|
/* XXX one problem here is that I'm not sure how to handle
|
|
|
|
|
fractional beats that don't evenly divide ticks_per_beat.
|
|
|
|
|
If they aren't handled consistently, I would guess we'll
|
|
|
|
|
@@ -901,7 +894,7 @@ TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetr
|
|
|
|
|
*/
|
|
|
|
|
uint32_t ticks_on_last_beat = (uint32_t)floor(BBT_Time::ticks_per_beat * beat_fraction);
|
|
|
|
|
|
|
|
|
|
if (bbt.beats > (uint32_t)floor(beats_per_bar) && bbt.ticks >= ticks_on_last_beat) {
|
|
|
|
|
if (bbt.beats > (uint32_t)floor(divisions_per_bar) && bbt.ticks >= ticks_on_last_beat) {
|
|
|
|
|
bbt.ticks -= ticks_on_last_beat;
|
|
|
|
|
bbt.beats = 0;
|
|
|
|
|
bbt.bars++;
|
|
|
|
|
@@ -928,20 +921,29 @@ TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) cons
|
|
|
|
|
|
|
|
|
|
uint32_t bar_offset = start.bars - m.start().bars;
|
|
|
|
|
|
|
|
|
|
double beat_offset = bar_offset*m.meter().beats_per_bar() - (m.start().beats-1) + (start.beats -1)
|
|
|
|
|
double beat_offset = bar_offset*m.meter().divisions_per_bar() - (m.start().beats-1) + (start.beats -1)
|
|
|
|
|
+ start.ticks/BBT_Time::ticks_per_beat;
|
|
|
|
|
|
|
|
|
|
start_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
|
|
|
|
|
|
|
|
|
|
start_frame = m.frame() + (framepos_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
|
|
|
|
|
// cerr << "from start " << start << " compute frame = " << start_frame
|
|
|
|
|
// << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
|
|
|
|
|
// << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
|
|
|
|
|
// << endl;
|
|
|
|
|
|
|
|
|
|
m = metric_at(end);
|
|
|
|
|
|
|
|
|
|
bar_offset = end.bars - m.start().bars;
|
|
|
|
|
|
|
|
|
|
beat_offset = bar_offset * m.meter().beats_per_bar() - (m.start().beats -1) + (end.beats - 1)
|
|
|
|
|
beat_offset = bar_offset * m.meter().divisions_per_bar() - (m.start().beats -1) + (end.beats - 1)
|
|
|
|
|
+ end.ticks/BBT_Time::ticks_per_beat;
|
|
|
|
|
|
|
|
|
|
end_frame = m.frame() + (framepos_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
|
|
|
|
|
end_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
|
|
|
|
|
|
|
|
|
|
// cerr << "from end " << end << " compute frame = " << end_frame
|
|
|
|
|
// << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
|
|
|
|
|
// << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
|
|
|
|
|
// << endl;
|
|
|
|
|
|
|
|
|
|
frames = end_frame - start_frame;
|
|
|
|
|
|
|
|
|
|
@@ -957,43 +959,43 @@ TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo,
|
|
|
|
|
framecnt_t frames = 0;
|
|
|
|
|
uint32_t bar = start.bars;
|
|
|
|
|
double beat = (double) start.beats;
|
|
|
|
|
double beats_counted = 0;
|
|
|
|
|
double beats_per_bar = 0;
|
|
|
|
|
double beat_frames = 0;
|
|
|
|
|
double divisions_counted = 0;
|
|
|
|
|
double divisions_per_bar = 0;
|
|
|
|
|
double division_frames = 0;
|
|
|
|
|
|
|
|
|
|
beats_per_bar = meter.beats_per_bar();
|
|
|
|
|
beat_frames = tempo.frames_per_beat (_frame_rate,meter);
|
|
|
|
|
divisions_per_bar = meter.divisions_per_bar();
|
|
|
|
|
division_frames = meter.frames_per_division (tempo, _frame_rate);
|
|
|
|
|
|
|
|
|
|
frames = 0;
|
|
|
|
|
|
|
|
|
|
while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
|
|
|
|
|
|
|
|
|
|
if (beat >= beats_per_bar) {
|
|
|
|
|
if (beat >= divisions_per_bar) {
|
|
|
|
|
beat = 1;
|
|
|
|
|
++bar;
|
|
|
|
|
++beats_counted;
|
|
|
|
|
++divisions_counted;
|
|
|
|
|
|
|
|
|
|
if (beat > beats_per_bar) {
|
|
|
|
|
if (beat > divisions_per_bar) {
|
|
|
|
|
|
|
|
|
|
/* this is a fractional beat at the end of a fractional bar
|
|
|
|
|
so it should only count for the fraction
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
beats_counted -= (ceil(beats_per_bar) - beats_per_bar);
|
|
|
|
|
divisions_counted -= (ceil(divisions_per_bar) - divisions_per_bar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
++beat;
|
|
|
|
|
++beats_counted;
|
|
|
|
|
++divisions_counted;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cerr << "Counted " << beats_counted << " from " << start << " to " << end
|
|
|
|
|
// << " bpb were " << beats_per_bar
|
|
|
|
|
// << " bpb were " << divisions_per_bar
|
|
|
|
|
// << " fpb was " << beat_frames
|
|
|
|
|
// << endl;
|
|
|
|
|
|
|
|
|
|
frames = (framecnt_t) llrint (floor (beats_counted * beat_frames));
|
|
|
|
|
frames = (framecnt_t) llrint (floor (divisions_counted * division_frames));
|
|
|
|
|
|
|
|
|
|
return frames;
|
|
|
|
|
|
|
|
|
|
@@ -1028,7 +1030,7 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
{
|
|
|
|
|
framecnt_t frames = 0;
|
|
|
|
|
|
|
|
|
|
double beats_per_bar;
|
|
|
|
|
double divisions_per_bar;
|
|
|
|
|
BBT_Time result;
|
|
|
|
|
|
|
|
|
|
result.bars = max(1U, when.bars + dir * bbt.bars) ;
|
|
|
|
|
@@ -1036,7 +1038,7 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
result.ticks = 0;
|
|
|
|
|
|
|
|
|
|
TempoMetric metric = metric_at(result);
|
|
|
|
|
beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
|
|
|
|
|
/* Reduce things to legal bbt values we have to handle possible
|
|
|
|
|
fractional=shorter beats at the end of measures and things like 0|11|9000
|
|
|
|
|
@@ -1048,11 +1050,11 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
result.beats = when.beats + bbt.beats;
|
|
|
|
|
result.ticks = when.ticks + bbt.ticks;
|
|
|
|
|
|
|
|
|
|
while (result.beats >= (beats_per_bar + 1)) {
|
|
|
|
|
while (result.beats >= (divisions_per_bar + 1)) {
|
|
|
|
|
result.bars++;
|
|
|
|
|
result.beats -= (uint32_t) ceil(beats_per_bar);
|
|
|
|
|
result.beats -= (uint32_t) ceil(divisions_per_bar);
|
|
|
|
|
metric = metric_at(result); // maybe there is a meter change
|
|
|
|
|
beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1066,21 +1068,21 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
/* of course gtk_ardour only allows bar with at least 1.0 beats .....
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(beats_per_bar) ?
|
|
|
|
|
(1 - (ceil(beats_per_bar) - beats_per_bar))* BBT_Time::ticks_per_beat
|
|
|
|
|
uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
|
|
|
|
|
(1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_beat
|
|
|
|
|
: BBT_Time::ticks_per_beat );
|
|
|
|
|
|
|
|
|
|
while (result.ticks >= ticks_at_beat) {
|
|
|
|
|
result.beats++;
|
|
|
|
|
result.ticks -= ticks_at_beat;
|
|
|
|
|
if (result.beats >= (beats_per_bar + 1)) {
|
|
|
|
|
if (result.beats >= (divisions_per_bar + 1)) {
|
|
|
|
|
result.bars++;
|
|
|
|
|
result.beats = 1;
|
|
|
|
|
metric = metric_at(result); // maybe there is a meter change
|
|
|
|
|
beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
}
|
|
|
|
|
ticks_at_beat= (uint32_t) (result.beats == ceil(beats_per_bar) ?
|
|
|
|
|
(1 - (ceil(beats_per_bar) - beats_per_bar) ) * BBT_Time::ticks_per_beat
|
|
|
|
|
ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
|
|
|
|
|
(1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_beat
|
|
|
|
|
: BBT_Time::ticks_per_beat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1093,11 +1095,11 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
--result.bars;
|
|
|
|
|
result.bars = max(1U, result.bars);
|
|
|
|
|
metric = metric_at(result); // maybe there is a meter change
|
|
|
|
|
beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
if (b >= ceil(beats_per_bar)) {
|
|
|
|
|
b -= (uint32_t) ceil(beats_per_bar);
|
|
|
|
|
divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
if (b >= ceil(divisions_per_bar)) {
|
|
|
|
|
b -= (uint32_t) ceil(divisions_per_bar);
|
|
|
|
|
} else {
|
|
|
|
|
b = (uint32_t) ceil(beats_per_bar) - b + when.beats ;
|
|
|
|
|
b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result.beats = when.beats - b;
|
|
|
|
|
@@ -1117,9 +1119,9 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
|
|
|
|
|
--result.bars;
|
|
|
|
|
result.bars = max(1U, result.bars) ;
|
|
|
|
|
metric = metric_at(result); // maybe there is a meter change
|
|
|
|
|
beats_per_bar = metric.meter().beats_per_bar();
|
|
|
|
|
result.beats = (uint32_t) ceil(beats_per_bar);
|
|
|
|
|
ticks_at_beat = (uint32_t) ((1 - (ceil(beats_per_bar) - beats_per_bar)) * BBT_Time::ticks_per_beat) ;
|
|
|
|
|
divisions_per_bar = metric.meter().divisions_per_bar();
|
|
|
|
|
result.beats = (uint32_t) ceil(divisions_per_bar);
|
|
|
|
|
ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_beat) ;
|
|
|
|
|
} else {
|
|
|
|
|
--result.beats;
|
|
|
|
|
ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
|
|
|
|
|
@@ -1283,7 +1285,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
|
|
|
|
|
float midbar_beats;
|
|
|
|
|
float midbar_ticks;
|
|
|
|
|
|
|
|
|
|
midbar_beats = metric.meter().beats_per_bar() / 2 + 1;
|
|
|
|
|
midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
|
|
|
|
|
midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
|
|
|
|
|
midbar_beats = floor (midbar_beats);
|
|
|
|
|
|
|
|
|
|
@@ -1370,7 +1372,7 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
const TempoSection* t;
|
|
|
|
|
uint32_t bar;
|
|
|
|
|
uint32_t beat;
|
|
|
|
|
double beats_per_bar;
|
|
|
|
|
double divisions_per_bar;
|
|
|
|
|
double beat_frame;
|
|
|
|
|
double beat_frames;
|
|
|
|
|
double frames_per_bar;
|
|
|
|
|
@@ -1406,7 +1408,7 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
Now start generating points.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
beats_per_bar = meter->beats_per_bar ();
|
|
|
|
|
divisions_per_bar = meter->divisions_per_bar ();
|
|
|
|
|
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
|
|
|
|
|
beat_frames = meter->frames_per_division (*tempo,_frame_rate);
|
|
|
|
|
|
|
|
|
|
@@ -1426,7 +1428,7 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
delta_bars = (lower-current) / frames_per_bar;
|
|
|
|
|
delta_beats = modf(delta_bars, &dummy) * beats_per_bar;
|
|
|
|
|
delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
|
|
|
|
|
current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
|
|
|
|
|
|
|
|
|
|
// adjust bars and beats too
|
|
|
|
|
@@ -1463,7 +1465,7 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
|
|
|
|
|
beat_frame = current;
|
|
|
|
|
|
|
|
|
|
while (beat <= ceil(beats_per_bar) && beat_frame < limit) {
|
|
|
|
|
while (beat <= ceil(divisions_per_bar) && beat_frame < limit) {
|
|
|
|
|
if (beat_frame >= lower) {
|
|
|
|
|
// cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
|
|
|
|
|
points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
|
|
|
|
|
@@ -1474,11 +1476,12 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
beat++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
|
|
|
|
|
// << (beat > ceil(beats_per_bar))
|
|
|
|
|
// cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
|
|
|
|
|
// << (beat > ceil(divisions_per_bar))
|
|
|
|
|
// << " beat frame @ " << beat_frame << " vs. " << limit
|
|
|
|
|
// << endl;
|
|
|
|
|
|
|
|
|
|
if (beat > ceil(beats_per_bar) || i != metrics->end()) {
|
|
|
|
|
if (beat > ceil(divisions_per_bar) || i != metrics->end()) {
|
|
|
|
|
|
|
|
|
|
/* we walked an entire bar. its
|
|
|
|
|
important to move `current' forward
|
|
|
|
|
@@ -1496,9 +1499,9 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
so we subtract the possible extra fraction from the current
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (beat > ceil (beats_per_bar)) {
|
|
|
|
|
if (beat > ceil (divisions_per_bar)) {
|
|
|
|
|
/* next bar goes where the numbers suggest */
|
|
|
|
|
current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
|
|
|
|
|
current -= beat_frames * (ceil(divisions_per_bar)-divisions_per_bar);
|
|
|
|
|
// cerr << "++ next bar from numbers\n";
|
|
|
|
|
} else {
|
|
|
|
|
/* next bar goes where the next metric is */
|
|
|
|
|
@@ -1530,11 +1533,11 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
|
|
|
|
/* new MeterSection, beat always returns to 1 */
|
|
|
|
|
beat = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current = (*i)->frame ();
|
|
|
|
|
// cerr << "loop around with current @ " << current << endl;
|
|
|
|
|
|
|
|
|
|
beats_per_bar = meter->beats_per_bar ();
|
|
|
|
|
divisions_per_bar = meter->divisions_per_bar ();
|
|
|
|
|
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
|
|
|
|
|
beat_frames = meter->frames_per_division (*tempo, _frame_rate);
|
|
|
|
|
|
|
|
|
|
@@ -1672,7 +1675,7 @@ TempoMap::dump (std::ostream& o) const
|
|
|
|
|
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()
|
|
|
|
|
o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
|
|
|
|
|
<< " (move? " << m->movable() << ')' << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1801,7 +1804,7 @@ TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const Tempo
|
|
|
|
|
|
|
|
|
|
/* given the current meter, have we gone past the end of the bar ? */
|
|
|
|
|
|
|
|
|
|
if (result.beats >= meter->beats_per_bar()) {
|
|
|
|
|
if (result.beats >= meter->divisions_per_bar()) {
|
|
|
|
|
/* move to next bar, first beat */
|
|
|
|
|
result.bars++;
|
|
|
|
|
result.beats = 1;
|
|
|
|
|
@@ -1909,7 +1912,7 @@ TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.bars--;
|
|
|
|
|
result.beats = meter->beats_per_bar();
|
|
|
|
|
result.beats = meter->divisions_per_bar();
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* back one beat */
|
|
|
|
|
@@ -1991,14 +1994,14 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
|
|
|
|
|
framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
|
|
|
|
|
|
|
|
|
|
/* Distance to the end in beats */
|
|
|
|
|
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
/* Amount to subtract this time */
|
|
|
|
|
double const sub = min (distance_beats, beats);
|
|
|
|
|
|
|
|
|
|
/* Update */
|
|
|
|
|
beats -= sub;
|
|
|
|
|
pos += sub * tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
pos += sub * tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
/* Move on if there's anything to move to */
|
|
|
|
|
if (i != metrics->end ()) {
|
|
|
|
|
@@ -2075,14 +2078,14 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
|
|
|
|
|
framecnt_t distance_frames = no_more_metrics ? max_framepos : (pos - (*i)->frame());
|
|
|
|
|
|
|
|
|
|
/* Distance to the end in beats */
|
|
|
|
|
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
/* Amount to subtract this time */
|
|
|
|
|
double const sub = min (distance_beats, beats);
|
|
|
|
|
|
|
|
|
|
/* Update */
|
|
|
|
|
beats -= sub;
|
|
|
|
|
pos -= sub * tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
pos -= sub * tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
/* Move i, tempo and meter back, if there's anything to move to.
|
|
|
|
|
This is more complicated than the forward case, as we have to
|
|
|
|
|
@@ -2182,7 +2185,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
|
|
|
|
|
checking for a new metric on every beat.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
uint64_t bars = 0;
|
|
|
|
|
|
|
|
|
|
@@ -2204,7 +2207,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
|
|
|
|
|
* frames_per_beat value.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pos += llrint (frames_per_beat * (bars * meter->beats_per_bar()));
|
|
|
|
|
pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
|
|
|
|
|
bars = 0;
|
|
|
|
|
|
|
|
|
|
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
|
|
|
|
|
@@ -2213,14 +2216,14 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
|
|
|
|
|
meter = m;
|
|
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += llrint (frames_per_beat * (bars * meter->beats_per_bar()));
|
|
|
|
|
pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
|
|
|
|
|
|
|
|
|
|
uint64_t beats = 0;
|
|
|
|
|
|
|
|
|
|
@@ -2253,7 +2256,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
|
|
|
|
|
meter = m;
|
|
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
frames_per_beat = tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -2324,7 +2327,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
|
|
|
|
|
/* Update */
|
|
|
|
|
pos += sub;
|
|
|
|
|
distance -= sub;
|
|
|
|
|
beats += sub / tempo->frames_per_beat (_frame_rate, *meter);
|
|
|
|
|
beats += sub / tempo->frames_per_beat (_frame_rate);
|
|
|
|
|
|
|
|
|
|
/* Move on if there's anything to move to */
|
|
|
|
|
if (i != metrics->end ()) {
|
|
|
|
|
@@ -2373,3 +2376,28 @@ MetricSection::compare (MetricSection* other, bool with_bbt) const
|
|
|
|
|
/* NOTREACHED */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream&
|
|
|
|
|
operator<< (std::ostream& o, const Meter& m) {
|
|
|
|
|
return o << m.divisions_per_bar() << '/' << m.note_divisor();
|
|
|
|
|
}
|
|
|
|
|
std::ostream&
|
|
|
|
|
operator<< (std::ostream& o, const Tempo& t) {
|
|
|
|
|
return o << t.beats_per_minute() << " (1/" << t.note_type() << " per minute)" << endl;
|
|
|
|
|
}
|
|
|
|
|
std::ostream&
|
|
|
|
|
operator<< (std::ostream& o, const MetricSection& section) {
|
|
|
|
|
|
|
|
|
|
o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
|
|
|
|
|
|
|
|
|
|
const TempoSection* ts;
|
|
|
|
|
const MeterSection* ms;
|
|
|
|
|
|
|
|
|
|
if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
|
|
|
|
|
o << *((Tempo*) ts);
|
|
|
|
|
} else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
|
|
|
|
|
o << *((Meter*) ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
|