rename Tempo _beats_per_minute to _note_types_per_minute, provide pulse helpers.

- adds quarter_notes_per_minute(), note_divisions_per_minute (double)
	  pulses_per_minute() and frames_per_quarter_note()

	- this should be a no-op except for the use of tempo by
	  the vst callback which definitely uses quarter notes per minute.

	- the XML node for TempoSection named 'beats-per-minute'
	  has been renamed.
This commit is contained in:
nick_m 2016-11-06 05:14:20 +11:00
parent e52f90357e
commit 33e95a1577
18 changed files with 282 additions and 179 deletions

View file

@ -1316,7 +1316,8 @@ AudioClock::set_bbt (framepos_t when, framecnt_t offset, bool /*force*/)
TempoMetric m (_session->tempo_map().metric_at (pos)); TempoMetric m (_session->tempo_map().metric_at (pos));
sprintf (buf, "%-5.3f", _session->tempo_map().tempo_at_frame (pos).beats_per_minute()); sprintf (buf, "%-5.3f/%f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute(), m.tempo().note_type());
/* XXX this doesn't fit inside the container. */
_left_layout->set_markup (string_compose ("<span size=\"%1\">" TXTSPAN "%3</span> <span foreground=\"green\">%2</span></span>", _left_layout->set_markup (string_compose ("<span size=\"%1\">" TXTSPAN "%3</span> <span foreground=\"green\">%2</span></span>",
INFO_FONT_SIZE, buf, _("Tempo"))); INFO_FONT_SIZE, buf, _("Tempo")));

View file

@ -274,7 +274,7 @@ AutomationController::set_freq_beats(double beats)
const ARDOUR::Session& session = _controllable->session(); const ARDOUR::Session& session = _controllable->session();
const framepos_t pos = session.transport_frame(); const framepos_t pos = session.transport_frame();
const ARDOUR::Tempo& tempo = session.tempo_map().tempo_at_frame (pos); const ARDOUR::Tempo& tempo = session.tempo_map().tempo_at_frame (pos);
const double bpm = tempo.beats_per_minute(); const double bpm = tempo.note_types_per_minute();
const double bps = bpm / 60.0; const double bps = bpm / 60.0;
const double freq = bps / beats; const double freq = bps / beats;
_controllable->set_value(clamp(freq, desc.lower, desc.upper), Controllable::NoGroup); _controllable->set_value(clamp(freq, desc.lower, desc.upper), Controllable::NoGroup);

View file

@ -3279,7 +3279,7 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
_marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker")); _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
_real_section = &_marker->tempo(); _real_section = &_marker->tempo();
_movable = _real_section->movable(); _movable = _real_section->movable();
_grab_bpm = _real_section->beats_per_minute(); _grab_bpm = _real_section->note_types_per_minute();
assert (_marker); assert (_marker);
} }
@ -3312,7 +3312,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
// mvc drag - create a dummy marker to catch events, hide it. // mvc drag - create a dummy marker to catch events, hide it.
char name[64]; char name[64];
snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute()); snprintf (name, sizeof (name), "%.2f", _marker->tempo().note_types_per_minute());
TempoSection section (_marker->tempo()); TempoSection section (_marker->tempo());
@ -3443,8 +3443,8 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame())); _tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame()));
ostringstream sstr; ostringstream sstr;
sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (adjusted_current_frame (event)).beats_per_minute() << "\n"; sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (adjusted_current_frame (event)).note_types_per_minute() << "\n";
sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute(); sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute();
show_verbose_cursor_text (sstr.str()); show_verbose_cursor_text (sstr.str());
finished (event, false); finished (event, false);
} }
@ -3497,8 +3497,8 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move)
_editor->session()->tempo_map().gui_dilate_tempo (_tempo, map.frame_at_quarter_note (_grab_qn), pf); _editor->session()->tempo_map().gui_dilate_tempo (_tempo, map.frame_at_quarter_note (_grab_qn), pf);
} }
ostringstream sstr; ostringstream sstr;
sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (pf).beats_per_minute() << "\n"; sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (pf).note_types_per_minute() << "\n";
sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute(); sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute();
show_verbose_cursor_text (sstr.str()); show_verbose_cursor_text (sstr.str());
} }

View file

@ -1404,7 +1404,7 @@ Editor::toggle_marker_lock_style ()
} else if (tm) { } else if (tm) {
TempoSection* tsp = &tm->tempo(); TempoSection* tsp = &tm->tempo();
const Tempo tempo (tsp->beats_per_minute()); const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type());
const double pulse = tsp->pulse(); const double pulse = tsp->pulse();
const framepos_t frame = tsp->frame(); const framepos_t frame = tsp->frame();
const TempoSection::Type type = tsp->type(); const TempoSection::Type type = tsp->type();
@ -1431,7 +1431,7 @@ Editor::toggle_tempo_type ()
if (tm) { if (tm) {
TempoSection* tsp = &tm->tempo(); TempoSection* tsp = &tm->tempo();
const Tempo tempo (tsp->beats_per_minute(), tsp->note_type()); const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type());
const double pulse = tsp->pulse(); const double pulse = tsp->pulse();
const framepos_t frame = tsp->frame(); const framepos_t frame = tsp->frame();
const TempoSection::Type type = (tsp->type() == TempoSection::Ramp) ? TempoSection::Constant : TempoSection::Ramp; const TempoSection::Type type = (tsp->type() == TempoSection::Ramp) ? TempoSection::Constant : TempoSection::Ramp;

View file

@ -100,13 +100,13 @@ Editor::draw_metric_marks (const Metrics& metrics)
} }
} else if ((ts = dynamic_cast<const TempoSection*>(*i)) != 0) { } else if ((ts = dynamic_cast<const TempoSection*>(*i)) != 0) {
if (UIConfiguration::instance().get_allow_non_quarter_pulse()) { if (UIConfiguration::instance().get_allow_non_quarter_pulse()) {
snprintf (buf, sizeof (buf), "%.3f/%.0f", ts->beats_per_minute(), ts->note_type()); snprintf (buf, sizeof (buf), "%.3f/%.0f", ts->note_types_per_minute(), ts->note_type());
} else { } else {
snprintf (buf, sizeof (buf), "%.3f", ts->beats_per_minute()); snprintf (buf, sizeof (buf), "%.3f", ts->note_types_per_minute());
} }
max_tempo = max (max_tempo, ts->beats_per_minute()); max_tempo = max (max_tempo, ts->note_types_per_minute());
min_tempo = min (min_tempo, ts->beats_per_minute()); min_tempo = min (min_tempo, ts->note_types_per_minute());
tempo_curves.push_back (new TempoCurve (*this, *tempo_group, UIConfiguration::instance().color ("tempo curve"), tempo_curves.push_back (new TempoCurve (*this, *tempo_group, UIConfiguration::instance().color ("tempo curve"),
*(const_cast<TempoSection*>(ts)), ts->frame(), false)); *(const_cast<TempoSection*>(ts)), ts->frame(), false));
@ -147,7 +147,7 @@ Editor::draw_metric_marks (const Metrics& metrics)
TempoMarker* tempo_marker; TempoMarker* tempo_marker;
if ((tempo_marker = dynamic_cast<TempoMarker*> (*x)) != 0) { if ((tempo_marker = dynamic_cast<TempoMarker*> (*x)) != 0) {
tempo_marker->update_height_mark ((tempo_marker->tempo().beats_per_minute() - min_tempo) / max (10.0, max_tempo - min_tempo)); tempo_marker->update_height_mark ((tempo_marker->tempo().note_types_per_minute() - min_tempo) / max (10.0, max_tempo - min_tempo));
} }
} }
} }
@ -208,11 +208,17 @@ Editor::marker_position_changed ()
if ((ts = &tempo_marker->tempo()) != 0) { if ((ts = &tempo_marker->tempo()) != 0) {
tempo_marker->set_position (ts->frame ()); tempo_marker->set_position (ts->frame ());
char buf[64]; char buf[64];
snprintf (buf, sizeof (buf), "%.3f", ts->beats_per_minute());
if (UIConfiguration::instance().get_allow_non_quarter_pulse()) {
snprintf (buf, sizeof (buf), "%.3f/%.0f", ts->note_types_per_minute(), ts->note_type());
} else {
snprintf (buf, sizeof (buf), "%.3f", ts->note_types_per_minute());
}
tempo_marker->set_name (buf); tempo_marker->set_name (buf);
max_tempo = max (max_tempo, ts->beats_per_minute()); max_tempo = max (max_tempo, ts->note_types_per_minute());
min_tempo = min (min_tempo, ts->beats_per_minute()); min_tempo = min (min_tempo, ts->note_types_per_minute());
} }
} }
if ((meter_marker = dynamic_cast<MeterMarker*> (*x)) != 0) { if ((meter_marker = dynamic_cast<MeterMarker*> (*x)) != 0) {
@ -248,7 +254,7 @@ Editor::marker_position_changed ()
for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) { for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) {
TempoMarker* tempo_marker; TempoMarker* tempo_marker;
if ((tempo_marker = dynamic_cast<TempoMarker*> (*x)) != 0) { if ((tempo_marker = dynamic_cast<TempoMarker*> (*x)) != 0) {
tempo_marker->update_height_mark ((tempo_marker->tempo().beats_per_minute() - min_tempo) / max (max_tempo - min_tempo, 10.0)); tempo_marker->update_height_mark ((tempo_marker->tempo().note_types_per_minute() - min_tempo) / max (max_tempo - min_tempo, 10.0));
} }
} }

View file

@ -26,7 +26,7 @@ void TempoCurve::setup_sizes(const double timebar_height)
{ {
curve_height = floor (timebar_height) - 2.5; curve_height = floor (timebar_height) - 2.5;
} }
/* ignores Tempo note type - only note_types_per_minute is potentially curved */
TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint32 rgba, ARDOUR::TempoSection& temp, framepos_t frame, bool handle_events) TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint32 rgba, ARDOUR::TempoSection& temp, framepos_t frame, bool handle_events)
: editor (ed) : editor (ed)
@ -34,8 +34,8 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint
, _curve (0) , _curve (0)
, _shown (false) , _shown (false)
, _color (rgba) , _color (rgba)
, _min_tempo (temp.beats_per_minute()) , _min_tempo (temp.note_types_per_minute())
, _max_tempo (temp.beats_per_minute()) , _max_tempo (temp.note_types_per_minute())
, _tempo (temp) , _tempo (temp)
{ {
@ -44,12 +44,12 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint
group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (unit_position, 1)); group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (unit_position, 1));
#ifdef CANVAS_DEBUG #ifdef CANVAS_DEBUG
group->name = string_compose ("TempoCurve::group for %1", _tempo.beats_per_minute()); group->name = string_compose ("TempoCurve::group for %1", _tempo.note_types_per_minute());
#endif #endif
_curve = new ArdourCanvas::FramedCurve (group); _curve = new ArdourCanvas::FramedCurve (group);
#ifdef CANVAS_DEBUG #ifdef CANVAS_DEBUG
_curve->name = string_compose ("TempoCurve::curve for %1", _tempo.beats_per_minute()); _curve->name = string_compose ("TempoCurve::curve for %1", _tempo.note_types_per_minute());
#endif #endif
_curve->set_points_per_segment (3); _curve->set_points_per_segment (3);
points = new ArdourCanvas::Points (); points = new ArdourCanvas::Points ();
@ -113,14 +113,14 @@ TempoCurve::set_position (framepos_t frame, framepos_t end_frame)
points->push_back (ArdourCanvas::Duple (0.0, curve_height)); points->push_back (ArdourCanvas::Duple (0.0, curve_height));
if (end_frame == (framepos_t) UINT32_MAX) { if (end_frame == (framepos_t) UINT32_MAX) {
const double tempo_at = _tempo.beats_per_minute(); const double tempo_at = _tempo.note_types_per_minute();
const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height); const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height);
points->push_back (ArdourCanvas::Duple (0.0, y_pos)); points->push_back (ArdourCanvas::Duple (0.0, y_pos));
points->push_back (ArdourCanvas::Duple (ArdourCanvas::COORD_MAX - 5.0, y_pos)); points->push_back (ArdourCanvas::Duple (ArdourCanvas::COORD_MAX - 5.0, y_pos));
} else if (_tempo.type() == ARDOUR::TempoSection::Constant) { } else if (_tempo.type() == ARDOUR::TempoSection::Constant) {
const double tempo_at = _tempo.beats_per_minute(); const double tempo_at = _tempo.note_types_per_minute();
const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height); const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height);
points->push_back (ArdourCanvas::Duple (0.0, y_pos)); points->push_back (ArdourCanvas::Duple (0.0, y_pos));

View file

@ -48,7 +48,7 @@ TempoDialog::TempoDialog (TempoMap& map, framepos_t frame, const string&)
Tempo tempo (map.tempo_at_frame (frame)); Tempo tempo (map.tempo_at_frame (frame));
Timecode::BBT_Time when (map.bbt_at_frame (frame)); Timecode::BBT_Time when (map.bbt_at_frame (frame));
init (when, tempo.beats_per_minute(), tempo.note_type(), TempoSection::Constant, true, MusicTime); init (when, tempo.note_types_per_minute(), tempo.note_type(), TempoSection::Constant, true, MusicTime);
} }
TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&) TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
@ -63,7 +63,7 @@ TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
, tap_tempo_button (_("Tap tempo")) , tap_tempo_button (_("Tap tempo"))
{ {
Timecode::BBT_Time when (map.bbt_at_frame (section.frame())); Timecode::BBT_Time when (map.bbt_at_frame (section.frame()));
init (when, section.beats_per_minute(), section.note_type(), section.type(), section.movable(), section.position_lock_style()); init (when, section.note_types_per_minute(), section.note_type(), section.type(), section.movable(), section.position_lock_style());
} }
void void

View file

@ -77,11 +77,11 @@ TempoLines::draw_ticks (std::vector<ARDOUR::TempoMap::BBTPoint>& grid,
if (grid.begin()->c != 0.0) { if (grid.begin()->c != 0.0) {
const double beat_divisions = (l / ((double) divisions)) * (grid.begin()->tempo.note_type() / grid.begin()->meter.note_divisor()); const double beat_divisions = (l / ((double) divisions)) * (grid.begin()->tempo.note_type() / grid.begin()->meter.note_divisor());
const double time_at_division = log (((grid.begin()->c * (beat_divisions)) / const double time_at_division = log (((grid.begin()->c * (beat_divisions)) /
grid.begin()->tempo.beats_per_minute()) + 1) / grid.begin()->c; grid.begin()->tempo.note_types_per_minute()) + 1) / grid.begin()->c;
f = grid.begin()->frame + (framecnt_t) floor ((time_at_division * 60.0 * frame_rate) + 0.5); f = grid.begin()->frame + (framecnt_t) floor ((time_at_division * 60.0 * frame_rate) + 0.5);
} else { } else {
const double fpb = grid.begin()->tempo.frames_per_beat (frame_rate) const double fpb = grid.begin()->tempo.frames_per_note_type (frame_rate)
* (grid.begin()->tempo.note_type() / grid.begin()->meter.note_divisor()); * (grid.begin()->tempo.note_type() / grid.begin()->meter.note_divisor());
f = grid.begin()->frame + (l * (fpb / (double) divisions)); f = grid.begin()->frame + (l * (fpb / (double) divisions));

View file

@ -54,25 +54,32 @@ class LIBARDOUR_API Tempo {
* @param type Note Type (default `4': quarter note) * @param type Note Type (default `4': quarter note)
*/ */
Tempo (double npm, double type=4.0) // defaulting to quarter note Tempo (double npm, double type=4.0) // defaulting to quarter note
: _beats_per_minute (npm), _note_type(type) {} : _note_types_per_minute (npm), _note_type(type) {}
/* double note_types_per_minute () const { return _note_types_per_minute; }
note types per minute. void set_note_types_per_minute (double npm) { _note_types_per_minute = npm; }
*/
double beats_per_minute () const { return _beats_per_minute; }
void set_beats_per_minute (double bpm) { _beats_per_minute = bpm; }
double note_type () const { return _note_type; } double note_type () const { return _note_type; }
/** audio samples per quarter note beat.
* this is only useful for constant tempo and should not be used. double note_divisions_per_minute (double note_type) const { return _note_types_per_minute * (note_type / _note_type); }
* if you want an instantaneous value for this, use frames_per_beat_at() instead. double quarter_notes_per_minute () const { return note_divisions_per_minute (4.0); }
double pulses_per_minute () const { return note_divisions_per_minute (1.0); }
/** audio samples per note type.
* if you want an instantaneous value for this, use TempoMap::frames_per_quarter_note_at() instead.
* @param sr samplerate * @param sr samplerate
*/ */
double frames_per_beat (framecnt_t sr) const { double frames_per_note_type (framecnt_t sr) const {
return (60.0 * sr) / _beats_per_minute; return (60.0 * sr) / _note_types_per_minute;
}
/** audio samples per quarter note.
* if you want an instantaneous value for this, use TempoMap::frames_per_quarter_note_at() instead.
* @param sr samplerate
*/
double frames_per_quarter_note (framecnt_t sr) const {
return (60.0 * sr) / quarter_notes_per_minute ();
} }
protected: protected:
double _beats_per_minute; double _note_types_per_minute;
double _note_type; double _note_type;
}; };
@ -313,7 +320,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f, BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f,
uint32_t b, uint32_t e, double func_c) uint32_t b, uint32_t e, double func_c)
: frame (f), meter (m.divisions_per_bar(), m.note_divisor()), tempo (t.beats_per_minute(), t.note_type()), c (func_c), bar (b), beat (e) {} : frame (f), meter (m.divisions_per_bar(), m.note_divisor()), tempo (t.note_types_per_minute(), t.note_type()), c (func_c), bar (b), beat (e) {}
Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); } Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
operator Timecode::BBT_Time() const { return bbt(); } operator Timecode::BBT_Time() const { return bbt(); }
@ -332,8 +339,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
static const Tempo& default_tempo() { return _default_tempo; } static const Tempo& default_tempo() { return _default_tempo; }
static const Meter& default_meter() { return _default_meter; } static const Meter& default_meter() { return _default_meter; }
/* because tempos may be ramped, this is only valid for the instant requested.*/ /* because tempi may be ramped, this is only valid for the instant requested.*/
double frames_per_beat_at (const framepos_t&, const framecnt_t& sr) const; double frames_per_quarter_note_at (const framepos_t&, const framecnt_t& sr) const;
const TempoSection& tempo_section_at_frame (framepos_t frame) const; const TempoSection& tempo_section_at_frame (framepos_t frame) const;
const MeterSection& meter_section_at_frame (framepos_t frame) const; const MeterSection& meter_section_at_frame (framepos_t frame) const;

View file

@ -1370,8 +1370,10 @@ LuaBindings::common (lua_State* L)
.beginClass <Tempo> ("Tempo") .beginClass <Tempo> ("Tempo")
.addConstructor <void (*) (double, double)> () .addConstructor <void (*) (double, double)> ()
.addFunction ("note_type", &Tempo::note_type) .addFunction ("note_type", &Tempo::note_type)
.addFunction ("beats_per_minute", &Tempo::beats_per_minute) .addFunction ("note_types_per_minute", &Tempo::note_types_per_minute)
.addFunction ("frames_per_beat", &Tempo::frames_per_beat) .addFunction ("quarter_notes_per_minute", &Tempo::quarter_notes_per_minute)
.addFunction ("frames_per_quarter_note", &Tempo::frames_per_quarter_note)
.addFunction ("frames_per_note_type", &Tempo::frames_per_note_type)
.endClass () .endClass ()
.beginClass <Meter> ("Meter") .beginClass <Meter> ("Meter")

View file

@ -2494,7 +2494,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
} }
if (_bpm_control_port) { if (_bpm_control_port) {
*_bpm_control_port = tmap.tempo_at_frame (start).beats_per_minute(); *_bpm_control_port = tmap.tempo_at_frame (start).note_types_per_minute();
} }
#ifdef LV2_EXTENDED #ifdef LV2_EXTENDED
@ -2566,7 +2566,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
if (valid && (flags & PORT_INPUT)) { if (valid && (flags & PORT_INPUT)) {
if ((flags & PORT_POSITION)) { if ((flags & PORT_POSITION)) {
Timecode::BBT_Time bbt (tmap.bbt_at_frame (start)); Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
double bpm = tmap.tempo_at_frame (start).beats_per_minute(); double bpm = tmap.tempo_at_frame (start).note_types_per_minute();
double beatpos = (bbt.bars - 1) * tmetric.meter().divisions_per_bar() double beatpos = (bbt.bars - 1) * tmetric.meter().divisions_per_bar()
+ (bbt.beats - 1) + (bbt.beats - 1)
+ (bbt.ticks / Timecode::BBT_Time::ticks_per_beat); + (bbt.ticks / Timecode::BBT_Time::ticks_per_beat);
@ -2608,7 +2608,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
tmetric.set_metric(metric); tmetric.set_metric(metric);
Timecode::BBT_Time bbt; Timecode::BBT_Time bbt;
bbt = tmap.bbt_at_frame (metric->frame()); bbt = tmap.bbt_at_frame (metric->frame());
double bpm = tmap.tempo_at_frame (start/*XXX*/).beats_per_minute(); double bpm = tmap.tempo_at_frame (start/*XXX*/).note_types_per_minute();
write_position(&_impl->forge, _ev_buffers[port_index], write_position(&_impl->forge, _ev_buffers[port_index],
tmetric, bbt, speed, bpm, tmetric, bbt, speed, bpm,
metric->frame(), metric->frame(),
@ -2881,7 +2881,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
* so it needs to be realative to that. * so it needs to be realative to that.
*/ */
TempoMetric t = tmap.metric_at(start); TempoMetric t = tmap.metric_at(start);
_current_bpm = tmap.tempo_at_frame (start).beats_per_minute(); _current_bpm = tmap.tempo_at_frame (start).note_types_per_minute();
Timecode::BBT_Time bbt (tmap.bbt_at_frame (start)); Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
double beatpos = (bbt.bars - 1) * t.meter().divisions_per_bar() double beatpos = (bbt.bars - 1) * t.meter().divisions_per_bar()
+ (bbt.beats - 1) + (bbt.beats - 1)

View file

@ -82,11 +82,7 @@ MIDIClock_Slave::rebind (MidiPort& port)
void void
MIDIClock_Slave::calculate_one_ppqn_in_frames_at(framepos_t time) MIDIClock_Slave::calculate_one_ppqn_in_frames_at(framepos_t time)
{ {
const Tempo& current_tempo = session->tempo_map().tempo_at_frame (time); const double frames_per_quarter_note = session->tempo_map().frames_per_quarter_note_at (time, session->frame_rate());
double const frames_per_beat = session->tempo_map().frames_per_beat_at (time, session->frame_rate());
double quarter_notes_per_beat = 4.0 / current_tempo.note_type();
double frames_per_quarter_note = frames_per_beat / quarter_notes_per_beat;
one_ppqn_in_frames = frames_per_quarter_note / double (ppqn); one_ppqn_in_frames = frames_per_quarter_note / double (ppqn);
// DEBUG_TRACE (DEBUG::MidiClock, string_compose ("at %1, one ppqn = %2\n", time, one_ppqn_in_frames)); // DEBUG_TRACE (DEBUG::MidiClock, string_compose ("at %1, one ppqn = %2\n", time, one_ppqn_in_frames));

View file

@ -208,7 +208,7 @@ intptr_t Session::vst_callback (
if (value & (kVstTempoValid)) { if (value & (kVstTempoValid)) {
const Tempo& t (session->tempo_map().tempo_at_frame (now)); const Tempo& t (session->tempo_map().tempo_at_frame (now));
timeinfo->tempo = t.beats_per_minute (); timeinfo->tempo = t.quarter_notes_per_minute ();
newflags |= (kVstTempoValid); newflags |= (kVstTempoValid);
} }
if (value & (kVstTimeSigValid)) { if (value & (kVstTimeSigValid)) {
@ -333,7 +333,7 @@ intptr_t Session::vst_callback (
// returns tempo (in bpm * 10000) at sample frame location passed in <value> // returns tempo (in bpm * 10000) at sample frame location passed in <value>
if (session) { if (session) {
const Tempo& t (session->tempo_map().tempo_at_frame (value)); const Tempo& t (session->tempo_map().tempo_at_frame (value));
return t.beats_per_minute() * 1000; return t.quarter_notes_per_minute() * 1000;
} else { } else {
return 0; return 0;
} }

View file

@ -71,7 +71,7 @@ Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
The return value IS NOT interpretable in terms of "beats". The return value IS NOT interpretable in terms of "beats".
*/ */
return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type())); return (60.0 * sr) / (tempo.note_types_per_minute() * (_note_type/tempo.note_type()));
} }
double double
@ -97,6 +97,7 @@ TempoSection::TempoSection (const XMLNode& node, framecnt_t sample_rate)
double pulse; double pulse;
uint32_t frame; uint32_t frame;
double minute; double minute;
bool had_beats_per_minute = false;
_legacy_bbt = BBT_Time (0, 0, 0); _legacy_bbt = BBT_Time (0, 0, 0);
@ -136,13 +137,23 @@ TempoSection::TempoSection (const XMLNode& node, framecnt_t sample_rate)
} }
} }
if ((prop = node.property ("beats-per-minute")) == 0) { /* replace old beats-per-minute with note-types-per-minute */
error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg; if ((prop = node.property ("beats-per-minute")) != 0) {
throw failed_constructor(); info << _("Renaming legacy \"beats-per-minute\" XML node to note-types-per-minute") << endmsg;
if (sscanf (prop->value().c_str(), "%lf", &_note_types_per_minute) != 1 || _note_types_per_minute < 0.0) {
error << _("TempoSection XML node has an illegal \"beats-per-minutee\" value") << endmsg;
throw failed_constructor();
}
had_beats_per_minute = true;
} }
if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) { if ((prop = node.property ("note-types-per-minute")) != 0) {
error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg; if (sscanf (prop->value().c_str(), "%lf", &_note_types_per_minute) != 1 || _note_types_per_minute < 0.0) {
error << _("TempoSection XML node has an illegal \"note-types-per-minute\" value") << endmsg;
throw failed_constructor();
}
} else if (!had_beats_per_minute) {
error << _("TempoSection XML node has no \"note-types-per-minute\" or \"beats-per-minute\" property") << endmsg;
throw failed_constructor(); throw failed_constructor();
} }
@ -206,8 +217,8 @@ TempoSection::get_state() const
root->add_property ("frame", buf); root->add_property ("frame", buf);
snprintf (buf, sizeof (buf), "%lf", minute()); snprintf (buf, sizeof (buf), "%lf", minute());
root->add_property ("minute", buf); root->add_property ("minute", buf);
snprintf (buf, sizeof (buf), "%lf", _beats_per_minute); snprintf (buf, sizeof (buf), "%lf", _note_types_per_minute);
root->add_property ("beats-per-minute", buf); root->add_property ("note-types-per-minute", buf);
snprintf (buf, sizeof (buf), "%lf", _note_type); snprintf (buf, sizeof (buf), "%lf", _note_type);
root->add_property ("note-type", buf); root->add_property ("note-type", buf);
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no"); snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
@ -234,7 +245,7 @@ TempoSection::tempo_at_minute (const double& m) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return beats_per_minute(); return note_types_per_minute();
} }
return _tempo_at_time (m - minute()); return _tempo_at_time (m - minute());
@ -246,13 +257,13 @@ TempoSection::tempo_at_minute (const double& m) const
note that the tempo map may have multiple such values. note that the tempo map may have multiple such values.
*/ */
double double
TempoSection::minute_at_tempo (const double& bpm, const double& p) const TempoSection::minute_at_tempo (const double& npm, const double& p) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return (((p - pulse()) * note_type()) / beats_per_minute()) + minute(); return ((p - pulse()) / pulses_per_minute()) + minute();
} }
return _time_at_tempo (bpm) + minute(); return _time_at_tempo (npm) + minute();
} }
/** returns the tempo in note types per minute at the supplied pulse. /** returns the tempo in note types per minute at the supplied pulse.
@ -262,7 +273,7 @@ TempoSection::tempo_at_pulse (const double& p) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return beats_per_minute(); return note_types_per_minute();
} }
return _tempo_at_pulse (p - pulse()); return _tempo_at_pulse (p - pulse());
@ -273,14 +284,14 @@ TempoSection::tempo_at_pulse (const double& p) const
note that the session tempo map may have multiple locations where a given tempo occurs. note that the session tempo map may have multiple locations where a given tempo occurs.
*/ */
double double
TempoSection::pulse_at_tempo (const double& bpm, const double& m) const TempoSection::pulse_at_tempo (const double& npm, const double& m) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
const double pulses = (((m - minute()) * beats_per_minute()) / note_type()) + pulse(); const double pulses = ((m - minute()) * pulses_per_minute()) + pulse();
return pulses; return pulses;
} }
return _pulse_at_tempo (bpm) + pulse(); return _pulse_at_tempo (npm) + pulse();
} }
/** returns the pulse at the supplied session-relative minute. /** returns the pulse at the supplied session-relative minute.
@ -289,7 +300,7 @@ double
TempoSection::pulse_at_minute (const double& m) const TempoSection::pulse_at_minute (const double& m) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return (((m - minute()) * beats_per_minute()) / _note_type) + pulse(); return ((m - minute()) * pulses_per_minute()) + pulse();
} }
return _pulse_at_time (m - minute()) + pulse(); return _pulse_at_time (m - minute()) + pulse();
@ -301,7 +312,7 @@ double
TempoSection::minute_at_pulse (const double& p) const TempoSection::minute_at_pulse (const double& p) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return (((p - pulse()) * note_type()) / beats_per_minute()) + minute(); return ((p - pulse()) / pulses_per_minute()) + minute();
} }
return _time_at_pulse (p - pulse()) + minute(); return _time_at_pulse (p - pulse()) + minute();
@ -382,82 +393,83 @@ https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Te
*/ */
/* /** compute this ramp's function constant from some tempo-pulse point
compute this ramp's function constant from some tempo-pulse point * @param end_npm end tempo (in note types per minute)
end tempo (in note types per minute) * @param end_pulse duration (pulses into global start) of some other position.
duration (pulses into global start) of some other position. * @return the calculated function constant
*/ */
double double
TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse) const TempoSection::compute_c_func_pulse (const double& end_npm, const double& end_pulse) const
{ {
double const log_tempo_ratio = log (end_bpm / beats_per_minute()); double const log_tempo_ratio = log (end_npm / note_types_per_minute());
return (beats_per_minute() * expm1 (log_tempo_ratio)) / ((end_pulse - pulse()) * _note_type); return (note_types_per_minute() * expm1 (log_tempo_ratio)) / ((end_pulse - pulse()) * _note_type);
} }
/* compute the function constant from some tempo-time point. /** compute the function constant from some tempo-time point.
tempo (note types/min.) * @param end_npm tempo (note types/min.)
distance (in minutes) from session origin * @param end_minute distance (in minutes) from session origin
* @return the calculated function constant
*/ */
double double
TempoSection::compute_c_func_minute (const double& end_bpm, const double& end_minute) const TempoSection::compute_c_func_minute (const double& end_npm, const double& end_minute) const
{ {
return c_func (end_bpm, end_minute - minute()); return c_func (end_npm, end_minute - minute());
} }
/* position function */ /* position function */
double double
TempoSection::a_func (double end_bpm, double c_func) const TempoSection::a_func (double end_npm, double c_func) const
{ {
return log (end_bpm / beats_per_minute()) / c_func; return log (end_npm / note_types_per_minute()) / c_func;
} }
/*function constant*/ /*function constant*/
double double
TempoSection::c_func (double end_bpm, double end_time) const TempoSection::c_func (double end_npm, double end_time) const
{ {
return log (end_bpm / beats_per_minute()) / end_time; return log (end_npm / note_types_per_minute()) / end_time;
} }
/* tempo in note types per minute at time in minutes */ /* tempo in note types per minute at time in minutes */
double double
TempoSection::_tempo_at_time (const double& time) const TempoSection::_tempo_at_time (const double& time) const
{ {
return exp (_c_func * time) * beats_per_minute(); return exp (_c_func * time) * note_types_per_minute();
} }
/* time in minutes at tempo in note types per minute */ /* time in minutes at tempo in note types per minute */
double double
TempoSection::_time_at_tempo (const double& tempo) const TempoSection::_time_at_tempo (const double& tempo) const
{ {
return log (tempo / beats_per_minute()) / _c_func; return log (tempo / note_types_per_minute()) / _c_func;
} }
/* pulse at tempo in note types per minute */ /* pulse at tempo in note types per minute */
double double
TempoSection::_pulse_at_tempo (const double& tempo) const TempoSection::_pulse_at_tempo (const double& tempo) const
{ {
return ((tempo - beats_per_minute()) / _c_func) / _note_type; return ((tempo - note_types_per_minute()) / _c_func) / _note_type;
} }
/* tempo in note types per minute at pulse */ /* tempo in note types per minute at pulse */
double double
TempoSection::_tempo_at_pulse (const double& pulse) const TempoSection::_tempo_at_pulse (const double& pulse) const
{ {
return (pulse * _note_type * _c_func) + beats_per_minute(); return (pulse * _note_type * _c_func) + note_types_per_minute();
} }
/* pulse at time in minutes */ /* pulse at time in minutes */
double double
TempoSection::_pulse_at_time (const double& time) const TempoSection::_pulse_at_time (const double& time) const
{ {
return expm1 (_c_func * time) * (beats_per_minute() / (_c_func * _note_type)); return (expm1 (_c_func * time) * (note_types_per_minute() / _c_func)) / _note_type;
} }
/* time in minutes at pulse */ /* time in minutes at pulse */
double double
TempoSection::_time_at_pulse (const double& pulse) const TempoSection::_time_at_pulse (const double& pulse) const
{ {
return log1p ((_c_func * pulse * _note_type) / beats_per_minute()) / _c_func; return log1p ((_c_func * pulse * _note_type) / note_types_per_minute()) / _c_func;
} }
/***********************************************************************/ /***********************************************************************/
@ -618,7 +630,7 @@ MeterSection::get_state() const
TempoSection - translates between time, musical pulse and tempo. TempoSection - translates between time, musical pulse and tempo.
has a musical location in whole notes (pulses). has a musical location in whole notes (pulses).
has a time location in minutes. has a time location in minutes.
Note that 'beats' in Tempo::beats_per_minute() are in fact note types per minute. Note that 'beats' in Tempo::note_types_per_minute() are in fact note types per minute.
(In the rest of tempo map,'beat' usually refers to accumulated BBT beats (pulse and meter based). (In the rest of tempo map,'beat' usually refers to accumulated BBT beats (pulse and meter based).
MeterSection - translates between BBT, meter-based beat and musical pulse. MeterSection - translates between BBT, meter-based beat and musical pulse.
@ -703,7 +715,7 @@ TempoMap::TempoMap (framecnt_t fr)
_frame_rate = fr; _frame_rate = fr;
BBT_Time start (1, 1, 0); BBT_Time start (1, 1, 0);
TempoSection *t = new TempoSection (0.0, 0.0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime, fr); TempoSection *t = new TempoSection (0.0, 0.0, _default_tempo.note_types_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime, fr);
MeterSection *m = new MeterSection (0.0, 0.0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime, fr); MeterSection *m = new MeterSection (0.0, 0.0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime, fr);
t->set_movable (false); t->set_movable (false);
@ -1005,7 +1017,7 @@ TempoSection*
TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, double minute TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, double minute
, TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter) , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter)
{ {
TempoSection* t = new TempoSection (pulse, minute, tempo.beats_per_minute(), tempo.note_type(), type, pls, _frame_rate); TempoSection* t = new TempoSection (pulse, minute, tempo.note_types_per_minute(), tempo.note_type(), type, pls, _frame_rate);
t->set_locked_to_meter (locked_to_meter); t->set_locked_to_meter (locked_to_meter);
bool solved = false; bool solved = false;
@ -1126,9 +1138,9 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, const BBT_Time& whe
} }
void void
TempoMap::change_initial_tempo (double beats_per_minute, double note_type) TempoMap::change_initial_tempo (double note_types_per_minute, double note_type)
{ {
Tempo newtempo (beats_per_minute, note_type); Tempo newtempo (note_types_per_minute, note_type);
TempoSection* t; TempoSection* t;
for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) { for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
@ -1148,9 +1160,9 @@ TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
} }
void void
TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type) TempoMap::change_existing_tempo_at (framepos_t where, double note_types_per_minute, double note_type)
{ {
Tempo newtempo (beats_per_minute, note_type); Tempo newtempo (note_types_per_minute, note_type);
TempoSection* prev; TempoSection* prev;
TempoSection* first; TempoSection* first;
@ -1298,14 +1310,14 @@ TempoMap::recompute_tempi (Metrics& metrics)
} }
if (prev_t) { if (prev_t) {
if (t->position_lock_style() == AudioTime) { if (t->position_lock_style() == AudioTime) {
prev_t->set_c_func (prev_t->compute_c_func_minute (t->beats_per_minute(), t->minute())); prev_t->set_c_func (prev_t->compute_c_func_minute (t->note_types_per_minute(), t->minute()));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute(), t->minute())); t->set_pulse (prev_t->pulse_at_tempo (t->note_types_per_minute(), t->minute()));
} }
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse())); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->note_types_per_minute(), t->pulse()));
t->set_minute (prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse())); t->set_minute (prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()));
} }
} }
@ -1602,7 +1614,7 @@ TempoMap::tempo_at_minute_locked (const Metrics& metrics, const double& minute)
} }
} }
const double ret = prev_t->beats_per_minute(); const double ret = prev_t->note_types_per_minute();
const Tempo ret_tempo (ret, prev_t->note_type ()); const Tempo ret_tempo (ret, prev_t->note_type ());
return ret_tempo; return ret_tempo;
@ -1625,7 +1637,7 @@ double
TempoMap::minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const TempoMap::minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
{ {
TempoSection* prev_t = 0; TempoSection* prev_t = 0;
const double tempo_bpm = tempo.beats_per_minute(); const double tempo_bpm = tempo.note_types_per_minute();
Metrics::const_iterator i; Metrics::const_iterator i;
@ -1638,14 +1650,14 @@ TempoMap::minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) co
continue; continue;
} }
const double t_bpm = t->beats_per_minute(); const double t_bpm = t->note_types_per_minute();
if (t_bpm == tempo_bpm) { if (t_bpm == tempo_bpm) {
return t->minute(); return t->minute();
} }
if (prev_t) { if (prev_t) {
const double prev_t_bpm = prev_t->beats_per_minute(); const double prev_t_bpm = prev_t->note_types_per_minute();
if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) { if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) {
return prev_t->minute_at_tempo (tempo_bpm, prev_t->pulse()); return prev_t->minute_at_tempo (tempo_bpm, prev_t->pulse());
@ -1681,7 +1693,7 @@ TempoMap::tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) co
} }
} }
const double ret = prev_t->beats_per_minute(); const double ret = prev_t->note_types_per_minute();
const Tempo ret_tempo (ret, prev_t->note_type ()); const Tempo ret_tempo (ret, prev_t->note_type ());
return ret_tempo; return ret_tempo;
@ -1691,7 +1703,7 @@ double
TempoMap::pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const TempoMap::pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
{ {
TempoSection* prev_t = 0; TempoSection* prev_t = 0;
const double tempo_bpm = tempo.beats_per_minute(); const double tempo_bpm = tempo.note_types_per_minute();
Metrics::const_iterator i; Metrics::const_iterator i;
@ -1704,14 +1716,14 @@ TempoMap::pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) con
continue; continue;
} }
const double t_bpm = t->beats_per_minute(); const double t_bpm = t->note_types_per_minute();
if (t_bpm == tempo_bpm) { if (t_bpm == tempo_bpm) {
return t->pulse(); return t->pulse();
} }
if (prev_t) { if (prev_t) {
const double prev_t_bpm = prev_t->beats_per_minute(); const double prev_t_bpm = prev_t->note_types_per_minute();
if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) { if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) {
return prev_t->pulse_at_tempo (tempo_bpm, prev_t->minute()); return prev_t->pulse_at_tempo (tempo_bpm, prev_t->minute());
@ -1822,7 +1834,7 @@ TempoMap::pulse_at_minute_locked (const Metrics& metrics, const double& minute)
} }
/* treated as constant for this ts */ /* treated as constant for this ts */
const double pulses_in_section = ((minute - prev_t->minute()) * prev_t->beats_per_minute()) / prev_t->note_type(); const double pulses_in_section = ((minute - prev_t->minute()) * prev_t->note_types_per_minute()) / prev_t->note_type();
return pulses_in_section + prev_t->pulse(); return pulses_in_section + prev_t->pulse();
} }
@ -1851,7 +1863,7 @@ TempoMap::minute_at_pulse_locked (const Metrics& metrics, const double& pulse) c
} }
} }
/* must be treated as constant, irrespective of _type */ /* must be treated as constant, irrespective of _type */
double const dtime = ((pulse - prev_t->pulse()) * prev_t->note_type()) / prev_t->beats_per_minute(); double const dtime = ((pulse - prev_t->pulse()) * prev_t->note_type()) / prev_t->note_types_per_minute();
return dtime + prev_t->minute(); return dtime + prev_t->minute();
} }
@ -2395,7 +2407,7 @@ TempoMap::check_solved (const Metrics& metrics) const
} }
/* precision check ensures tempo and frames align.*/ /* precision check ensures tempo and frames align.*/
if (t->frame() != frame_at_minute (prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse()))) { if (t->frame() != frame_at_minute (prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()))) {
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
return false; return false;
} }
@ -2498,12 +2510,12 @@ TempoMap::solve_map_minute (Metrics& imaginary, TempoSection* section, const dou
continue; continue;
} }
if (t->position_lock_style() == MusicTime) { if (t->position_lock_style() == MusicTime) {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse())); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->note_types_per_minute(), t->pulse()));
t->set_minute (prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse())); t->set_minute (prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()));
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_minute (t->beats_per_minute(), t->minute())); prev_t->set_c_func (prev_t->compute_c_func_minute (t->note_types_per_minute(), t->minute()));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute(), t->minute())); t->set_pulse (prev_t->pulse_at_tempo (t->note_types_per_minute(), t->minute()));
} }
} }
} }
@ -2512,9 +2524,9 @@ TempoMap::solve_map_minute (Metrics& imaginary, TempoSection* section, const dou
} }
if (section_prev) { if (section_prev) {
section_prev->set_c_func (section_prev->compute_c_func_minute (section->beats_per_minute(), minute)); section_prev->set_c_func (section_prev->compute_c_func_minute (section->note_types_per_minute(), minute));
if (!section->locked_to_meter()) { if (!section->locked_to_meter()) {
section->set_pulse (section_prev->pulse_at_tempo (section->beats_per_minute(), minute)); section->set_pulse (section_prev->pulse_at_tempo (section->note_types_per_minute(), minute));
} }
} }
@ -2566,12 +2578,12 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
continue; continue;
} }
if (t->position_lock_style() == MusicTime) { if (t->position_lock_style() == MusicTime) {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse())); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->note_types_per_minute(), t->pulse()));
t->set_minute (prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse())); t->set_minute (prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()));
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_minute (t->beats_per_minute(), t->minute())); prev_t->set_c_func (prev_t->compute_c_func_minute (t->note_types_per_minute(), t->minute()));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute(), t->minute())); t->set_pulse (prev_t->pulse_at_tempo (t->note_types_per_minute(), t->minute()));
} }
} }
} }
@ -2580,8 +2592,8 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
} }
if (section_prev) { if (section_prev) {
section_prev->set_c_func (section_prev->compute_c_func_pulse (section->beats_per_minute(), pulse)); section_prev->set_c_func (section_prev->compute_c_func_pulse (section->note_types_per_minute(), pulse));
section->set_minute (section_prev->minute_at_tempo (section->beats_per_minute(), pulse)); section->set_minute (section_prev->minute_at_tempo (section->note_types_per_minute(), pulse));
} }
#if (0) #if (0)
@ -3148,11 +3160,11 @@ TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
{ {
Glib::Threads::RWLock::WriterLock lm (lock); Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts); TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
tempo_copy->set_beats_per_minute (bpm.beats_per_minute()); tempo_copy->set_note_types_per_minute (bpm.note_types_per_minute());
recompute_tempi (future_map); recompute_tempi (future_map);
if (check_solved (future_map)) { if (check_solved (future_map)) {
ts->set_beats_per_minute (bpm.beats_per_minute()); ts->set_note_types_per_minute (bpm.note_types_per_minute());
recompute_map (_metrics); recompute_map (_metrics);
can_solve = true; can_solve = true;
} }
@ -3233,18 +3245,18 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) { if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) { if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame()) new_bpm = prev_t->note_types_per_minute() * ((frame - prev_to_prev_t->frame())
/ (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame())); / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
} else { } else {
new_bpm = prev_t->beats_per_minute(); new_bpm = prev_t->note_types_per_minute();
} }
} else { } else {
/* prev to prev is irrelevant */ /* prev to prev is irrelevant */
if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) { if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse())); new_bpm = prev_t->note_types_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
} else { } else {
new_bpm = prev_t->beats_per_minute(); new_bpm = prev_t->note_types_per_minute();
} }
} }
} else { } else {
@ -3252,18 +3264,18 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) { if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) { if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame()) new_bpm = prev_t->note_types_per_minute() * ((frame - prev_to_prev_t->frame())
/ (double) ((end_frame) - prev_to_prev_t->frame())); / (double) ((end_frame) - prev_to_prev_t->frame()));
} else { } else {
new_bpm = prev_t->beats_per_minute(); new_bpm = prev_t->note_types_per_minute();
} }
} else { } else {
/* prev_to_prev_t is irrelevant */ /* prev_to_prev_t is irrelevant */
if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) { if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame())); new_bpm = prev_t->note_types_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
} else { } else {
new_bpm = prev_t->beats_per_minute(); new_bpm = prev_t->note_types_per_minute();
} }
} }
} }
@ -3286,7 +3298,7 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
} }
pulse_ratio = (start_pulse / end_pulse); pulse_ratio = (start_pulse / end_pulse);
} }
new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio); new_bpm = prev_t->note_types_per_minute() * (pulse_ratio * frame_ratio);
} }
/* don't clamp and proceed here. /* don't clamp and proceed here.
@ -3297,12 +3309,12 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
return; return;
} }
new_bpm = min (new_bpm, (double) 1000.0); new_bpm = min (new_bpm, (double) 1000.0);
prev_t->set_beats_per_minute (new_bpm); prev_t->set_note_types_per_minute (new_bpm);
recompute_tempi (future_map); recompute_tempi (future_map);
recompute_meters (future_map); recompute_meters (future_map);
if (check_solved (future_map)) { if (check_solved (future_map)) {
ts->set_beats_per_minute (new_bpm); ts->set_note_types_per_minute (new_bpm);
recompute_tempi (_metrics); recompute_tempi (_metrics);
recompute_meters (_metrics); recompute_meters (_metrics);
} }
@ -3837,7 +3849,7 @@ TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& be
do that stuff based on the beat_at_frame and frame_at_beat api do that stuff based on the beat_at_frame and frame_at_beat api
*/ */
double double
TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const TempoMap::frames_per_quarter_note_at (const framepos_t& frame, const framecnt_t& sr) const
{ {
Glib::Threads::RWLock::ReaderLock lm (lock); Glib::Threads::RWLock::ReaderLock lm (lock);
@ -3862,10 +3874,10 @@ TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) con
} }
if (ts_after) { if (ts_after) {
return (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)); return (60.0 * _frame_rate) / ((ts_at->tempo_at_minute (minute_at_frame (frame)) / ts_at->note_type()) * 4.0);
} }
/* must be treated as constant tempo */ /* must be treated as constant tempo */
return ts_at->frames_per_beat (_frame_rate); return ts_at->frames_per_quarter_note (_frame_rate);
} }
const MeterSection& const MeterSection&
@ -4132,19 +4144,19 @@ TempoMap::dump (const Metrics& metrics, std::ostream& o) const
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) { for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) { if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() o << "Tempo @ " << *i << t->note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
<< " type= " << enum_2_string (t->type()) << ") " << " at pulse= " << t->pulse() << " type= " << enum_2_string (t->type()) << ") " << " at pulse= " << t->pulse()
<< " minute= " << t->minute() << " frame= " << t->frame() << " (movable? " << t->movable() << ')' << " minute= " << t->minute() << " frame= " << t->frame() << " (movable? " << t->movable() << ')'
<< " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl; << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
if (prev_t) { if (prev_t) {
o << std::setprecision (17) << " current : " << t->beats_per_minute() o << std::setprecision (17) << " current : " << t->note_types_per_minute()
<< " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl; << " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
o << " previous : " << prev_t->beats_per_minute() o << " previous : " << prev_t->note_types_per_minute()
<< " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl; << " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
o << " calculated : " << prev_t->tempo_at_pulse (t->pulse()) o << " calculated : " << prev_t->tempo_at_pulse (t->pulse())
<< " | " << prev_t->pulse_at_tempo (t->beats_per_minute(), t->minute()) << " | " << prev_t->pulse_at_tempo (t->note_types_per_minute(), t->minute())
<< " | " << frame_at_minute (prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse())) << " | " << frame_at_minute (prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()))
<< " | " << prev_t->minute_at_tempo (t->beats_per_minute(), t->pulse()) << std::endl; << " | " << prev_t->minute_at_tempo (t->note_types_per_minute(), t->pulse()) << std::endl;
} }
prev_t = t; prev_t = t;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
@ -4327,7 +4339,7 @@ operator<< (std::ostream& o, const Meter& m) {
std::ostream& std::ostream&
operator<< (std::ostream& o, const Tempo& t) { operator<< (std::ostream& o, const Tempo& t) {
return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute"; return o << t.note_types_per_minute() << " 1/" << t.note_type() << "'s per minute";
} }
std::ostream& std::ostream&

View file

@ -85,23 +85,23 @@ TempoTest::recomputeMapTest48 ()
/* tempo - frame */ /* tempo - frame */
CPPUNIT_ASSERT_EQUAL (framepos_t (288e3), map.frame_at_tempo (240.0)); CPPUNIT_ASSERT_EQUAL (framepos_t (288e3), map.frame_at_tempo (240.0));
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_frame (288e3).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_frame (288e3).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_frame (288e3 - 1).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_frame (288e3 - 1).note_types_per_minute(), 1e-17);
/* tempo - quarter note */ /* tempo - quarter note */
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (24.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (24.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (12.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (12.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (6.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (6.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (0.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (0.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (12.0, map.quarter_note_at_tempo (240.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (12.0, map.quarter_note_at_tempo (240.0), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, map.quarter_note_at_tempo (120.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, map.quarter_note_at_tempo (120.0), 1e-17);
/* tempo - internal minute interface */ /* tempo - internal minute interface */
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_minute_locked (map._metrics, 0.1).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_minute_locked (map._metrics, 0.1).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (0.1, map.minute_at_tempo_locked (map._metrics, tempoB), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (0.1, map.minute_at_tempo_locked (map._metrics, tempoB), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_pulse_locked (map._metrics, 3.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_pulse_locked (map._metrics, 3.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (3.0, map.pulse_at_tempo_locked (map._metrics, tempoB), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (3.0, map.pulse_at_tempo_locked (map._metrics, tempoB), 1e-17);
} }
@ -185,23 +185,23 @@ TempoTest::recomputeMapTest44 ()
/* tempo - frame */ /* tempo - frame */
CPPUNIT_ASSERT_EQUAL (framepos_t (264600), map.frame_at_tempo (tempoB)); CPPUNIT_ASSERT_EQUAL (framepos_t (264600), map.frame_at_tempo (tempoB));
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_frame (264600).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_frame (264600).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_frame (264600 - 1).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_frame (264600 - 1).note_types_per_minute(), 1e-17);
/* tempo - quarter note */ /* tempo - quarter note */
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (24.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (24.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (12.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_quarter_note (12.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (6.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (6.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (0.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, map.tempo_at_quarter_note (0.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (12.0, map.quarter_note_at_tempo (240.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (12.0, map.quarter_note_at_tempo (240.0), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, map.quarter_note_at_tempo (120.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, map.quarter_note_at_tempo (120.0), 1e-17);
/* tempo - internal minute interface */ /* tempo - internal minute interface */
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_minute_locked (map._metrics, 0.1).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_minute_locked (map._metrics, 0.1).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (0.1, map.minute_at_tempo_locked (map._metrics, tempoB), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (0.1, map.minute_at_tempo_locked (map._metrics, tempoB), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_pulse_locked (map._metrics, 3.0).beats_per_minute(), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, map.tempo_at_pulse_locked (map._metrics, 3.0).note_types_per_minute(), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (3.0, map.pulse_at_tempo_locked (map._metrics, tempoB), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (3.0, map.pulse_at_tempo_locked (map._metrics, tempoB), 1e-17);
} }
@ -395,7 +395,7 @@ TempoTest::rampTest48 ()
TempoSection& tA = map.first_tempo(); TempoSection& tA = map.first_tempo();
const TempoSection& tB = map.tempo_section_at_frame ((framepos_t) 60 * sampling_rate); const TempoSection& tB = map.tempo_section_at_frame ((framepos_t) 60 * sampling_rate);
CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0, tA.minute_at_tempo (tB.beats_per_minute(), 300.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0, tA.minute_at_tempo (tB.note_types_per_minute(), 300.0), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (217.0, tA.tempo_at_minute (1.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (217.0, tA.tempo_at_minute (1.0), 1e-17);
/* note 1e-14 here. pulse is two derivatives away from time */ /* note 1e-14 here. pulse is two derivatives away from time */
@ -457,7 +457,7 @@ TempoTest::rampTest44 ()
TempoSection& tA = map.first_tempo(); TempoSection& tA = map.first_tempo();
const TempoSection& tB = map.tempo_section_at_frame ((framepos_t) 60 * sampling_rate); const TempoSection& tB = map.tempo_section_at_frame ((framepos_t) 60 * sampling_rate);
CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0, tA.minute_at_tempo (tB.beats_per_minute(), 300.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0, tA.minute_at_tempo (tB.note_types_per_minute(), 300.0), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (217.0, tA.tempo_at_minute (1.0), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (217.0, tA.tempo_at_minute (1.0), 1e-17);
/* note 1e-14 here. pulse is two derivatives away from time */ /* note 1e-14 here. pulse is two derivatives away from time */
@ -554,3 +554,84 @@ TempoTest::tempoAtPulseTest ()
CPPUNIT_ASSERT_DOUBLES_EQUAL (160.0, tA->tempo_at_minute (tB->minute()), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (160.0, tA->tempo_at_minute (tB->minute()), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (123.0, tB->tempo_at_minute (tC->minute()), 1e-17); CPPUNIT_ASSERT_DOUBLES_EQUAL (123.0, tB->tempo_at_minute (tC->minute()), 1e-17);
} }
void
TempoTest::tempoFundamentalsTest ()
{
int const sampling_rate = 48000;
TempoMap map (sampling_rate);
Meter meterA (4, 8);
Tempo tempoA (120.0, 4.0);
Tempo tempoB (120.0, 8.0);
Tempo tempoC (120.0, 2.0);
Tempo tempoD (160.0, 2.0);
Tempo tempoE (123.0, 3.0);
map.replace_meter (map.first_meter(), meterA, BBT_Time (1, 1, 0), AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.add_tempo (tempoB, 20.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoC, 30.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoD, 40.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoE, 50.0, 0, TempoSection::Constant, MusicTime);
TempoSection* tA = 0;
TempoSection* tB = 0;
TempoSection* tC = 0;
TempoSection* tD = 0;
TempoSection* tE = 0;
list<MetricSection*>::iterator i;
for (i = map._metrics.begin(); i != map._metrics.end(); ++i) {
TempoSection* t;
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
if (!tA) {
tA = t;
continue;
}
if (!tB) {
tB = t;
continue;
}
if (!tC) {
tC = t;
continue;
}
if (!tD) {
tD = t;
continue;
}
if (!tE) {
tE = t;
continue;
}
}
}
CPPUNIT_ASSERT_DOUBLES_EQUAL (24000.0, tA->frames_per_quarter_note (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (24000.0, tA->frames_per_note_type (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (120.0, tA->quarter_notes_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (30.0, tA->pulses_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (48000.0, tB->frames_per_quarter_note (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (24000.0, tB->frames_per_note_type (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (60.0, tB->quarter_notes_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (15.0, tB->pulses_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (12000.0, tC->frames_per_quarter_note (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (24000.0, tC->frames_per_note_type (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (240.0, tC->quarter_notes_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (60.0, tC->pulses_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (9000.0, tD->frames_per_quarter_note (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (18000.0, tD->frames_per_note_type (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (320.0, tD->quarter_notes_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (80.0, tD->pulses_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (17560.975609756097, tE->frames_per_quarter_note (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (23414.634146341465, tE->frames_per_note_type (sampling_rate), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (164.0, tE->quarter_notes_per_minute (), 1e-17);
CPPUNIT_ASSERT_DOUBLES_EQUAL (41.0, tE->pulses_per_minute (), 1e-17);
}

View file

@ -12,6 +12,7 @@ class TempoTest : public CppUnit::TestFixture
CPPUNIT_TEST (rampTest48); CPPUNIT_TEST (rampTest48);
CPPUNIT_TEST (rampTest44); CPPUNIT_TEST (rampTest44);
CPPUNIT_TEST (tempoAtPulseTest); CPPUNIT_TEST (tempoAtPulseTest);
CPPUNIT_TEST (tempoFundamentalsTest);
CPPUNIT_TEST_SUITE_END (); CPPUNIT_TEST_SUITE_END ();
public: public:
@ -26,5 +27,6 @@ public:
void rampTest48 (); void rampTest48 ();
void rampTest44 (); void rampTest44 ();
void tempoAtPulseTest(); void tempoAtPulseTest();
void tempoFundamentalsTest();
}; };

View file

@ -308,11 +308,7 @@ MidiClockTicker::tick (const framepos_t& /* transport_frame */, pframes_t nframe
double double
MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position) MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position)
{ {
const Tempo& current_tempo = _session->tempo_map().tempo_at_frame (transport_position); const double frames_per_quarter_note = _session->tempo_map().frames_per_quarter_note_at (transport_position, _session->nominal_frame_rate());
double frames_per_beat = _session->tempo_map().frames_per_beat_at (transport_position, _session->nominal_frame_rate());
double quarter_notes_per_beat = 4.0 / current_tempo.note_type();
double frames_per_quarter_note = frames_per_beat / quarter_notes_per_beat;
return frames_per_quarter_note / double (_ppqn); return frames_per_quarter_note / double (_ppqn);
} }

View file

@ -132,7 +132,7 @@ JACKSession::timebase_callback (jack_transport_state_t /*state*/,
pos->beats_per_bar = metric.meter().divisions_per_bar(); pos->beats_per_bar = metric.meter().divisions_per_bar();
pos->beat_type = metric.meter().note_divisor(); pos->beat_type = metric.meter().note_divisor();
pos->ticks_per_beat = Timecode::BBT_Time::ticks_per_beat; pos->ticks_per_beat = Timecode::BBT_Time::ticks_per_beat;
pos->beats_per_minute = metric.tempo().beats_per_minute(); pos->beats_per_minute = metric.tempo().note_types_per_minute();
pos->valid = jack_position_bits_t (pos->valid | JackPositionBBT); pos->valid = jack_position_bits_t (pos->valid | JackPositionBBT);