Tempo ramps - improve music-locked meter drags, improve dump().

- dump now shows cross-calculation of tempo positions.
This commit is contained in:
nick_m
2016-03-21 23:47:57 +11:00
parent a58f862640
commit b47bb55226
3 changed files with 102 additions and 76 deletions

View File

@@ -3185,7 +3185,7 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
framepos_t const pf = adjusted_current_frame (event);
_marker->set_position (pf);
if (_marker->meter().position_lock_style() == MusicTime) {
double const baf = _editor->session()->tempo_map().beat_at_frame (pf);
double const baf = _editor->session()->tempo_map().beat_at_frame (_editor->session()->tempo_map().round_to_bar (pf, (RoundMode) 0));
_editor->session()->tempo_map().gui_move_meter (_real_section, _marker->meter(), baf);
} else {
_editor->session()->tempo_map().gui_move_meter (_real_section, _marker->meter(), pf);

View File

@@ -336,8 +336,9 @@ Editor::edit_meter_section (MeterSection* section)
meter_dialog.get_bbt_time(when);
framepos_t const frame = _session->tempo_map().frame_at_beat (_session->tempo_map().bbt_to_beats (when));
begin_reversible_command (_("replace tempo mark"));
begin_reversible_command (_("replace meter mark"));
XMLNode &before = _session->tempo_map().get_state();
section->set_position_lock_style (meter_dialog.get_lock_style());
if (meter_dialog.get_lock_style() == MusicTime) {
_session->tempo_map().replace_meter (*section, Meter (bpb, note_type), when);
} else {

View File

@@ -770,6 +770,7 @@ TempoMap::do_insert (MetricSection* section)
*/
*(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
(*i)->set_position_lock_style (insert_meter->position_lock_style());
need_add = false;
} else {
_metrics.erase (i);
@@ -917,12 +918,14 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
{
Glib::Threads::RWLock::WriterLock lm (lock);
MeterSection& first (first_meter());
const PositionLockStyle pl = ms.position_lock_style();
if (ms.pulse() != first.pulse()) {
remove_meter_locked (ms);
add_meter_locked (meter, bbt_to_beats_locked (_metrics, where), where, true);
} else {
/* cannot move the first meter section */
*static_cast<Meter*>(&first) = meter;
first.set_position_lock_style (pl);
recompute_map (_metrics);
}
}
@@ -936,12 +939,14 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const frame
{
Glib::Threads::RWLock::WriterLock lm (lock);
MeterSection& first (first_meter());
const PositionLockStyle pl = ms.position_lock_style();
if (ms.pulse() != first.pulse()) {
remove_meter_locked (ms);
add_meter_locked (meter, frame, true);
} else {
/* cannot move the first meter section */
*static_cast<Meter*>(&first) = meter;
first.set_position_lock_style (pl);
recompute_map (_metrics);
}
}
@@ -1000,7 +1005,6 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
where.beats = 1;
where.bars++;
}
/* new meters *always* start on a beat. */
where.ticks = 0;
double pulse = pulse_at_beat (_metrics, beat);
@@ -1285,7 +1289,7 @@ TempoMap::first_meter () const
}
}
fatal << _("programming error: no tempo section in tempo map!") << endmsg;
fatal << _("programming error: no meter section in tempo map!") << endmsg;
abort(); /*NOTREACHED*/
return *m;
}
@@ -1373,21 +1377,25 @@ TempoMap::recompute_meters (Metrics& metrics)
MeterSection* meter = 0;
MeterSection* prev_m = 0;
double accumulated_beats = 0.0;
uint32_t accumulated_bars = 0;
for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
if (prev_m) {
accumulated_beats += (meter->pulse() - prev_m->pulse()) * prev_m->note_divisor();
const double beats_in_m = (meter->pulse() - prev_m->pulse()) * prev_m->note_divisor();
accumulated_beats += beats_in_m;
accumulated_bars += (beats_in_m + 1) / prev_m->divisions_per_bar();
}
if (meter->position_lock_style() == AudioTime) {
pair<double, BBT_Time> pr;
pr.first = ceil (pulse_at_frame_locked (metrics, meter->frame()));
BBT_Time const where = beats_to_bbt_locked (metrics, accumulated_beats);
pr.first = pulse_at_frame_locked (metrics, meter->frame());
BBT_Time const where = BBT_Time (accumulated_bars + 1, 1, 0);
pr.second = where;
meter->set_pulse (pr);
} else {
meter->set_frame (frame_at_pulse_locked (metrics, meter->pulse()));
}
meter->set_beat (accumulated_beats);
prev_m = meter;
}
@@ -1706,51 +1714,6 @@ TempoMap::pulse_to_bbt (const double& pulse)
return ret;
}
double
TempoMap::beat_offset_at (const Metrics& metrics, const double& beat) const
{
MeterSection* prev_m = 0;
double beat_off = 0.0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (prev_m) {
if (m->beat() > beat) {
break;
}
if (m->position_lock_style() == AudioTime) {
beat_off += ((m->pulse() - prev_m->pulse()) / prev_m->note_divisor()) - floor ((m->pulse() - prev_m->pulse()) / prev_m->note_divisor());
}
}
prev_m = m;
}
}
return beat_off;
}
frameoffset_t
TempoMap::frame_offset_at (const Metrics& metrics, const framepos_t& frame) const
{
frameoffset_t frame_off = 0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (m->frame() > frame) {
break;
}
if (m->position_lock_style() == AudioTime) {
frame_off += frame_at_pulse_locked (metrics, m->pulse()) - m->frame();
}
}
}
return frame_off;
}
double
TempoMap::beat_at_frame (const framecnt_t& frame) const
{
@@ -1841,6 +1804,51 @@ TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) co
return ret;
}
double
TempoMap::beat_offset_at (const Metrics& metrics, const double& beat) const
{
MeterSection* prev_m = 0;
double beat_off = 0.0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (prev_m) {
if (m->beat() > beat) {
break;
}
if (m->position_lock_style() == AudioTime) {
beat_off += ((m->pulse() - prev_m->pulse()) / prev_m->note_divisor()) - floor ((m->pulse() - prev_m->pulse()) / prev_m->note_divisor());
}
}
prev_m = m;
}
}
return beat_off;
}
frameoffset_t
TempoMap::frame_offset_at (const Metrics& metrics, const framepos_t& frame) const
{
frameoffset_t frame_off = 0;
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* m = 0;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (m->frame() > frame) {
break;
}
if (m->position_lock_style() == AudioTime) {
frame_off += frame_at_pulse_locked (metrics, m->pulse()) - m->frame();
}
}
}
return frame_off;
}
framepos_t
TempoMap::frame_time (const BBT_Time& bbt)
{
@@ -1883,7 +1891,6 @@ TempoMap::check_solved (Metrics& metrics, bool by_frame)
if (by_frame && t->frame() != prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
return false;
}
/*
if (!by_frame && fabs (t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate)) > 0.00001) {
std::cerr << "beat precision too low for bpm: " << t->beats_per_minute() << std::endl <<
" |error :" << t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << std::endl <<
@@ -1891,7 +1898,6 @@ TempoMap::check_solved (Metrics& metrics, bool by_frame)
" |frame at tempo : " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
return false;
}
*/
}
prev_ts = t;
}
@@ -2067,28 +2073,37 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt,
{
MeterSection* prev_ms = 0;
pair<double, BBT_Time> b_bbt = make_pair (pulse, beats_to_bbt_locked (imaginary, pulse));
pair<double, BBT_Time> b_bbt = make_pair (pulse, BBT_Time (1, 1, 0));
double accumulated_beats = 0.0;
uint32_t accumulated_bars = 0;
section->set_pulse (b_bbt);
MetricSectionSorter cmp;
imaginary.sort (cmp);
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MeterSection* m;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (prev_ms) {
if (m == section){
section->set_frame (frame_at_pulse_locked (imaginary, pulse_at_beat (imaginary, pulse)));
prev_ms = section;
continue;
}
double const beats_in_m = (m->pulse() - prev_ms->pulse()) * prev_ms->note_divisor();
accumulated_beats += beats_in_m;
accumulated_bars += (beats_in_m + 1) / prev_ms->divisions_per_bar();
}
if (m == section){
section->set_frame (frame_at_pulse_locked (imaginary, pulse));
b_bbt = make_pair (pulse, BBT_Time (accumulated_bars + 1, 1, 0));
section->set_pulse (b_bbt);
m->set_beat (accumulated_beats);
prev_ms = section;
continue;
}
if (prev_ms) {
if (m->position_lock_style() == MusicTime) {
m->set_frame (frame_at_pulse_locked (imaginary, m->pulse()));
} else {
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_frame_locked (imaginary, m->frame()), BBT_Time (1, 1, 0));
b_bbt.second = beats_to_bbt_locked (imaginary, beat_at_pulse (imaginary, b_bbt.first));
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_frame_locked (imaginary, m->frame()), BBT_Time (accumulated_bars + 1, 1, 0));
m->set_pulse (b_bbt);
}
}
m->set_beat (accumulated_beats);
prev_ms = m;
}
}
@@ -2107,33 +2122,43 @@ void
TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt, const framepos_t& frame)
{
MeterSection* prev_ms = 0;
double accumulated_beats = 0.0;
uint32_t accumulated_bars = 0;
section->set_frame (frame);
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MeterSection* m;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (prev_ms) {
if (m == section){
const double beats_in_m = (m->pulse() - prev_ms->pulse()) * prev_ms->note_divisor();
accumulated_beats += beats_in_m;
accumulated_bars += (beats_in_m + 1) / prev_ms->divisions_per_bar();
}
if (m == section){
/*
here we define the pulse for this frame.
we're going to set it 'incorrectly' to the next integer and use this 'error'
as an offset to the map as far as users of the public methods are concerned.
(meters should go on absolute pulses to keep us sane)
*/
double const pulse_at_f = ceil (pulse_at_frame_locked (imaginary, m->frame()));
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_f, beats_to_bbt_locked (imaginary, beat_at_pulse (imaginary, pulse_at_f)));
double const pulse_at_f = pulse_at_frame_locked (imaginary, m->frame());
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_f, BBT_Time (accumulated_bars + 1, 1, 0));
m->set_pulse (b_bbt);
m->set_beat (accumulated_beats);
prev_ms = m;
continue;
}
}
if (prev_ms) {
if (m->position_lock_style() == MusicTime) {
m->set_frame (frame_at_pulse_locked (imaginary, m->pulse()));
} else {
double const pulse_at_f = ceil (pulse_at_frame_locked (imaginary, frame));
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_f, beats_to_bbt_locked (imaginary, beat_at_pulse (imaginary, pulse_at_f)));
pair<double, BBT_Time> b_bbt = make_pair (pulse_at_f, BBT_Time (accumulated_bars + 1, 1, 0));
m->set_pulse (b_bbt);
}
}
m->set_beat (accumulated_beats);
prev_ms = m;
}
}
@@ -2619,19 +2644,19 @@ TempoMap::dump (Metrics& metrics, std::ostream& o) const
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
<< t->movable() << ')' << endl;
<< t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
o << "current : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
if (prev_ts) {
o << "current : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
o << "previous : " << prev_ts->beats_per_minute() << " | " << prev_ts->pulse() << " | " << prev_ts->frame() << std::endl;
o << "calculated : " << prev_ts->tempo_at_pulse (t->pulse()) << " | " << prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << " | " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
o << "------" << std::endl;
o << "calculated : " << prev_ts->tempo_at_pulse (t->pulse()) * prev_ts->note_type() << " | " << prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << " | " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
}
prev_ts = t;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
<< " (movable? " << m->movable() << ')' << endl;
<< " pulse: " << m->pulse() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
}
prev_ts = t;
}
o << "------" << std::endl;
}
int