new approach to tempo/meter: compute and store the entire map (every bar|beat point), thus enabling us to use the same computation to set the BBT points AND the metric markers (tempo + meter) on the audio timeline. It is known that snapping to the BBT grid doesn't work correctly right now, but this probably caused by the separate code in TempoMap::round_to_type() and i'll dig into that tomorrow. Note that the Bar|beat point list is evaluated "lazily" - we'll never store more than anyone actually needs to display or know, other than 1 minute's worth starting from frame zero
git-svn-id: svn://localhost/ardour2/branches/3.0@11129 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
084fc8b327
commit
69c7dac1a1
|
@ -305,7 +305,6 @@ Editor::Editor ()
|
|||
pre_press_cursor = 0;
|
||||
_drags = new DragManager (this);
|
||||
current_mixer_strip = 0;
|
||||
current_bbt_points = 0;
|
||||
tempo_lines = 0;
|
||||
|
||||
snap_type_strings = I18N (_snap_type_strings);
|
||||
|
@ -5335,8 +5334,7 @@ Editor::session_going_away ()
|
|||
hide_measures ();
|
||||
clear_marker_display ();
|
||||
|
||||
delete current_bbt_points;
|
||||
current_bbt_points = 0;
|
||||
current_bbt_points.clear ();
|
||||
|
||||
/* get rid of any existing editor mixer strip */
|
||||
|
||||
|
|
|
@ -1451,7 +1451,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
/// true if we scroll the tracks rather than the playhead
|
||||
bool _stationary_playhead;
|
||||
|
||||
ARDOUR::TempoMap::BBTPointList *current_bbt_points;
|
||||
ARDOUR::TempoMap::BBTPointList current_bbt_points;
|
||||
|
||||
TempoLines* tempo_lines;
|
||||
|
||||
|
|
|
@ -1224,18 +1224,18 @@ Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper)
|
|||
break;
|
||||
}
|
||||
|
||||
if (current_bbt_points == 0 || current_bbt_points->empty()) {
|
||||
if (current_bbt_points.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = current_bbt_points->end();
|
||||
i = current_bbt_points.end();
|
||||
i--;
|
||||
if ((*i).beat >= (*current_bbt_points->begin()).beat) {
|
||||
bbt_bars = (*i).bar - (*current_bbt_points->begin()).bar;
|
||||
if ((*i).beat >= (*current_bbt_points.begin()).beat) {
|
||||
bbt_bars = (*i).bar - (*current_bbt_points.begin()).bar;
|
||||
} else {
|
||||
bbt_bars = (*i).bar - (*current_bbt_points->begin()).bar - 1;
|
||||
bbt_bars = (*i).bar - (*current_bbt_points.begin()).bar - 1;
|
||||
}
|
||||
beats = current_bbt_points->size() - bbt_bars;
|
||||
beats = current_bbt_points.size() - bbt_bars;
|
||||
|
||||
/* Only show the bar helper if there aren't many bars on the screen */
|
||||
if ((bbt_bars < 2) || (beats < 5)) {
|
||||
|
@ -1291,14 +1291,14 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
bool i_am_accented = false;
|
||||
bool helper_active = false;
|
||||
|
||||
if (current_bbt_points == 0 || current_bbt_points->empty()) {
|
||||
if (current_bbt_points.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (bbt_ruler_scale) {
|
||||
|
||||
case bbt_show_beats:
|
||||
beats = current_bbt_points->size();
|
||||
beats = current_bbt_points.size();
|
||||
bbt_nmarks = beats + 2;
|
||||
|
||||
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
|
||||
|
@ -1307,10 +1307,8 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
(*marks)[0].position = lower;
|
||||
(*marks)[0].style = GtkCustomRulerMarkMicro;
|
||||
|
||||
for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) {
|
||||
if ((*i).type != TempoMap::Beat) {
|
||||
continue;
|
||||
}
|
||||
for (n = 1, i = current_bbt_points.begin(); n < bbt_nmarks && i != current_bbt_points.end(); ++i) {
|
||||
|
||||
if ((*i).frame < lower && (bbt_bar_helper_on)) {
|
||||
snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
|
||||
(*marks)[0].label = g_strdup (buf);
|
||||
|
@ -1336,7 +1334,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
|
||||
case bbt_show_ticks:
|
||||
|
||||
beats = current_bbt_points->size();
|
||||
beats = current_bbt_points.size();
|
||||
bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
|
||||
|
||||
bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
|
||||
|
@ -1346,10 +1344,8 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
(*marks)[0].position = lower;
|
||||
(*marks)[0].style = GtkCustomRulerMarkMicro;
|
||||
|
||||
for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) {
|
||||
if ((*i).type != TempoMap::Beat) {
|
||||
continue;
|
||||
}
|
||||
for (n = 1, i = current_bbt_points.begin(); n < bbt_nmarks && i != current_bbt_points.end(); ++i) {
|
||||
|
||||
if ((*i).frame < lower && (bbt_bar_helper_on)) {
|
||||
snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
|
||||
(*marks)[0].label = g_strdup (buf);
|
||||
|
@ -1428,7 +1424,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
|
||||
case bbt_show_ticks_detail:
|
||||
|
||||
beats = current_bbt_points->size();
|
||||
beats = current_bbt_points.size();
|
||||
bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
|
||||
|
||||
bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
|
||||
|
@ -1438,10 +1434,8 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
(*marks)[0].position = lower;
|
||||
(*marks)[0].style = GtkCustomRulerMarkMicro;
|
||||
|
||||
for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) {
|
||||
if ((*i).type != TempoMap::Beat) {
|
||||
continue;
|
||||
}
|
||||
for (n = 1, i = current_bbt_points.begin(); n < bbt_nmarks && i != current_bbt_points.end(); ++i) {
|
||||
|
||||
if ((*i).frame < lower && (bbt_bar_helper_on)) {
|
||||
snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
|
||||
(*marks)[0].label = g_strdup (buf);
|
||||
|
@ -1525,7 +1519,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
|
||||
case bbt_show_ticks_super_detail:
|
||||
|
||||
beats = current_bbt_points->size();
|
||||
beats = current_bbt_points.size();
|
||||
bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
|
||||
|
||||
bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
|
||||
|
@ -1535,10 +1529,8 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
(*marks)[0].position = lower;
|
||||
(*marks)[0].style = GtkCustomRulerMarkMicro;
|
||||
|
||||
for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) {
|
||||
if ((*i).type != TempoMap::Beat) {
|
||||
continue;
|
||||
}
|
||||
for (n = 1, i = current_bbt_points.begin(); n < bbt_nmarks && i != current_bbt_points.end(); ++i) {
|
||||
|
||||
if ((*i).frame < lower && (bbt_bar_helper_on)) {
|
||||
snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
|
||||
(*marks)[0].label = g_strdup (buf);
|
||||
|
@ -1634,7 +1626,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
case bbt_show_64:
|
||||
bbt_nmarks = (gint) (bbt_bars / 64) + 1;
|
||||
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
|
||||
for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) {
|
||||
for (n = 0, i = current_bbt_points.begin(); i != current_bbt_points.end() && n < bbt_nmarks; i++) {
|
||||
if ((*i).type == TempoMap::Bar) {
|
||||
if ((*i).bar % 64 == 1) {
|
||||
if ((*i).bar % 256 == 1) {
|
||||
|
@ -1659,7 +1651,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
case bbt_show_16:
|
||||
bbt_nmarks = (bbt_bars / 16) + 1;
|
||||
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
|
||||
for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) {
|
||||
for (n = 0, i = current_bbt_points.begin(); i != current_bbt_points.end() && n < bbt_nmarks; i++) {
|
||||
if ((*i).type == TempoMap::Bar) {
|
||||
if ((*i).bar % 16 == 1) {
|
||||
if ((*i).bar % 64 == 1) {
|
||||
|
@ -1684,7 +1676,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
case bbt_show_4:
|
||||
bbt_nmarks = (bbt_bars / 4) + 1;
|
||||
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
|
||||
for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; ++i) {
|
||||
for (n = 0, i = current_bbt_points.begin(); i != current_bbt_points.end() && n < bbt_nmarks; ++i) {
|
||||
if ((*i).type == TempoMap::Bar) {
|
||||
if ((*i).bar % 4 == 1) {
|
||||
if ((*i).bar % 16 == 1) {
|
||||
|
@ -1710,7 +1702,7 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upp
|
|||
// default:
|
||||
bbt_nmarks = bbt_bars + 2;
|
||||
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks );
|
||||
for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) {
|
||||
for (n = 0, i = current_bbt_points.begin(); i != current_bbt_points.end() && n < bbt_nmarks; i++) {
|
||||
if ((*i).type == TempoMap::Bar) {
|
||||
if ((*i).bar % 4 == 1) {
|
||||
snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
|
||||
|
|
|
@ -114,7 +114,7 @@ Editor::tempo_map_changed (const PropertyChange& /*ignored*/)
|
|||
tempo_lines->tempo_map_changed();
|
||||
}
|
||||
|
||||
compute_current_bbt_points(leftmost_frame, leftmost_frame + current_page_frames());
|
||||
compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames());
|
||||
_session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
|
||||
redraw_measures ();
|
||||
update_tempo_based_rulers ();
|
||||
|
@ -169,10 +169,8 @@ Editor::compute_current_bbt_points (framepos_t leftmost, framepos_t rightmost)
|
|||
}
|
||||
next_beat.ticks = 0;
|
||||
|
||||
delete current_bbt_points;
|
||||
current_bbt_points = 0;
|
||||
|
||||
current_bbt_points = _session->tempo_map().get_points (_session->tempo_map().frame_time (previous_beat), _session->tempo_map().frame_time (next_beat) + 1);
|
||||
current_bbt_points.clear();
|
||||
_session->tempo_map().map (current_bbt_points, _session->tempo_map().frame_time (previous_beat), _session->tempo_map().frame_time (next_beat) + 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -192,8 +190,7 @@ Editor::redraw_measures ()
|
|||
void
|
||||
Editor::draw_measures ()
|
||||
{
|
||||
if (_session == 0 || _show_measures == false ||
|
||||
!current_bbt_points || current_bbt_points->empty()) {
|
||||
if (_session == 0 || _show_measures == false || current_bbt_points.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -201,7 +198,7 @@ Editor::draw_measures ()
|
|||
tempo_lines = new TempoLines(*track_canvas, time_line_group, physical_screen_height(get_window()));
|
||||
}
|
||||
|
||||
tempo_lines->draw(*current_bbt_points, frames_per_unit);
|
||||
tempo_lines->draw (current_bbt_points, frames_per_unit);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -131,122 +131,114 @@ TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit
|
|||
|
||||
for (i = points.begin(); i != points.end(); ++i) {
|
||||
|
||||
switch ((*i).type) {
|
||||
case ARDOUR::TempoMap::Bar:
|
||||
break;
|
||||
|
||||
case ARDOUR::TempoMap::Beat:
|
||||
if ((*i).beat == 1) {
|
||||
color = ARDOUR_UI::config()->canvasvar_MeasureLineBar.get();
|
||||
} else {
|
||||
color = ARDOUR_UI::config()->canvasvar_MeasureLineBeat.get();
|
||||
if (beat_density > 2.0) {
|
||||
break; /* only draw beat lines if the gaps between beats are large. */
|
||||
}
|
||||
if ((*i).type == ARDOUR::TempoMap::Bar) {
|
||||
color = ARDOUR_UI::config()->canvasvar_MeasureLineBar.get();
|
||||
} else {
|
||||
if (beat_density > 2.0) {
|
||||
continue; /* only draw beat lines if the gaps between beats are large. */
|
||||
}
|
||||
color = ARDOUR_UI::config()->canvasvar_MeasureLineBeat.get();
|
||||
}
|
||||
|
||||
xpos = rint(((framepos_t)(*i).frame) / (double)frames_per_unit);
|
||||
|
||||
if (inserted_last_time && !_lines.empty()) {
|
||||
li = _lines.lower_bound(xpos); // first line >= xpos
|
||||
}
|
||||
|
||||
line = (li != _lines.end()) ? li->second : NULL;
|
||||
assert(!line || line->property_x1() == li->first);
|
||||
|
||||
Lines::iterator next = li;
|
||||
if (next != _lines.end())
|
||||
++next;
|
||||
|
||||
exhausted = (next == _lines.end());
|
||||
|
||||
// Hooray, line is perfect
|
||||
if (line && line->property_x1() == xpos) {
|
||||
if (li != _lines.end())
|
||||
++li;
|
||||
|
||||
line->property_color_rgba() = color;
|
||||
inserted_last_time = false; // don't search next time
|
||||
|
||||
xpos = rint(((framepos_t)(*i).frame) / (double)frames_per_unit);
|
||||
|
||||
if (inserted_last_time && !_lines.empty()) {
|
||||
li = _lines.lower_bound(xpos); // first line >= xpos
|
||||
}
|
||||
|
||||
line = (li != _lines.end()) ? li->second : NULL;
|
||||
assert(!line || line->property_x1() == li->first);
|
||||
|
||||
Lines::iterator next = li;
|
||||
if (next != _lines.end())
|
||||
++next;
|
||||
|
||||
exhausted = (next == _lines.end());
|
||||
|
||||
// Hooray, line is perfect
|
||||
if (line && line->property_x1() == xpos) {
|
||||
if (li != _lines.end())
|
||||
++li;
|
||||
|
||||
line->property_color_rgba() = color;
|
||||
inserted_last_time = false; // don't search next time
|
||||
|
||||
// Use existing line, moving if necessary
|
||||
} else if (!exhausted) {
|
||||
Lines::iterator steal = _lines.end();
|
||||
--steal;
|
||||
|
||||
// Steal from the right
|
||||
if (left->first > needed_left && li != steal && steal->first > needed_right) {
|
||||
//cout << "*** STEALING FROM RIGHT" << endl;
|
||||
line = steal->second;
|
||||
_lines.erase(steal);
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
line->property_color_rgba() = color;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true; // search next time
|
||||
invalidated = true;
|
||||
|
||||
// Shift clean range left
|
||||
_clean_left = min(_clean_left, xpos);
|
||||
_clean_right = min(_clean_right, steal->first);
|
||||
|
||||
// Move this line to where we need it
|
||||
} else {
|
||||
Lines::iterator existing = _lines.find(xpos);
|
||||
if (existing != _lines.end()) {
|
||||
//cout << "*** EXISTING LINE" << endl;
|
||||
li = existing;
|
||||
li->second->property_color_rgba() = color;
|
||||
inserted_last_time = false; // don't search next time
|
||||
} else {
|
||||
//cout << "*** MOVING LINE" << endl;
|
||||
const double x1 = line->property_x1();
|
||||
const bool was_clean = x1 >= _clean_left && x1 <= _clean_right;
|
||||
invalidated = invalidated || was_clean;
|
||||
// Invalidate clean portion (XXX: too harsh?)
|
||||
_clean_left = needed_left;
|
||||
_clean_right = needed_right;
|
||||
_lines.erase(li);
|
||||
line->property_color_rgba() = color;
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true; // search next time
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new line
|
||||
} else if (_lines.size() < needed || _lines.size() < MAX_CACHED_LINES) {
|
||||
//cout << "*** CREATING LINE" << endl;
|
||||
assert(_lines.find(xpos) == _lines.end());
|
||||
line = new ArdourCanvas::SimpleLine (*_group);
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
line->property_y1() = 0.0;
|
||||
line->property_y2() = _height;
|
||||
line->property_color_rgba() = color;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true;
|
||||
|
||||
// Steal from the left
|
||||
} else {
|
||||
//cout << "*** STEALING FROM LEFT" << endl;
|
||||
assert(_lines.find(xpos) == _lines.end());
|
||||
Lines::iterator steal = _lines.begin();
|
||||
} else if (!exhausted) {
|
||||
Lines::iterator steal = _lines.end();
|
||||
--steal;
|
||||
|
||||
// Steal from the right
|
||||
if (left->first > needed_left && li != steal && steal->first > needed_right) {
|
||||
//cout << "*** STEALING FROM RIGHT" << endl;
|
||||
line = steal->second;
|
||||
_lines.erase(steal);
|
||||
line->property_color_rgba() = color;
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
line->property_color_rgba() = color;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true; // search next time
|
||||
invalidated = true;
|
||||
|
||||
// Shift clean range right
|
||||
_clean_left = max(_clean_left, steal->first);
|
||||
_clean_right = max(_clean_right, xpos);
|
||||
|
||||
// Shift clean range left
|
||||
_clean_left = min(_clean_left, xpos);
|
||||
_clean_right = min(_clean_right, steal->first);
|
||||
|
||||
// Move this line to where we need it
|
||||
} else {
|
||||
Lines::iterator existing = _lines.find(xpos);
|
||||
if (existing != _lines.end()) {
|
||||
//cout << "*** EXISTING LINE" << endl;
|
||||
li = existing;
|
||||
li->second->property_color_rgba() = color;
|
||||
inserted_last_time = false; // don't search next time
|
||||
} else {
|
||||
//cout << "*** MOVING LINE" << endl;
|
||||
const double x1 = line->property_x1();
|
||||
const bool was_clean = x1 >= _clean_left && x1 <= _clean_right;
|
||||
invalidated = invalidated || was_clean;
|
||||
// Invalidate clean portion (XXX: too harsh?)
|
||||
_clean_left = needed_left;
|
||||
_clean_right = needed_right;
|
||||
_lines.erase(li);
|
||||
line->property_color_rgba() = color;
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true; // search next time
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Create a new line
|
||||
} else if (_lines.size() < needed || _lines.size() < MAX_CACHED_LINES) {
|
||||
//cout << "*** CREATING LINE" << endl;
|
||||
assert(_lines.find(xpos) == _lines.end());
|
||||
line = new ArdourCanvas::SimpleLine (*_group);
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
line->property_y1() = 0.0;
|
||||
line->property_y2() = _height;
|
||||
line->property_color_rgba() = color;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true;
|
||||
|
||||
// Steal from the left
|
||||
} else {
|
||||
//cout << "*** STEALING FROM LEFT" << endl;
|
||||
assert(_lines.find(xpos) == _lines.end());
|
||||
Lines::iterator steal = _lines.begin();
|
||||
line = steal->second;
|
||||
_lines.erase(steal);
|
||||
line->property_color_rgba() = color;
|
||||
line->property_x1() = xpos;
|
||||
line->property_x2() = xpos;
|
||||
_lines.insert(make_pair(xpos, line));
|
||||
inserted_last_time = true; // search next time
|
||||
invalidated = true;
|
||||
|
||||
// Shift clean range right
|
||||
_clean_left = max(_clean_left, steal->first);
|
||||
_clean_right = max(_clean_right, xpos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -218,8 +218,9 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
(obj.*method)(*metrics);
|
||||
}
|
||||
|
||||
BBTPointList *get_points (framepos_t start, framepos_t end) const;
|
||||
|
||||
const BBTPointList& map() const { return _map ; }
|
||||
void map (BBTPointList&, framepos_t start, framepos_t end);
|
||||
|
||||
void bbt_time (framepos_t when, Timecode::BBT_Time&) const;
|
||||
framecnt_t frame_time (const Timecode::BBT_Time&) const;
|
||||
framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir) const;
|
||||
|
@ -282,13 +283,15 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
static Meter _default_meter;
|
||||
|
||||
Metrics* metrics;
|
||||
framecnt_t _frame_rate;
|
||||
framecnt_t _frame_rate;
|
||||
framepos_t last_bbt_when;
|
||||
bool last_bbt_valid;
|
||||
Timecode::BBT_Time last_bbt;
|
||||
mutable Glib::RWLock lock;
|
||||
BBTPointList _map;
|
||||
|
||||
void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
|
||||
|
||||
void timestamp_metrics (bool reassign_bar_references);
|
||||
void timestamp_metrics_from_audio_time ();
|
||||
|
||||
framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
|
||||
|
@ -304,7 +307,6 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
|
||||
framecnt_t count_frames_between (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
|
||||
framecnt_t count_frames_with_metrics (const TempoMetric&, const TempoMetric&, const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
|
||||
framecnt_t count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const Timecode::BBT_Time& start, const Timecode::BBT_Time& end) const;
|
||||
|
||||
int move_metric_section (MetricSection&, const Timecode::BBT_Time& to);
|
||||
void do_insert (MetricSection* section);
|
||||
|
|
|
@ -41,7 +41,7 @@ Pool Click::pool ("click", sizeof (Click), 128);
|
|||
void
|
||||
Session::click (framepos_t start, framecnt_t nframes)
|
||||
{
|
||||
TempoMap::BBTPointList *points;
|
||||
TempoMap::BBTPointList points;
|
||||
Sample *buf;
|
||||
|
||||
if (_click_io == 0) {
|
||||
|
@ -59,18 +59,13 @@ Session::click (framepos_t start, framecnt_t nframes)
|
|||
|
||||
BufferSet& bufs = get_scratch_buffers(ChanCount(DataType::AUDIO, 1));
|
||||
buf = bufs.get_audio(0).data();
|
||||
points = _tempo_map->get_points (start, end);
|
||||
_tempo_map->map (points, start, end);
|
||||
|
||||
if (points == 0) {
|
||||
if (points.empty()) {
|
||||
goto run_clicks;
|
||||
}
|
||||
|
||||
if (points->empty()) {
|
||||
delete points;
|
||||
goto run_clicks;
|
||||
}
|
||||
|
||||
for (TempoMap::BBTPointList::iterator i = points->begin(); i != points->end(); ++i) {
|
||||
for (TempoMap::BBTPointList::iterator i = points.begin(); i != points.end(); ++i) {
|
||||
switch ((*i).type) {
|
||||
case TempoMap::Beat:
|
||||
if (click_emphasis_data == 0 || (click_emphasis_data && (*i).beat != 1)) {
|
||||
|
|
|
@ -156,8 +156,8 @@ void
|
|||
|
||||
TempoSection::update_bar_offset_from_bbt (const Meter& m)
|
||||
{
|
||||
_bar_offset = ((double) (start().beats - 1) + (start().ticks/Timecode::BBT_Time::ticks_per_bar_division)) /
|
||||
(m.divisions_per_bar() - 1);
|
||||
_bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_bar_division + start().ticks) /
|
||||
(m.divisions_per_bar() * BBT_Time::ticks_per_bar_division);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
|
||||
}
|
||||
|
@ -174,18 +174,16 @@ TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
|
|||
|
||||
new_start.bars = start().bars;
|
||||
|
||||
double ticks = BBT_Time::ticks_per_bar_division * (_bar_offset * (meter.divisions_per_bar() - 1));
|
||||
double ticks = BBT_Time::ticks_per_bar_division * meter.divisions_per_bar() * _bar_offset;
|
||||
new_start.beats = (uint32_t) floor(ticks/BBT_Time::ticks_per_bar_division);
|
||||
new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_bar_division);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
|
||||
_bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
|
||||
|
||||
/* remember the 1-based counting properties of beats */
|
||||
new_start.beats += 1;
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("tempo updated BBT time to %1 from bar offset %2 w/dpb = %3\n", new_start, _bar_offset, meter.divisions_per_bar()));
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
|
||||
_bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
|
||||
|
||||
set_start (new_start);
|
||||
}
|
||||
|
||||
|
@ -305,7 +303,7 @@ TempoMap::~TempoMap ()
|
|||
}
|
||||
|
||||
void
|
||||
TempoMap::remove_tempo (const TempoSection& tempo, bool send_signal)
|
||||
TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
|
||||
{
|
||||
bool removed = false;
|
||||
|
||||
|
@ -327,15 +325,15 @@ TempoMap::remove_tempo (const TempoSection& tempo, bool send_signal)
|
|||
}
|
||||
|
||||
if (removed) {
|
||||
timestamp_metrics (false);
|
||||
if (send_signal) {
|
||||
if (complete_operation) {
|
||||
recompute_map (false);
|
||||
PropertyChanged (PropertyChange ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TempoMap::remove_meter (const MeterSection& tempo, bool send_signal)
|
||||
TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
|
||||
{
|
||||
bool removed = false;
|
||||
|
||||
|
@ -357,8 +355,8 @@ TempoMap::remove_meter (const MeterSection& tempo, bool send_signal)
|
|||
}
|
||||
|
||||
if (removed) {
|
||||
timestamp_metrics (true);
|
||||
if (send_signal) {
|
||||
if (complete_operation) {
|
||||
recompute_map (true);
|
||||
PropertyChanged (PropertyChange ());
|
||||
}
|
||||
}
|
||||
|
@ -448,7 +446,7 @@ TempoMap::do_insert (MetricSection* section)
|
|||
metrics->insert (metrics->end(), section);
|
||||
}
|
||||
|
||||
timestamp_metrics (reassign_tempo_bbt);
|
||||
recompute_map (reassign_tempo_bbt);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -462,7 +460,7 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T
|
|||
} else {
|
||||
/* cannot move the first tempo section */
|
||||
*((Tempo*)&first) = tempo;
|
||||
timestamp_metrics (false);
|
||||
recompute_map (false);
|
||||
}
|
||||
|
||||
PropertyChanged (PropertyChange ());
|
||||
|
@ -526,7 +524,7 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
|
|||
} else {
|
||||
/* cannot move the first meter section */
|
||||
*((Meter*)&first) = meter;
|
||||
timestamp_metrics (true);
|
||||
recompute_map (true);
|
||||
}
|
||||
|
||||
PropertyChanged (PropertyChange ());
|
||||
|
@ -737,41 +735,80 @@ TempoMap::timestamp_metrics_from_audio_time ()
|
|||
}
|
||||
|
||||
void
|
||||
TempoMap::timestamp_metrics (bool reassign_tempo_bbt)
|
||||
TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
|
||||
{
|
||||
Metrics::iterator i;
|
||||
const MeterSection* meter;
|
||||
const TempoSection* tempo;
|
||||
MeterSection *m;
|
||||
TempoSection *t;
|
||||
MeterSection* meter;
|
||||
TempoSection* tempo;
|
||||
TempoSection* ts;
|
||||
MeterSection* ms;
|
||||
double divisions_per_bar;
|
||||
double beat_frames;
|
||||
double frames_per_bar;
|
||||
double current_frame;
|
||||
BBT_Time current;
|
||||
Metrics::iterator next_metric;
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, "###################### TIMESTAMP via BBT ##############\n");
|
||||
if (end < 0) {
|
||||
if (_map.empty()) {
|
||||
/* compute 1 mins worth */
|
||||
end = _frame_rate * 60;
|
||||
} else {
|
||||
end = _map.back().frame;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
|
||||
|
||||
framepos_t current = 0;
|
||||
framepos_t section_frames;
|
||||
BBT_Time start;
|
||||
BBT_Time end;
|
||||
_map.clear ();
|
||||
|
||||
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
|
||||
meter = ms;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
|
||||
tempo = ts;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* assumes that the first meter & tempo are at frame zero */
|
||||
current_frame = 0;
|
||||
meter->set_frame (0);
|
||||
tempo->set_frame (0);
|
||||
|
||||
/* assumes that the first meter & tempo are at 1|1|0 */
|
||||
current.bars = 1;
|
||||
current.beats = 1;
|
||||
current.ticks = 0;
|
||||
|
||||
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);
|
||||
|
||||
if (reassign_tempo_bbt) {
|
||||
|
||||
TempoSection* rtempo = tempo;
|
||||
MeterSection* rmeter = meter;
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
|
||||
|
||||
meter = &first_meter ();
|
||||
tempo = &first_tempo ();
|
||||
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
|
||||
/* reassign the BBT time of this tempo section
|
||||
* based on its bar offset position.
|
||||
*/
|
||||
|
||||
t->update_bbt_time_from_bar_offset (*meter);
|
||||
tempo = t;
|
||||
ts->update_bbt_time_from_bar_offset (*rmeter);
|
||||
rtempo = ts;
|
||||
|
||||
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
meter = m;
|
||||
} else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
rmeter = ms;
|
||||
} else {
|
||||
fatal << _("programming error: unhandled MetricSection type") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
|
@ -779,44 +816,110 @@ TempoMap::timestamp_metrics (bool reassign_tempo_bbt)
|
|||
}
|
||||
}
|
||||
|
||||
meter = &first_meter ();
|
||||
tempo = &first_tempo ();
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2 dpb %3 fpb %4\n",
|
||||
*((Meter*)meter), *((Tempo*)tempo), divisions_per_bar, beat_frames));
|
||||
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
next_metric = metrics->begin();
|
||||
++next_metric; // skip meter (or tempo)
|
||||
++next_metric; // skip tempo (or meter)
|
||||
|
||||
end = (*i)->start();
|
||||
|
||||
section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
|
||||
current += section_frames;
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
|
||||
_map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), Bar, 1, 1));
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frames between %1 & %2 = %3 using %4 & %6 puts %7 at %8\n",
|
||||
start, end, section_frames,
|
||||
*((Meter*) meter), *((Tempo*) tempo),
|
||||
(*i)->start(), current));
|
||||
while (current_frame < end) {
|
||||
|
||||
current.beats++;
|
||||
current_frame += beat_frames;
|
||||
|
||||
start = end;
|
||||
|
||||
(*i)->set_frame (current);
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
meter = m;
|
||||
} else {
|
||||
fatal << _("programming error: unhandled MetricSection type") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
if (current.beats > meter->divisions_per_bar()) {
|
||||
current.bars++;
|
||||
current.beats = 1;
|
||||
}
|
||||
|
||||
if (next_metric != metrics->end()) {
|
||||
|
||||
/* no operator >= so invert operator < */
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1 next metric @ %2\n", current, (*next_metric)->start()));
|
||||
|
||||
if (!(current < (*next_metric)->start())) {
|
||||
|
||||
|
||||
if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
|
||||
|
||||
tempo = ts;
|
||||
|
||||
/* new tempo section: if its on a beat,
|
||||
* we don't have to do anything other
|
||||
* than recompute various distances,
|
||||
* done further below as we transition
|
||||
* the next metric section.
|
||||
*
|
||||
* if its not on the beat, we have to
|
||||
* compute the duration of the beat it
|
||||
* is within, which will be different
|
||||
* from the preceding following ones
|
||||
* since it takes part of its duration
|
||||
* from the preceding tempo and part
|
||||
* from this new tempo.
|
||||
*/
|
||||
|
||||
if (tempo->start().ticks != 0) {
|
||||
|
||||
double next_beat_frames = meter->frames_per_division (*tempo,_frame_rate);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
|
||||
tempo->start(), current_frame, tempo->bar_offset()));
|
||||
|
||||
/* back up to previous beat */
|
||||
current_frame -= beat_frames;
|
||||
/* set tempo section location based on offset from last beat */
|
||||
tempo->set_frame (current_frame + (ts->bar_offset() * beat_frames));
|
||||
/* advance to the location of the new (adjusted) beat */
|
||||
current_frame += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Adjusted last beat to %1\n", current_frame));
|
||||
} else {
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into beat-aligned tempo metric at %1 = %2\n",
|
||||
tempo->start(), current_frame));
|
||||
tempo->set_frame (current_frame);
|
||||
}
|
||||
|
||||
} else if ((ms = dynamic_cast<MeterSection*>(*next_metric)) != 0) {
|
||||
|
||||
meter = ms;
|
||||
|
||||
/* new meter section: always defines the
|
||||
* start of a bar.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into meter section at %1 (%2)\n",
|
||||
meter->start(), current_frame));
|
||||
|
||||
assert (current.beats == 1);
|
||||
|
||||
meter->set_frame (current_frame);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 dpb %2 meter %3 tempo %4\n",
|
||||
beat_frames, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
|
||||
|
||||
++next_metric;
|
||||
}
|
||||
}
|
||||
|
||||
if (current.beats == 1) {
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
|
||||
_map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), Bar, current.bars, 1));
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
|
||||
_map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), Beat, current.bars, current.beats));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (DEBUG_ENABLED(DEBUG::TempoMath)) {
|
||||
dump (cerr);
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, "###############################################\n");
|
||||
|
||||
}
|
||||
|
||||
TempoMetric
|
||||
|
@ -1007,81 +1110,6 @@ TempoMap::count_frames_with_metrics (const TempoMetric& bm, const TempoMetric& e
|
|||
return frames;
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
|
||||
{
|
||||
/* this is used in timestamping the metrics by actually counting the
|
||||
* beats between two metrics ONLY. this means that we know we have a
|
||||
* fixed divisions_per_bar and frames_per_division for the entire
|
||||
* computation.
|
||||
*/
|
||||
|
||||
framecnt_t frames = 0;
|
||||
uint32_t bar = start.bars;
|
||||
double beat = (double) start.beats;
|
||||
double divisions_counted = 0;
|
||||
double divisions_per_bar = 0;
|
||||
double division_frames = 0;
|
||||
double max_divs;
|
||||
int32_t ticks = 0;
|
||||
|
||||
divisions_per_bar = meter.divisions_per_bar();
|
||||
max_divs = ceil (divisions_per_bar);
|
||||
division_frames = meter.frames_per_division (tempo, _frame_rate);
|
||||
|
||||
if (start.ticks > 0) {
|
||||
ticks = -start.ticks;
|
||||
|
||||
}
|
||||
|
||||
frames = 0;
|
||||
|
||||
while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
|
||||
|
||||
++beat;
|
||||
++divisions_counted;
|
||||
|
||||
if (beat > max_divs) {
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
divisions_counted -= (max_divs - divisions_per_bar);
|
||||
}
|
||||
|
||||
++bar;
|
||||
beat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ticks += end.ticks;
|
||||
|
||||
#if 0
|
||||
cerr << "for " << start.ticks << " and " << end.ticks << " adjust divs by " << ticks << " = "
|
||||
<< (ticks/BBT_Time::ticks_per_bar_division) << " divs => "
|
||||
<< ((ticks/BBT_Time::ticks_per_bar_division) * division_frames)
|
||||
<< " (fpd = " << division_frames << ')'
|
||||
<< endl;
|
||||
#endif
|
||||
|
||||
frames = (framecnt_t) llrint (floor ((divisions_counted + (ticks/BBT_Time::ticks_per_bar_division)) * division_frames));
|
||||
|
||||
#if 0
|
||||
cerr << "Counted " << divisions_counted << " + " << ticks << " from " << start << " to " << end
|
||||
<< " dpb were " << divisions_per_bar
|
||||
<< " fpd was " << division_frames
|
||||
<< " => "
|
||||
<< frames
|
||||
<< endl;
|
||||
#endif
|
||||
|
||||
return frames;
|
||||
|
||||
}
|
||||
|
||||
framepos_t
|
||||
TempoMap::frame_time (const BBT_Time& bbt) const
|
||||
{
|
||||
|
@ -1440,296 +1468,22 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
|
|||
return metric.frame() + count_frames_between (metric.start(), bbt);
|
||||
}
|
||||
|
||||
TempoMap::BBTPointList *
|
||||
TempoMap::get_points (framepos_t lower, framepos_t upper) const
|
||||
void
|
||||
TempoMap::map (TempoMap::BBTPointList& points, framepos_t lower, framepos_t upper)
|
||||
{
|
||||
Metrics::const_iterator next_metric;
|
||||
BBTPointList *points;
|
||||
double current;
|
||||
const MeterSection* meter;
|
||||
const MeterSection* m;
|
||||
const TempoSection* tempo;
|
||||
const TempoSection* t;
|
||||
uint32_t bar;
|
||||
uint32_t beat;
|
||||
double divisions_per_bar;
|
||||
double beat_frame;
|
||||
double beat_frames;
|
||||
double frames_per_bar;
|
||||
double delta_bars;
|
||||
double delta_beats;
|
||||
double dummy;
|
||||
framepos_t limit;
|
||||
|
||||
meter = &first_meter ();
|
||||
tempo = &first_tempo ();
|
||||
|
||||
/* find the starting point */
|
||||
|
||||
for (next_metric = metrics->begin(); next_metric != metrics->end(); ++next_metric) {
|
||||
|
||||
if ((*next_metric)->frame() > lower) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
|
||||
meter = m;
|
||||
}
|
||||
if (_map.empty() || upper >= _map.back().frame) {
|
||||
recompute_map (false, upper);
|
||||
}
|
||||
|
||||
/* We now have:
|
||||
|
||||
meter -> the Meter for "lower"
|
||||
tempo -> the Tempo for "lower"
|
||||
i -> for first new metric after "lower", possibly metrics->end()
|
||||
|
||||
Now start generating points.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Start with beat frames = %1 bar = %2\n", beat_frames, frames_per_bar));
|
||||
|
||||
if (meter->frame() > tempo->frame()) {
|
||||
bar = meter->start().bars;
|
||||
beat = meter->start().beats;
|
||||
current = meter->frame();
|
||||
} else {
|
||||
bar = tempo->start().bars;
|
||||
beat = tempo->start().beats;
|
||||
current = tempo->frame();
|
||||
}
|
||||
|
||||
/* initialize current to point to the bar/beat just prior to the
|
||||
lower frame bound passed in. assumes that current is initialized
|
||||
above to be on a beat.
|
||||
*/
|
||||
|
||||
delta_bars = (lower-current) / frames_per_bar;
|
||||
delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
|
||||
current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
|
||||
|
||||
// adjust bars and beats too
|
||||
bar += (uint32_t) (floor(delta_bars));
|
||||
beat += (uint32_t) (floor(delta_beats));
|
||||
|
||||
points = new BBTPointList;
|
||||
|
||||
do {
|
||||
|
||||
/* we're going to add bar or beat points until we hit the
|
||||
earlier of:
|
||||
|
||||
(1) the end point of this request
|
||||
(2) the next metric section
|
||||
*/
|
||||
|
||||
if (next_metric == metrics->end()) {
|
||||
limit = upper;
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to end of request @ %1\n", limit));
|
||||
} else {
|
||||
limit = (*next_metric)->frame();
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to next metric section @ %1\n", limit));
|
||||
for (BBTPointList::const_iterator i = _map.begin(); i != _map.end(); ++i) {
|
||||
if ((*i).frame < lower) {
|
||||
continue;
|
||||
}
|
||||
|
||||
limit = min (limit, upper);
|
||||
|
||||
bool reset_current_to_metric_section = true;
|
||||
bool bar_adjusted = false;
|
||||
TempoSection* ts;
|
||||
|
||||
while (current < limit) {
|
||||
|
||||
/* if we're at the start of a bar, add bar point */
|
||||
|
||||
if (beat == 1) {
|
||||
if (current >= lower) {
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", bar, current));
|
||||
points->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current), Bar, bar, 1));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* add some beats if we can */
|
||||
|
||||
beat_frame = current;
|
||||
|
||||
const uint32_t max_divs = ceil (divisions_per_bar);
|
||||
|
||||
while (beat <= max_divs && beat_frame < limit) {
|
||||
|
||||
if (beat_frame >= lower) {
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", bar, beat, beat_frame));
|
||||
points->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(beat_frame), Beat, bar, beat));
|
||||
}
|
||||
|
||||
beat_frame += beat_frames;
|
||||
current = beat_frame;
|
||||
beat++;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("break in beats addition @ end ? %1 out of bpb ? %2 beat frame @ %3 vs %4 beat @ %5 vs %6\n",
|
||||
(next_metric == metrics->end()), (beat > max_divs), beat_frame, limit, beat, max_divs));
|
||||
|
||||
if (beat <= max_divs) {
|
||||
|
||||
/* we didn't reach the end of the bar.
|
||||
|
||||
this could be be because we hit "upper"
|
||||
or a new metric section.
|
||||
|
||||
*/
|
||||
|
||||
if (next_metric != metrics->end() && limit == (*next_metric)->frame()) {
|
||||
|
||||
/* we bumped into a new metric
|
||||
* section. meter sections are always
|
||||
* at bar boundaries, but tempo
|
||||
* sections can begin anywhere and need
|
||||
* special handling if they are not on
|
||||
* a beat boundary.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stopped at metric at %1 @ 2\n", (*next_metric)->start(), (*next_metric)->frame()));
|
||||
|
||||
if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0) && ts->start().ticks != 0) {
|
||||
|
||||
/* compute current at the *next* beat,
|
||||
using the tempo section we just
|
||||
bumped into.
|
||||
*/
|
||||
|
||||
/* recompute how many frames per
|
||||
* division using the tempo we've just
|
||||
* found
|
||||
*/
|
||||
|
||||
double next_beat_frames = meter->frames_per_division (*ts,_frame_rate);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
|
||||
(*next_metric)->start(), (*next_metric)->frame(), ts->bar_offset()));
|
||||
|
||||
current -= beat_frames;
|
||||
current += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
|
||||
|
||||
/* avoid resetting current to position
|
||||
of the next metric section as we
|
||||
iterate through "metrics"
|
||||
further on below.
|
||||
*/
|
||||
|
||||
reset_current_to_metric_section = false;
|
||||
|
||||
} else if (dynamic_cast<MeterSection*> (*next_metric)) {
|
||||
|
||||
/* we hit a new meter
|
||||
* section. nothing to do - the
|
||||
* right thing will happen as
|
||||
* we move to the next metric
|
||||
* section down below.
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
/* we hit a tempo mark that is
|
||||
* precisely on beat. nothing
|
||||
* to do here - the
|
||||
* right thing will happen as
|
||||
* we move to the next metric
|
||||
* section down below.
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* we hit either:
|
||||
|
||||
- the end of the requested range
|
||||
|
||||
we'll exit from the outer loop soon.
|
||||
*/
|
||||
}
|
||||
|
||||
} else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
|
||||
|
||||
/* we've arrived at either the end of a bar or
|
||||
a new **meter** marker (not tempo marker).
|
||||
|
||||
its important to move `current' forward by
|
||||
the actual frames_per_bar, not move it to an
|
||||
integral beat_frame, so that metrics with
|
||||
non-integral beats-per-bar have their bar
|
||||
positions set correctly. consider a metric
|
||||
with 9-1/2 beats-per-bar. the bar we just
|
||||
filled had 10 beat marks, but the bar end is
|
||||
1/2 beat before the last beat mark. And it
|
||||
is also possible that a tempo change occured
|
||||
in the middle of a bar, so we subtract the
|
||||
possible extra fraction from the current
|
||||
*/
|
||||
|
||||
if (beat > max_divs) {
|
||||
/* next bar goes where the numbers suggest */
|
||||
current -= beat_frames * (max_divs - divisions_per_bar);
|
||||
DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
|
||||
} else {
|
||||
/* next bar goes where the next meter metric is */
|
||||
current = limit;
|
||||
DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
|
||||
}
|
||||
|
||||
bar++;
|
||||
beat = 1;
|
||||
bar_adjusted = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we're done, then we're done */
|
||||
|
||||
if (current >= upper) {
|
||||
if ((*i).frame >= upper) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* i is an iterator that refers to the next metric (or none).
|
||||
if there is a next metric, move to it, and continue.
|
||||
*/
|
||||
|
||||
if (next_metric != metrics->end()) {
|
||||
|
||||
if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
|
||||
meter = m;
|
||||
|
||||
if (!bar_adjusted) {
|
||||
/* new MeterSection, beat always returns to 1 */
|
||||
beat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset_current_to_metric_section) {
|
||||
current = (*next_metric)->frame ();
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
|
||||
|
||||
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);
|
||||
|
||||
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n",
|
||||
beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
|
||||
|
||||
++next_metric;
|
||||
}
|
||||
|
||||
} while (1);
|
||||
|
||||
return points;
|
||||
points.push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
const TempoSection&
|
||||
|
@ -1847,7 +1601,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
|
|||
|
||||
MetricSectionSorter cmp;
|
||||
metrics->sort (cmp);
|
||||
timestamp_metrics (true);
|
||||
recompute_map (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue