Rework duration clock and TempoMap::insert_time to include meter at offset.

- should fix 7072

	- also fixes scroll behavior over multiple tempi.
This commit is contained in:
nick_m 2016-10-16 02:33:49 +11:00
parent 9698f16aee
commit 3a0a628a75
3 changed files with 114 additions and 129 deletions

View File

@ -1003,7 +1003,7 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset)
break;
case BBT:
set_bbt (when, force);
set_bbt (when, offset, force);
break;
case MinSec:
@ -1226,7 +1226,7 @@ AudioClock::set_timecode (framepos_t when, bool /*force*/)
}
void
AudioClock::set_bbt (framepos_t when, bool /*force*/)
AudioClock::set_bbt (framepos_t when, framecnt_t offset, bool /*force*/)
{
char buf[16];
Timecode::BBT_Time BBT;
@ -1253,9 +1253,58 @@ AudioClock::set_bbt (framepos_t when, bool /*force*/)
BBT.beats = 0;
BBT.ticks = 0;
} else {
BBT = _session->tempo_map().bbt_at_frame (when);
BBT.bars--;
BBT.beats--;
TempoMap& tmap (_session->tempo_map());
const double divisions = tmap.meter_section_at_frame (offset).divisions_per_bar();
if (negative) {
BBT = tmap.bbt_at_beat (tmap.beat_at_frame (offset));
Timecode::BBT_Time when_bbt = tmap.bbt_at_frame (offset - when);
BBT.bars -= when_bbt.bars;
if (BBT.ticks < when_bbt.ticks) {
if (BBT.beats == 1) {
BBT.bars--;
BBT.beats = divisions;
} else {
BBT.beats--;
}
BBT.ticks = Timecode::BBT_Time::ticks_per_beat - (when_bbt.ticks - BBT.ticks);
} else {
BBT.ticks -= when_bbt.ticks;
}
if (BBT.beats < when_bbt.beats) {
BBT.bars--;
BBT.beats = divisions - (when_bbt.beats - BBT.beats);
} else {
BBT.beats -= when_bbt.beats;
}
} else {
BBT = tmap.bbt_at_beat (tmap.beat_at_frame (when + offset));
Timecode::BBT_Time when_bbt = tmap.bbt_at_frame (offset);
BBT.bars -= when_bbt.bars;
if (BBT.ticks < when_bbt.ticks) {
if (BBT.beats == 1) {
BBT.bars--;
BBT.beats = divisions;
} else {
BBT.beats--;
}
BBT.ticks = Timecode::BBT_Time::ticks_per_beat - (when_bbt.ticks - BBT.ticks);
} else {
BBT.ticks -= when_bbt.ticks;
}
if (BBT.beats < when_bbt.beats) {
BBT.bars--;
BBT.beats = divisions - (when_bbt.beats - BBT.beats);
} else {
BBT.beats -= when_bbt.beats;
}
}
}
} else {
BBT = _session->tempo_map().bbt_at_frame (when);
@ -1732,7 +1781,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev)
switch (ev->direction) {
case GDK_SCROLL_UP:
frames = get_frame_step (f);
frames = get_frame_step (f, current_time(), 1);
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;
@ -1743,7 +1792,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev)
break;
case GDK_SCROLL_DOWN:
frames = get_frame_step (f);
frames = get_frame_step (f, current_time(), -1);
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;

View File

@ -209,7 +209,7 @@ class AudioClock : public CairoWidget, public ARDOUR::SessionHandlePtr
void set_slave_info ();
void set_timecode (framepos_t, bool);
void set_bbt (framepos_t, bool);
void set_bbt (framepos_t, ARDOUR::framecnt_t, bool);
void set_minsec (framepos_t, bool);
void set_frames (framepos_t, bool);

View File

@ -3192,11 +3192,52 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
const double tick_at_time = max (0.0, beat_at_frame_locked (_metrics, pos)) * BBT_Time::ticks_per_beat;
const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
BBT_Time pos_bbt = bbt_at_frame_locked (_metrics, pos);
const framecnt_t offset = frame_at_bbt_locked (_metrics, pos_bbt);
const double divisions = meter_section_at_frame_locked (_metrics, pos).divisions_per_bar();
return frame_at_beat_locked (_metrics, total_beats);
if (dir > 0) {
pos_bbt.bars += bbt.bars;
pos_bbt.ticks += bbt.ticks;
if ((double) pos_bbt.ticks > BBT_Time::ticks_per_beat) {
pos_bbt.beats += 1;
pos_bbt.ticks -= BBT_Time::ticks_per_beat;
}
pos_bbt.beats += bbt.beats;
if ((double) pos_bbt.beats > divisions) {
pos_bbt.bars += 1;
pos_bbt.beats -= divisions;
}
return frame_at_bbt_locked (_metrics, pos_bbt) - offset;
} else {
pos_bbt.bars -= bbt.bars;
if (pos_bbt.ticks < bbt.ticks) {
if (pos_bbt.beats == 1) {
pos_bbt.bars--;
pos_bbt.beats = divisions;
} else {
pos_bbt.beats--;
}
pos_bbt.ticks = BBT_Time::ticks_per_beat - (bbt.ticks - pos_bbt.ticks);
} else {
pos_bbt.ticks -= bbt.ticks;
}
if (pos_bbt.beats <= bbt.beats) {
pos_bbt.bars--;
pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
} else {
pos_bbt.beats -= bbt.beats;
}
return offset - frame_at_bbt_locked (_metrics, pos_bbt);
}
return 0;
}
framepos_t
@ -3890,129 +3931,24 @@ TempoMap::n_meters() const
void
TempoMap::insert_time (framepos_t where, framecnt_t amount)
{
{
Glib::Threads::RWLock::WriterLock lm (lock);
for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
if ((*i)->frame() >= where && (*i)->movable ()) {
(*i)->set_frame ((*i)->frame() + amount);
for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
if ((*i)->frame() >= where && (*i)->movable ()) {
MeterSection* ms;
TempoSection* ts;
if ((ms = dynamic_cast <MeterSection*>(*i)) != 0) {
gui_move_meter (ms, (*i)->frame() + amount);
}
if ((ts = dynamic_cast <TempoSection*>(*i)) != 0) {
gui_move_tempo (ts, (*i)->frame() + amount, 0);
}
}
/* now reset the BBT time of all metrics, based on their new
* audio time. This is the only place where we do this reverse
* timestamp.
*/
Metrics::iterator i;
const MeterSection* meter;
const TempoSection* tempo;
MeterSection *m;
TempoSection *t;
meter = &first_meter ();
tempo = &first_tempo ();
BBT_Time start;
BBT_Time end;
// cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
bool first = true;
MetricSection* prev = 0;
for (i = _metrics.begin(); i != _metrics.end(); ++i) {
BBT_Time bbt;
//TempoMetric metric (*meter, *tempo);
MeterSection* ms = const_cast<MeterSection*>(meter);
TempoSection* ts = const_cast<TempoSection*>(tempo);
if (prev) {
if (ts){
if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
if (!t->active()) {
continue;
}
ts->set_pulse (t->pulse());
}
if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
ts->set_pulse (m->pulse());
}
ts->set_frame (prev->frame());
}
if (ms) {
if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
ms->set_beat (start);
ms->set_pulse (m->pulse());
}
if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
if (!t->active()) {
continue;
}
const double beat = beat_at_pulse_locked (_metrics, t->pulse());
pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
ms->set_beat (start);
ms->set_pulse (t->pulse());
}
ms->set_frame (prev->frame());
}
} else {
// metric will be at frames=0 bbt=1|1|0 by default
// which is correct for our purpose
}
// cerr << bbt << endl;
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
if (!t->active()) {
continue;
}
t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
tempo = t;
// cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
bbt = bbt_at_frame_locked (_metrics, m->frame());
// cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
if (first) {
first = false;
} else {
if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
/* round up to next beat */
bbt.beats += 1;
}
bbt.ticks = 0;
if (bbt.beats != 1) {
/* round up to next bar */
bbt.bars += 1;
bbt.beats = 1;
}
}
pair<double, BBT_Time> start = make_pair (max (0.0, beat_at_frame_locked (_metrics, m->frame())), bbt);
m->set_beat (start);
m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
meter = m;
// cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
} else {
fatal << _("programming error: unhandled MetricSection type") << endmsg;
abort(); /*NOTREACHED*/
}
prev = (*i);
}
recompute_map (_metrics);
}
PropertyChanged (PropertyChange ());
}
bool
TempoMap::remove_time (framepos_t where, framecnt_t amount)
{