_frame_rate = fr;
BBT_Time start (1, 1, 0);
- TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant, AudioTime);
+ TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime);
MeterSection *m = new MeterSection (0.0, 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime);
t->set_movable (false);
if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
- pair<double, BBT_Time> corrected = make_pair (m->pulse(), m->bbt());
+ pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
corrected.second.beats = 1;
corrected.second.ticks = 0;
- corrected.first = bbt_to_beats_locked (_metrics, corrected.second);
+ corrected.first = beat_at_bbt_locked (_metrics, corrected.second);
warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
m->bbt(), corrected.second) << endmsg;
//m->set_pulse (corrected);
{
{
Glib::Threads::RWLock::WriterLock lm (lock);
- const double beat = bbt_to_beats_locked (_metrics, where);
+ const double beat = beat_at_bbt_locked (_metrics, where);
if (ms.movable()) {
remove_meter_locked (ms);
first_t.set_frame (first.frame());
first_t.set_pulse (0.0);
first_t.set_position_lock_style (AudioTime);
+ recompute_map (_metrics);
}
- recompute_map (_metrics);
}
+
PropertyChanged (PropertyChange ());
}
if (pls == AudioTime) {
/* add meter-locked tempo */
- add_tempo_locked (tempo_at_locked (_metrics, frame), pulse, frame, TempoSection::Ramp, AudioTime, true, true);
+ add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse, frame, TempoSection::Ramp, AudioTime, true, true);
}
MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
} else {
/* MusicTime */
double pulse = 0.0;
- pair<double, BBT_Time> new_beat;
+ pair<double, BBT_Time> b_bbt;
if (prev_m) {
const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
if (beats + prev_m->beat() != meter->beat()) {
/* reordering caused a bbt change */
- new_beat = make_pair (beats + prev_m->beat()
+ b_bbt = make_pair (beats + prev_m->beat()
, BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
} else {
- new_beat = make_pair (beats + prev_m->beat(), meter->bbt());
+ b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
}
pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
} else {
/* shouldn't happen - the first is audio-locked */
pulse = pulse_at_beat_locked (metrics, meter->beat());
- new_beat = make_pair (meter->beat(), meter->bbt());
+ b_bbt = make_pair (meter->beat(), meter->bbt());
}
- meter->set_beat (new_beat);
+ meter->set_beat (b_bbt);
meter->set_pulse (pulse);
meter->set_frame (frame_at_pulse_locked (metrics, pulse));
}
return m;
}
+double
+TempoMap::beat_at_frame (const framecnt_t& frame) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ return beat_at_frame_locked (_metrics, frame);
+}
+
+/* meter / tempo section based */
+double
+TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
+{
+ const TempoSection& ts = tempo_section_at_locked (metrics, frame);
+ MeterSection* prev_m = 0;
+ MeterSection* next_m = 0;
+
+ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+ MeterSection* m;
+ if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
+ if (prev_m && m->frame() > frame) {
+ next_m = m;
+ break;
+ }
+ prev_m = m;
+ }
+ }
+ if (frame < prev_m->frame()) {
+ return 0.0;
+ }
+ const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
+
+ if (next_m && next_m->beat() < beat) {
+ return next_m->beat();
+ }
+
+ return beat;
+}
+
+framecnt_t
+TempoMap::frame_at_beat (const double& beat) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ return frame_at_beat_locked (_metrics, beat);
+}
+
+/* meter section based */
+framecnt_t
+TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
+{
+ const TempoSection& prev_t = tempo_section_at_beat_locked (metrics, beat);
+ MeterSection* prev_m = 0;
+
+ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+ MeterSection* m;
+ if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
+ if (prev_m && m->beat() > beat) {
+ break;
+ }
+ prev_m = m;
+ }
+ }
+
+ return prev_t.frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
+}
+
double
TempoMap::pulse_at_beat (const double& beat) const
{
return ret;
}
-double
-TempoMap::beat_at_frame (const framecnt_t& frame) const
+const Tempo
+TempoMap::tempo_at_frame (const framepos_t& frame) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return beat_at_frame_locked (_metrics, frame);
+ return tempo_at_frame_locked (_metrics, frame);
}
-/* meter / tempo section based */
-double
-TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
+const Tempo
+TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
{
- const TempoSection& ts = tempo_section_at_locked (metrics, frame);
- MeterSection* prev_m = 0;
- MeterSection* next_m = 0;
+ TempoSection* prev_t = 0;
- for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
- MeterSection* m;
- if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
- if (prev_m && m->frame() > frame) {
- next_m = m;
- break;
+ Metrics::const_iterator i;
+
+ for (i = _metrics.begin(); i != _metrics.end(); ++i) {
+ TempoSection* t;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (!t->active()) {
+ continue;
}
- prev_m = m;
+ if ((prev_t) && t->frame() > frame) {
+ /* t is the section past frame */
+ const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
+ const Tempo ret_tempo (ret_bpm, prev_t->note_type());
+ return ret_tempo;
+ }
+ prev_t = t;
}
}
- if (frame < prev_m->frame()) {
- return 0.0;
- }
- const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
- if (next_m && next_m->beat() < beat) {
- return next_m->beat();
- }
-
- return beat;
-}
+ const double ret = prev_t->beats_per_minute();
+ const Tempo ret_tempo (ret, prev_t->note_type ());
-framecnt_t
-TempoMap::frame_at_beat (const double& beat) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return frame_at_beat_locked (_metrics, beat);
+ return ret_tempo;
}
-/* meter section based */
-framecnt_t
-TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
-{
- const TempoSection& prev_t = tempo_section_at_beat_locked (metrics, beat);
- MeterSection* prev_m = 0;
-
- for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
- MeterSection* m;
- if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
- if (prev_m && m->beat() > beat) {
- break;
- }
- prev_m = m;
- }
- }
-
- return prev_t.frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
-}
double
-TempoMap::bbt_to_beats (const Timecode::BBT_Time& bbt)
+TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return bbt_to_beats_locked (_metrics, bbt);
+ return beat_at_bbt_locked (_metrics, bbt);
}
double
-TempoMap::bbt_to_beats_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
+TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
{
/* CALLER HOLDS READ LOCK */
}
Timecode::BBT_Time
-TempoMap::beats_to_bbt (const double& beats)
+TempoMap::bbt_at_beat (const double& beats)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return beats_to_bbt_locked (_metrics, beats);
+ return bbt_at_beat_locked (_metrics, beats);
}
Timecode::BBT_Time
-TempoMap::beats_to_bbt_locked (const Metrics& metrics, const double& b) const
+TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
{
/* CALLER HOLDS READ LOCK */
MeterSection* prev_m = 0;
return ret;
}
+double
+TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return pulse_at_bbt_locked (_metrics, bbt);
+}
+
+double
+TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
+{
+ /* CALLER HOLDS READ LOCK */
+
+ MeterSection* prev_m = 0;
+
+ /* because audio-locked meters have 'fake' integral beats,
+ there is no pulse offset here.
+ */
+ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+ MeterSection* m;
+ if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
+ if (prev_m) {
+ if (m->bbt().bars > bbt.bars) {
+ break;
+ }
+ }
+ prev_m = m;
+ }
+ }
+
+ const double remaining_bars = bbt.bars - prev_m->bbt().bars;
+ const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
+ const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
+
+ return ret;
+}
+
Timecode::BBT_Time
-TempoMap::pulse_to_bbt (const double& pulse)
+TempoMap::bbt_at_pulse (const double& pulse)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return bbt_at_pulse_locked (_metrics, pulse);
+}
+
+Timecode::BBT_Time
+TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
+{
MeterSection* prev_m = 0;
- for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
+ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
Glib::Threads::RWLock::ReaderLock lm (lock);
const double beat = beat_at_frame_locked (_metrics, frame);
- bbt = beats_to_bbt_locked (_metrics, beat);
+ bbt = bbt_at_beat_locked (_metrics, beat);
}
framepos_t
{
/* HOLD THE READER LOCK */
- const framepos_t ret = frame_at_beat_locked (metrics, bbt_to_beats_locked (metrics, bbt));
+ const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
return ret;
}
return false;
}
- /* precision check ensures pulses and frames align.*/
- if (t->frame() != prev_t->frame_at_pulse (t->pulse(), _frame_rate)) {
+ /* precision check ensures tempo and frames align.*/
+ if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
if (!t->locked_to_meter()) {
return false;
}
}
}
- const double beat = bbt_to_beats_locked (copy, bbt);
- const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_beat_locked (copy, beat));
+ const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
Metrics::const_iterator d = copy.begin();
while (d != copy.end()) {
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
- const double beat = bbt_to_beats_locked (future_map, bbt);
+ const double beat = beat_at_bbt_locked (future_map, bbt);
if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
ret.first = tempo_copy->pulse();
}
void
-TempoMap::gui_move_tempo (TempoSection* ts, const pair<double, framepos_t>& pulse)
+TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
{
Metrics future_map;
{
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map_pulse (future_map, tempo_copy, pulse.first)) {
- solve_map_pulse (_metrics, ts, pulse.first);
+ const double pulse = pulse_at_frame_locked (future_map, frame);
+ if (solve_map_pulse (future_map, tempo_copy, pulse)) {
+ solve_map_pulse (_metrics, ts, pulse);
recompute_meters (_metrics);
}
}
{
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map_frame (future_map, tempo_copy, pulse.second)) {
- solve_map_frame (_metrics, ts, pulse.second);
+ if (solve_map_frame (future_map, tempo_copy, frame)) {
+ solve_map_frame (_metrics, ts, frame);
recompute_meters (_metrics);
}
}
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
const double beat = beat_at_frame_locked (_metrics, frame);
- const Timecode::BBT_Time bbt = beats_to_bbt_locked (_metrics, beat);
+ const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
if (solve_map_bbt (future_map, copy, bbt)) {
solve_map_bbt (_metrics, ms, bbt);
return ret_frame;
}
-void
-TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
-{
- if (sub_num == -1) {
- if (dir > 0) {
- ++when.bars;
- when.beats = 1;
- when.ticks = 0;
- } else if (dir < 0) {
- when.beats = 1;
- when.ticks = 0;
- } else {
- const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
- if ((double) when.beats > bpb / 2.0) {
- ++when.bars;
- }
- when.beats = 1;
- when.ticks = 0;
- }
-
- return;
-
- } else if (sub_num == 0) {
- const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
- if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
- ++when.beats;
- while ((double) when.beats > bpb) {
- ++when.bars;
- when.beats -= (uint32_t) floor (bpb);
- }
- }
- when.ticks = 0;
-
- return;
- }
-
- const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
-
- if (dir > 0) {
- /* round to next (or same iff dir == RoundUpMaybe) */
-
- uint32_t mod = when.ticks % ticks_one_subdivisions_worth;
-
- if (mod == 0 && dir == RoundUpMaybe) {
- /* right on the subdivision, which is fine, so do nothing */
-
- } else if (mod == 0) {
- /* right on the subdivision, so the difference is just the subdivision ticks */
- when.ticks += ticks_one_subdivisions_worth;
-
- } else {
- /* not on subdivision, compute distance to next subdivision */
-
- when.ticks += ticks_one_subdivisions_worth - mod;
- }
-
- if (when.ticks >= BBT_Time::ticks_per_beat) {
- ++when.beats;
- const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
- if ((double) when.beats > bpb) {
- ++when.bars;
- when.beats = 1;
- }
- when.ticks -= BBT_Time::ticks_per_beat;
- }
-
- } else if (dir < 0) {
- /* round to previous (or same iff dir == RoundDownMaybe) */
-
- uint32_t difference = when.ticks % ticks_one_subdivisions_worth;
-
- if (difference == 0 && dir == RoundDownAlways) {
- /* right on the subdivision, but force-rounding down,
- so the difference is just the subdivision ticks */
- difference = ticks_one_subdivisions_worth;
- }
-
- if (when.ticks < difference) {
- --when.beats;
- const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
- if ((double) when.beats < bpb) {
- --when.bars;
- //when.beats = 1;
- }
- when.ticks = BBT_Time::ticks_per_beat - when.ticks;
- } else {
- when.ticks -= difference;
- }
-
- } else {
- /* round to nearest */ double rem;
- if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
- /* closer to the next subdivision, so shift forward */
-
- when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
-
- if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
- ++when.beats;
- when.ticks -= Timecode::BBT_Time::ticks_per_beat;
- }
-
- } else if (rem > 0) {
- /* closer to previous subdivision, so shift backward */
-
- if (rem > when.ticks) {
- if (when.beats == 0) {
- /* can't go backwards past zero, so ... */
- }
- /* step back to previous beat */
- --when.beats;
- when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
- } else {
- when.ticks = when.ticks - rem;
- }
- }
- }
-}
-
framepos_t
TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
- BBT_Time bbt (beats_to_bbt_locked (_metrics, beat_at_framepos));
+ BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
switch (type) {
case Bar:
pos = frame_at_beat_locked (_metrics, cnt);
const TempoSection tempo = tempo_section_at_locked (_metrics, pos);
const MeterSection meter = meter_section_at_locked (_metrics, pos);
- const BBT_Time bbt = beats_to_bbt (cnt);
- points.push_back (BBTPoint (meter, tempo_at_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
+ const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
+ points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
++cnt;
}
}
return ts_at->frames_per_beat (_frame_rate);
}
-const Tempo
-TempoMap::tempo_at_locked (const Metrics& metrics, const framepos_t& frame) const
-{
- TempoSection* prev_t = 0;
-
- Metrics::const_iterator i;
-
- for (i = _metrics.begin(); i != _metrics.end(); ++i) {
- TempoSection* t;
- if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
- if (!t->active()) {
- continue;
- }
- if ((prev_t) && t->frame() > frame) {
- /* t is the section past frame */
- const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
- const Tempo ret_tempo (ret_bpm, prev_t->note_type());
- return ret_tempo;
- }
- prev_t = t;
- }
- }
-
- const double ret = prev_t->beats_per_minute();
- const Tempo ret_tempo (ret, prev_t->note_type ());
-
- return ret_tempo;
-}
-
-const Tempo
-TempoMap::tempo_at (const framepos_t& frame) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return tempo_at_locked (_metrics, frame);
-}
-
const MeterSection&
TempoMap::meter_section_at_locked (const Metrics& metrics, framepos_t frame) const
{
}
const Meter&
-TempoMap::meter_at (framepos_t frame) const
+TempoMap::meter_at_frame (framepos_t frame) const
{
TempoMetric m (metric_at (frame));
return m.meter();
continue;
}
const double beat = beat_at_pulse_locked (_metrics, t->pulse());
- pair<double, BBT_Time> start = make_pair (beat, beats_to_bbt_locked (_metrics, beat));
+ pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
ms->set_beat (start);
ms->set_pulse (t->pulse());
}
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- BBT_Time pos_bbt = beats_to_bbt_locked (_metrics, beat_at_frame_locked (_metrics, pos));
+ BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
pos_bbt.ticks += op.ticks;
if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
++pos_bbt.beats;
}
pos_bbt.beats += op.beats;
/* the meter in effect will start on the bar */
- double divisions_per_bar = meter_section_at_beat (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
+ double divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
while (pos_bbt.beats >= divisions_per_bar + 1) {
++pos_bbt.bars;
- divisions_per_bar = meter_section_at_beat (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
+ divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
pos_bbt.beats -= divisions_per_bar;
}
pos_bbt.bars += op.bars;