/* XX replace old beats-per-minute name with note-types-per-minute */
if ((prop = node.property ("beats-per-minute")) != 0) {
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;
+ error << _("TempoSection XML node has an illegal \"beats-per-minute\" value") << endmsg;
throw failed_constructor();
}
}
throw failed_constructor();
}
- set_movable (string_is_affirmative (prop->value()));
+ set_initial (!string_is_affirmative (prop->value()));
if ((prop = node.property ("active")) == 0) {
warning << _("TempoSection XML node has no \"active\" property") << endmsg;
}
if ((prop = node.property ("lock-style")) == 0) {
- if (movable()) {
+ if (!initial()) {
set_position_lock_style (MusicTime);
} else {
set_position_lock_style (AudioTime);
root->add_property ("beats-per-minute", buf);
snprintf (buf, sizeof (buf), "%lf", _note_type);
root->add_property ("note-type", buf);
- snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
+ snprintf (buf, sizeof (buf), "%s", !initial()?"yes":"no");
root->add_property ("movable", buf);
snprintf (buf, sizeof (buf), "%s", active()?"yes":"no");
root->add_property ("active", buf);
*
*/
-/** user feedback dictates that if tempoA (120, 4.0) precedes tempoB (120, 8.0),
- * there will be no ramp between the two even if set to ramped.
+/** if tempoA (120, 4.0) precedes tempoB (120, 8.0),
+ * there should be no ramp between the two even if we are ramped.
* in other words a ramp should only place a curve on note_types_per_minute.
* we should be able to use Tempo note type here, but the above
* complicates things a bit.
- * we would ideally like to use arbitrary Tempo structs here.
*/
double
TempoSection::minute_at_ntpm (const double& ntpm, const double& p) const
return _time_at_pulse (p - pulse()) + minute();
}
+/** returns thw whole-note pulse at session frame position f.
+ * @param f the frame position.
+ * @return the position in whole-note pulses corresponding to f
+ *
+ * for use with musical units whose granularity is coarser than frames (e.g. ticks)
+*/
double
TempoSection::pulse_at_frame (const framepos_t& f) const
{
throw failed_constructor();
}
- set_movable (string_is_affirmative (prop->value()));
+ set_initial (!string_is_affirmative (prop->value()));
if ((prop = node.property ("lock-style")) == 0) {
warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
- if (movable()) {
+ if (!initial()) {
set_position_lock_style (MusicTime);
} else {
set_position_lock_style (AudioTime);
root->add_property ("lock-style", enum_2_string (position_lock_style()));
snprintf (buf, sizeof (buf), "%lf", _divisions_per_bar);
root->add_property ("divisions-per-bar", buf);
- snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
+ snprintf (buf, sizeof (buf), "%s", !initial()?"yes":"no");
root->add_property ("movable", buf);
return *root;
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);
- t->set_movable (false);
- m->set_movable (false);
+ t->set_initial (true);
+ m->set_initial (true);
/* note: frame time is correct (zero) for both of these */
for (i = _metrics.begin(); i != _metrics.end(); ++i) {
if (dynamic_cast<TempoSection*> (*i) != 0) {
if (tempo.frame() == (*i)->frame()) {
- if ((*i)->movable()) {
+ if (!(*i)->initial()) {
delete (*i);
_metrics.erase (i);
return true;
for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
if (dynamic_cast<MeterSection*> (*i) != 0) {
if (meter.frame() == (*i)->frame()) {
- if ((*i)->movable()) {
+ if (!(*i)->initial()) {
delete (*i);
_metrics.erase (i);
return true;
bool const ipm = insert_tempo->position_lock_style() == MusicTime;
if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
- if (!tempo->movable()) {
+ if (tempo->initial()) {
/* can't (re)move this section, so overwrite
* its data content (but not its properties as
if ((ipm && meter->beat() == insert_meter->beat()) || (!ipm && meter->frame() == insert_meter->frame())) {
- if (!meter->movable()) {
+ if (meter->initial()) {
/* can't (re)move this section, so overwrite
* its data content (but not its properties as
Glib::Threads::RWLock::WriterLock lm (lock);
const double beat = beat_at_bbt_locked (_metrics, where);
- if (ms.movable()) {
+ if (!ms.initial()) {
remove_meter_locked (ms);
add_meter_locked (meter, beat, where, pls, true);
} else {
if (!t->active()) {
continue;
}
- if (!t->movable()) {
+ if (t->initial()) {
return *t;
}
}
if (!t->active()) {
continue;
}
- if (!t->movable()) {
+ if (t->initial()) {
return *t;
}
}
if (!t->active()) {
continue;
}
- if (!t->movable()) {
+ if (t->initial()) {
if (!prev_t) {
t->set_pulse (0.0);
prev_t = t;
prev_t = t;
}
}
+ assert (prev_t);
prev_t->set_c_func (0.0);
}
TempoSection* t;
if ((*ii)->is_tempo()) {
t = static_cast<TempoSection*> (*ii);
- if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
+ if ((t->locked_to_meter() || t->initial()) && t->frame() == meter->frame()) {
meter_locked_tempo = t;
break;
}
}
if (prev_m) {
- const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
+ double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
if (beats + prev_m->beat() != meter->beat()) {
/* reordering caused a bbt change */
+
+ beats = meter->beat() - prev_m->beat();
b_bbt = make_pair (beats + prev_m->beat()
, BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
- } else if (meter->movable()) {
+ } else if (!meter->initial()) {
b_bbt = make_pair (meter->beat(), meter->bbt());
pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
}
prev_m = m;
}
}
+ assert (prev_m);
TempoSection* t;
}
}
+ assert (prev_t);
return prev_t->minute_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse());
}
prev_m = m;
}
}
+ assert (prev_m);
double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
return ret;
prev_m = m;
}
}
+ assert (prev_m);
const double beats_in_ms = beats - prev_m->beat();
const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
}
}
+ assert (prev_m);
+
const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
*
*/
double
-TempoMap::quarter_note_at_beat (const double beat)
+TempoMap::quarter_note_at_beat (const double beat) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
*
*/
double
-TempoMap::beat_at_quarter_note (const double quarter_note)
+TempoMap::beat_at_quarter_note (const double quarter_note) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
prev_t = t;
}
}
+ assert (prev_t);
const double start_qn = prev_t->pulse_at_frame (start);
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
TempoSection* t;
if ((*i)->is_tempo()) {
t = static_cast<TempoSection*> (*i);
- if (!t->movable()) {
+ if (t->initial()) {
t->set_active (true);
continue;
}
- if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
+ if (!t->initial() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
t->set_active (false);
t->set_pulse (0.0);
- } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
+ } else if (!t->initial() && t->position_lock_style() == AudioTime && t->frame() > frame) {
t->set_active (true);
- } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
+ } else if (!t->initial() && t->position_lock_style() == AudioTime && t->frame() == frame) {
return false;
}
}
MeterSection* m;
if (!(*i)->is_tempo()) {
m = static_cast<MeterSection*> (*i);
- if (!m->movable()) {
+ if (m->initial()) {
first_m_minute = m->minute();
break;
}
}
}
- if (section->movable() && minute <= first_m_minute) {
+ if (!section->initial() && minute <= first_m_minute) {
return false;
}
if (!t->active()) {
continue;
}
- if (!t->movable()) {
+ if (t->initial()) {
t->set_pulse (0.0);
prev_t = t;
continue;
bool
TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const double& minute)
{
- /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
+ /* disallow moving first meter past any subsequent one, and any initial meter before the first one */
const MeterSection* other = &meter_section_at_minute_locked (imaginary, minute);
- if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->minute() >= minute)) {
+ if ((section->initial() && !other->initial()) || (other->initial() && !section->initial() && other->minute() >= minute)) {
return false;
}
- if (!section->movable()) {
+ if (section->initial()) {
/* lock the first tempo to our first meter */
if (!set_active_tempos (imaginary, section->frame_at_minute (minute))) {
return false;
TempoSection* t;
if ((*ii)->is_tempo()) {
t = static_cast<TempoSection*> (*ii);
- if ((t->locked_to_meter() || !t->movable()) && t->minute() == section->minute()) {
+ if ((t->locked_to_meter() || t->initial()) && t->minute() == section->minute()) {
meter_locked_tempo = t;
break;
}
if (!(*i)->is_tempo()) {
m = static_cast<MeterSection*> (*i);
if (m == section){
- if (prev_m && section->movable()) {
+ if (prev_m && !section->initial()) {
const double beats = (pulse_at_minute_locked (imaginary, minute) - prev_m->pulse()) * prev_m->note_divisor();
if (beats + prev_m->beat() < section->beat()) {
/* set the section pulse according to its musical position,
}
}
} else {
- /* not movable (first meter atm) */
+ /* initial (first meter atm) */
tempo_copy->set_minute (minute);
tempo_copy->set_pulse (0.0);
MeterSection* m;
if (!(*i)->is_tempo()) {
m = static_cast<MeterSection*> (*i);
+
+ if (m == section) {
+ continue;
+ }
+
pair<double, BBT_Time> b_bbt;
double new_pulse = 0.0;
if (prev_m && m->bbt().bars > when.bars && !section_prev){
section_prev = prev_m;
+
const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
section->set_pulse (pulse);
section->set_minute (minute_at_pulse_locked (imaginary, pulse));
prev_m = section;
- continue;
}
if (m->position_lock_style() == AudioTime) {
TempoSection* t;
if ((*ii)->is_tempo()) {
t = static_cast<TempoSection*> (*ii);
- if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
+ if ((t->locked_to_meter() || t->initial()) && t->frame() == m->frame()) {
meter_locked_tempo = t;
break;
}
}
if (prev_m) {
- const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+ double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
if (beats + prev_m->beat() != m->beat()) {
/* tempo/ meter change caused a change in beat (bar). */
+
+ /* the user has requested that the previous section of music overlaps this one.
+ we have no choice but to change the bar number here, as being locked to audio means
+ we must stay where we are on the timeline.
+ */
+ beats = m->beat() - prev_m->beat();
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() + (beats / prev_m->note_divisor());
- } else if (m->movable()) {
+
+ } else if (!m->initial()) {
b_bbt = make_pair (m->beat(), m->bbt());
new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
}
const double beat = beat_at_bbt_locked (future_map, bbt);
+ if (section->position_lock_style() == AudioTime) {
+ tempo_copy->set_position_lock_style (MusicTime);
+ }
+
if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
ret.first = tempo_copy->pulse();
ret.second = tempo_copy->frame();
TempoSection* prev_to_prev_t = 0;
const frameoffset_t fr_off = end_frame - frame;
- if (prev_t && prev_t->pulse() > 0.0) {
+ assert (prev_t);
+
+ if (prev_t->pulse() > 0.0) {
prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_minute_locked (future_map, minute_at_frame (prev_t->frame() - 1)));
}
* This function is sensitive to tempo and meter.
*/
double
-TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
}
double
-TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions)
+TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions) const
{
return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
}
* This function is tempo-sensitive.
*/
double
-TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
}
double
-TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num) const
{
double qn = quarter_note_at_minute_locked (metrics, minute_at_frame (frame));
Glib::Threads::RWLock::ReaderLock lm (lock);
BBT_Time pos_bbt = bbt_at_minute_locked (_metrics, minute_at_frame (pos));
- const framecnt_t offset = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+
const double divisions = meter_section_at_minute_locked (_metrics, minute_at_frame (pos)).divisions_per_bar();
if (dir > 0) {
pos_bbt.bars += 1;
pos_bbt.beats -= divisions;
}
+ const framecnt_t pos_bbt_frame = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+
+ return pos_bbt_frame - pos;
- return frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt)) - offset;
} else {
- pos_bbt.bars -= bbt.bars;
+
+ if (pos_bbt.bars <= bbt.bars) {
+ pos_bbt.bars = 1;
+ } else {
+ pos_bbt.bars -= bbt.bars;
+ }
if (pos_bbt.ticks < bbt.ticks) {
- if (pos_bbt.beats == 1) {
- pos_bbt.bars--;
- pos_bbt.beats = divisions;
+ if (pos_bbt.bars > 1) {
+ 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.beats--;
+ pos_bbt.beats = 1;
+ pos_bbt.ticks = 0;
}
- 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);
+ if (pos_bbt.bars > 1) {
+ pos_bbt.bars--;
+ pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
+ } else {
+ pos_bbt.beats = 1;
+ }
} else {
pos_bbt.beats -= bbt.beats;
}
- return offset - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+ return pos - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
}
return 0;
ts_at = t;
}
}
+ assert (ts_at);
if (ts_after) {
return (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)).quarter_notes_per_minute();
TempoSection* t;
if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
- if (!m->movable()) {
+ if (m->initial()) {
pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
m->set_beat (bbt);
m->set_pulse (0.0);
continue;
}
- if (!t->movable()) {
+ if (t->initial()) {
t->set_pulse (0.0);
t->set_minute (0.0);
t->set_position_lock_style (AudioTime);
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
o << "Tempo @ " << *i << t->note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
<< " 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() << " (initial? " << t->initial() << ')'
<< " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
if (prev_t) {
- o << std::setprecision (17) << " current : " << t->note_types_per_minute()
+ o << " current : " << t->note_types_per_minute()
<< " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
o << " previous : " << prev_t->note_types_per_minute()
<< " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
} 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() << " pulse: " << m->pulse() << " beat : " << m->beat()
- << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
+ << " pos lock: " << enum_2_string (m->position_lock_style()) << " (initial? " << m->initial() << ')' << endl;
}
}
o << "------" << std::endl;
TempoMap::insert_time (framepos_t where, framecnt_t amount)
{
for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
- if ((*i)->frame() >= where && (*i)->movable ()) {
+ if ((*i)->frame() >= where && !(*i)->initial ()) {
MeterSection* ms;
TempoSection* ts;