mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 19:56:31 +01:00
Tempo ramps - music-locked meter drags are now bbt based.
This commit is contained in:
parent
3c76fa9dd1
commit
992fc6b510
3 changed files with 129 additions and 64 deletions
|
|
@ -3199,17 +3199,15 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
|
||||||
Timecode::BBT_Time bbt;
|
Timecode::BBT_Time bbt;
|
||||||
map.bbt_time (pf, bbt);
|
map.bbt_time (pf, bbt);
|
||||||
/* round bbt to bars */
|
/* round bbt to bars */
|
||||||
map.round_bbt (bbt, -1);
|
map.round_bbt (bbt, -1, RoundNearest);
|
||||||
const MeterSection& prev_m = map.meter_section_at (_real_section->frame() - 1);
|
|
||||||
|
|
||||||
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier ())) {
|
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier ())) {
|
||||||
|
/* adjust previous tempo to match meter frame */
|
||||||
_editor->session()->tempo_map().gui_dilate_tempo (_real_section, pf);
|
_editor->session()->tempo_map().gui_dilate_tempo (_real_section, pf);
|
||||||
} else if (bbt.bars > _real_section->bbt().bars) {
|
} else if ((bbt.bars > _real_section->bbt().bars && pf > last_pointer_frame())
|
||||||
const double pulse = _real_section->pulse() + (prev_m.note_divisor() / prev_m.divisions_per_bar());
|
|| (bbt.bars < _real_section->bbt().bars && pf < last_pointer_frame())) {
|
||||||
_editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
|
/* move meter beat-based */
|
||||||
} else if (bbt.bars < _real_section->bbt().bars) {
|
_editor->session()->tempo_map().gui_move_meter (_real_section, bbt);
|
||||||
const double pulse = _real_section->pulse() - (prev_m.note_divisor() / prev_m.divisions_per_bar());
|
|
||||||
_editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* AudioTime */
|
/* AudioTime */
|
||||||
|
|
@ -3352,17 +3350,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
||||||
|
|
||||||
if (_real_section->position_lock_style() == MusicTime) {
|
if (_real_section->position_lock_style() == MusicTime) {
|
||||||
if (use_snap && _editor->snap_type() == SnapToBar) {
|
if (use_snap && _editor->snap_type() == SnapToBar) {
|
||||||
map.round_bbt (bbt, -1);
|
map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
|
||||||
} else if (use_snap) {
|
} else if (use_snap) {
|
||||||
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
|
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
|
||||||
}
|
}
|
||||||
double const pulse = map.predict_tempo_pulse (_real_section, map.frame_time (bbt));
|
double const pulse = map.predict_tempo_pulse (_real_section, map.frame_time (bbt));
|
||||||
_real_section = map.add_tempo (_marker->tempo(), pulse, _real_section->type());
|
_real_section = map.add_tempo (_marker->tempo(), pulse, _real_section->type());
|
||||||
} else {
|
} else {
|
||||||
if (use_snap && _editor->snap_type() == SnapToBar) {
|
if (use_snap && _editor->snap_type() == SnapToBar) {
|
||||||
map.round_bbt (bbt, -1);
|
map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
|
||||||
} else if (use_snap) {
|
} else if (use_snap) {
|
||||||
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
|
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
|
||||||
}
|
}
|
||||||
if (use_snap) {
|
if (use_snap) {
|
||||||
frame = map.predict_tempo_frame (_real_section, bbt);
|
frame = map.predict_tempo_frame (_real_section, bbt);
|
||||||
|
|
@ -3417,17 +3415,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
||||||
const double pulse = map.predict_tempo_pulse (_real_section, pf);
|
const double pulse = map.predict_tempo_pulse (_real_section, pf);
|
||||||
when = map.pulse_to_bbt (pulse);
|
when = map.pulse_to_bbt (pulse);
|
||||||
if (use_snap && _editor->snap_type() == SnapToBar) {
|
if (use_snap && _editor->snap_type() == SnapToBar) {
|
||||||
map.round_bbt (when, -1);
|
map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
|
||||||
} else if (use_snap) {
|
} else if (use_snap) {
|
||||||
map.round_bbt (when, _editor->get_grid_beat_divisions (0));
|
map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
|
||||||
}
|
}
|
||||||
const double beat = map.bbt_to_beats (when);
|
const double beat = map.bbt_to_beats (when);
|
||||||
map.gui_move_tempo_beat (_real_section, beat);
|
map.gui_move_tempo_beat (_real_section, beat);
|
||||||
} else {
|
} else {
|
||||||
if (use_snap && _editor->snap_type() == SnapToBar) {
|
if (use_snap && _editor->snap_type() == SnapToBar) {
|
||||||
map.round_bbt (when, -1);
|
map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
|
||||||
} else if (use_snap) {
|
} else if (use_snap) {
|
||||||
map.round_bbt (when, _editor->get_grid_beat_divisions (0));
|
map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
|
||||||
}
|
}
|
||||||
if (use_snap) {
|
if (use_snap) {
|
||||||
pf = map.predict_tempo_frame (_real_section, when);
|
pf = map.predict_tempo_frame (_real_section, when);
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||||
void gui_move_tempo_beat (TempoSection*, const double& beat);
|
void gui_move_tempo_beat (TempoSection*, const double& beat);
|
||||||
void gui_move_tempo_pulse (TempoSection*, const double& pulse);
|
void gui_move_tempo_pulse (TempoSection*, const double& pulse);
|
||||||
void gui_move_meter (MeterSection*, const framepos_t& frame);
|
void gui_move_meter (MeterSection*, const framepos_t& frame);
|
||||||
void gui_move_meter (MeterSection*, const double& pulse);
|
void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
|
||||||
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
|
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
|
||||||
void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
|
void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
|
||||||
|
|
||||||
|
|
@ -408,7 +408,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||||
framepos_t round_to_bar (framepos_t frame, RoundMode dir);
|
framepos_t round_to_bar (framepos_t frame, RoundMode dir);
|
||||||
framepos_t round_to_beat (framepos_t frame, RoundMode dir);
|
framepos_t round_to_beat (framepos_t frame, RoundMode dir);
|
||||||
framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir);
|
framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir);
|
||||||
void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor);
|
void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor, RoundMode dir);
|
||||||
|
|
||||||
void set_length (framepos_t frames);
|
void set_length (framepos_t frames);
|
||||||
|
|
||||||
|
|
@ -477,7 +477,7 @@ private:
|
||||||
bool solve_map (Metrics& metrics, TempoSection* section, const framepos_t& frame);
|
bool solve_map (Metrics& metrics, TempoSection* section, const framepos_t& frame);
|
||||||
bool solve_map (Metrics& metrics, TempoSection* section, const double& pulse);
|
bool solve_map (Metrics& metrics, TempoSection* section, const double& pulse);
|
||||||
bool solve_map (Metrics& metrics, MeterSection* section, const framepos_t& frame);
|
bool solve_map (Metrics& metrics, MeterSection* section, const framepos_t& frame);
|
||||||
bool solve_map (Metrics& metrics, MeterSection* section, const double& pulse);
|
bool solve_map (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt);
|
||||||
|
|
||||||
friend class ::BBTTest;
|
friend class ::BBTTest;
|
||||||
friend class ::FrameposPlusBeatsTest;
|
friend class ::FrameposPlusBeatsTest;
|
||||||
|
|
|
||||||
|
|
@ -1105,7 +1105,7 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
|
||||||
do_insert (new_meter);
|
do_insert (new_meter);
|
||||||
|
|
||||||
if (recompute) {
|
if (recompute) {
|
||||||
solve_map (_metrics, new_meter, pulse);
|
solve_map (_metrics, new_meter, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_meter;
|
return new_meter;
|
||||||
|
|
@ -2092,10 +2092,8 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
|
||||||
TempoSection* t;
|
TempoSection* t;
|
||||||
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
|
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
|
||||||
if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
|
if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
|
||||||
if (t->frame() == section->frame()) {
|
meter_locked_tempo = t;
|
||||||
meter_locked_tempo = t;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2209,7 +2207,6 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
|
||||||
section->set_pulse (0.0);
|
section->set_pulse (0.0);
|
||||||
|
|
||||||
}
|
}
|
||||||
//section->set_frame (frame);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2232,33 +2229,37 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pulse)
|
TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
|
||||||
{
|
{
|
||||||
MeterSection* prev_m = 0;
|
MeterSection* prev_m = 0;
|
||||||
|
|
||||||
section->set_pulse (pulse);
|
|
||||||
|
|
||||||
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
|
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
|
||||||
MeterSection* m;
|
MeterSection* m;
|
||||||
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
|
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
|
||||||
double new_pulse = 0.0;
|
|
||||||
pair<double, BBT_Time> b_bbt;
|
pair<double, BBT_Time> b_bbt;
|
||||||
|
double new_pulse = 0.0;
|
||||||
|
|
||||||
if (prev_m && m == section){
|
if (prev_m && m == section){
|
||||||
/* the first meter is always audio-locked, so prev_m should exist.
|
const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
|
||||||
should we allow setting audio locked meters by pulse?
|
const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
|
||||||
*/
|
|
||||||
const double beats = floor (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + 0.5);
|
b_bbt = make_pair (beats + prev_m->beat(), when);
|
||||||
const int32_t bars = (beats) / prev_m->divisions_per_bar();
|
|
||||||
pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), BBT_Time (bars + prev_m->bbt().bars, 1, 0));
|
|
||||||
section->set_beat (b_bbt);
|
section->set_beat (b_bbt);
|
||||||
|
section->set_pulse (pulse);
|
||||||
section->set_frame (frame_at_pulse_locked (imaginary, pulse));
|
section->set_frame (frame_at_pulse_locked (imaginary, pulse));
|
||||||
|
|
||||||
prev_m = m;
|
prev_m = m;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
} else if (m->bbt().bars == when.bars) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->position_lock_style() == AudioTime) {
|
if (m->position_lock_style() == AudioTime) {
|
||||||
if (m->movable()) {
|
if (m->movable()) {
|
||||||
const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
|
const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
|
||||||
|
|
||||||
if (beats + prev_m->beat() != m->beat()) {
|
if (beats + prev_m->beat() != m->beat()) {
|
||||||
/* tempo/ meter change caused a change in beat (bar). */
|
/* tempo/ meter change caused a change in beat (bar). */
|
||||||
b_bbt = make_pair (beats + prev_m->beat()
|
b_bbt = make_pair (beats + prev_m->beat()
|
||||||
|
|
@ -2271,12 +2272,23 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pu
|
||||||
} else {
|
} else {
|
||||||
b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
|
b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m->set_beat (b_bbt);
|
||||||
|
m->set_pulse (new_pulse);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar() / prev_m->note_divisor());
|
const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
|
||||||
b_bbt = make_pair (((new_pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat(), m->bbt());
|
|
||||||
|
b_bbt = make_pair (beats + prev_m->beat()
|
||||||
|
, BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
|
||||||
|
new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar()
|
||||||
|
/ prev_m->note_divisor());
|
||||||
|
|
||||||
|
m->set_beat (b_bbt);
|
||||||
|
m->set_pulse (new_pulse);
|
||||||
|
m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
|
||||||
}
|
}
|
||||||
m->set_beat (b_bbt);
|
|
||||||
m->set_pulse (new_pulse);
|
|
||||||
prev_m = m;
|
prev_m = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2521,14 +2533,14 @@ TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TempoMap::gui_move_meter (MeterSection* ms, const double& pulse)
|
TempoMap::gui_move_meter (MeterSection* ms, const Timecode::BBT_Time& bbt)
|
||||||
{
|
{
|
||||||
Metrics future_map;
|
Metrics future_map;
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (lock);
|
Glib::Threads::RWLock::WriterLock lm (lock);
|
||||||
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
|
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
|
||||||
if (solve_map (future_map, copy, pulse)) {
|
if (solve_map (future_map, copy, bbt)) {
|
||||||
solve_map (_metrics, ms, pulse);
|
solve_map (_metrics, ms, bbt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2821,16 +2833,27 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
|
TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
|
||||||
{
|
{
|
||||||
if (sub_num == -1) {
|
if (sub_num == -1) {
|
||||||
const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
|
if (dir > 0) {
|
||||||
if ((double) when.beats > bpb / 2.0) {
|
|
||||||
++when.bars;
|
++when.bars;
|
||||||
|
when.beats = 1;
|
||||||
|
when.ticks = 0;
|
||||||
|
} else if (dir < 0) {
|
||||||
|
when.beats = 1;
|
||||||
|
when.ticks = 0;
|
||||||
|
} else {
|
||||||
|
const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
|
||||||
|
if ((double) when.beats > bpb / 2.0) {
|
||||||
|
++when.bars;
|
||||||
|
}
|
||||||
|
when.beats = 1;
|
||||||
|
when.ticks = 0;
|
||||||
}
|
}
|
||||||
when.beats = 1;
|
|
||||||
when.ticks = 0;
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (sub_num == 0) {
|
} else if (sub_num == 0) {
|
||||||
const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
|
const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
|
||||||
if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
|
if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
|
||||||
|
|
@ -2841,32 +2864,76 @@ TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when.ticks = 0;
|
when.ticks = 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
|
const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
|
||||||
double rem;
|
|
||||||
if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
|
|
||||||
/* closer to the next subdivision, so shift forward */
|
|
||||||
|
|
||||||
when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
|
if (dir > 0) {
|
||||||
|
/* round to next (or same iff dir == RoundUpMaybe) */
|
||||||
|
|
||||||
if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
|
uint32_t mod = when.ticks % ticks_one_subdivisions_worth;
|
||||||
++when.beats;
|
|
||||||
when.ticks -= Timecode::BBT_Time::ticks_per_beat;
|
if (mod == 0 && dir == RoundUpMaybe) {
|
||||||
|
/* right on the subdivision, which is fine, so do nothing */
|
||||||
|
|
||||||
|
} else if (mod == 0) {
|
||||||
|
/* right on the subdivision, so the difference is just the subdivision ticks */
|
||||||
|
when.ticks += ticks_one_subdivisions_worth;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* not on subdivision, compute distance to next subdivision */
|
||||||
|
|
||||||
|
when.ticks += ticks_one_subdivisions_worth - mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (rem > 0) {
|
if (when.ticks >= BBT_Time::ticks_per_beat) {
|
||||||
/* closer to previous subdivision, so shift backward */
|
when.ticks -= BBT_Time::ticks_per_beat;
|
||||||
|
}
|
||||||
|
|
||||||
if (rem > when.ticks) {
|
} else if (dir < 0) {
|
||||||
if (when.beats == 0) {
|
/* round to previous (or same iff dir == RoundDownMaybe) */
|
||||||
/* can't go backwards past zero, so ... */
|
|
||||||
}
|
uint32_t difference = when.ticks % ticks_one_subdivisions_worth;
|
||||||
/* step back to previous beat */
|
|
||||||
--when.beats;
|
if (difference == 0 && dir == RoundDownAlways) {
|
||||||
when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
|
/* right on the subdivision, but force-rounding down,
|
||||||
|
so the difference is just the subdivision ticks */
|
||||||
|
difference = ticks_one_subdivisions_worth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (when.ticks < difference) {
|
||||||
|
when.ticks = BBT_Time::ticks_per_beat - when.ticks;
|
||||||
} else {
|
} else {
|
||||||
when.ticks = when.ticks - rem;
|
when.ticks -= difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* round to nearest */ double rem;
|
||||||
|
if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
|
||||||
|
/* closer to the next subdivision, so shift forward */
|
||||||
|
|
||||||
|
when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
|
||||||
|
|
||||||
|
if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
|
||||||
|
++when.beats;
|
||||||
|
when.ticks -= Timecode::BBT_Time::ticks_per_beat;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (rem > 0) {
|
||||||
|
/* closer to previous subdivision, so shift backward */
|
||||||
|
|
||||||
|
if (rem > when.ticks) {
|
||||||
|
if (when.beats == 0) {
|
||||||
|
/* can't go backwards past zero, so ... */
|
||||||
|
}
|
||||||
|
/* step back to previous beat */
|
||||||
|
--when.beats;
|
||||||
|
when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
|
||||||
|
} else {
|
||||||
|
when.ticks = when.ticks - rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue