TempoSection methods deal in beats rather than pulses per minute.

- removes note type from curve function for a slightly more
	  accurate result.
This commit is contained in:
nick_m 2016-10-09 03:46:50 +11:00
parent b1df56d531
commit 2f72b42385
3 changed files with 67 additions and 69 deletions

View file

@ -121,7 +121,7 @@ TempoCurve::set_position (framepos_t frame, framepos_t end_frame)
points->push_back (ArdourCanvas::Duple (0.0, curve_height)); points->push_back (ArdourCanvas::Duple (0.0, curve_height));
if (end_frame == UINT32_MAX) { if (end_frame == UINT32_MAX) {
const double tempo_at = _tempo.tempo_at_frame (frame, editor.session()->frame_rate()) * _tempo.note_type(); const double tempo_at = _tempo.tempo_at_frame (frame, editor.session()->frame_rate());
const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height); const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height);
points->push_back (ArdourCanvas::Duple (0.0, y_pos)); points->push_back (ArdourCanvas::Duple (0.0, y_pos));
@ -133,7 +133,7 @@ TempoCurve::set_position (framepos_t frame, framepos_t end_frame)
framepos_t current_frame = frame; framepos_t current_frame = frame;
while (current_frame < (end_frame - frame_step)) { while (current_frame < (end_frame - frame_step)) {
const double tempo_at = _tempo.tempo_at_frame (current_frame, editor.session()->frame_rate()) * _tempo.note_type(); const double tempo_at = _tempo.tempo_at_frame (current_frame, editor.session()->frame_rate());
const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0); const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0);
points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (current_frame - frame), min (y_pos, curve_height))); points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (current_frame - frame), min (y_pos, curve_height)));
@ -141,7 +141,7 @@ TempoCurve::set_position (framepos_t frame, framepos_t end_frame)
current_frame += frame_step; current_frame += frame_step;
} }
const double tempo_at = _tempo.tempo_at_frame (end_frame, editor.session()->frame_rate()) * _tempo.note_type(); const double tempo_at = _tempo.tempo_at_frame (end_frame, editor.session()->frame_rate());
const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0); const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0);
points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel ((end_frame - 1) - frame), min (y_pos, curve_height))); points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel ((end_frame - 1) - frame), min (y_pos, curve_height)));

View file

@ -62,7 +62,6 @@ class LIBARDOUR_API Tempo {
double beats_per_minute () const { return _beats_per_minute; } double beats_per_minute () const { return _beats_per_minute; }
void set_beats_per_minute (double bpm) { _beats_per_minute = bpm; } void set_beats_per_minute (double bpm) { _beats_per_minute = bpm; }
double note_type () const { return _note_type; } double note_type () const { return _note_type; }
double pulses_per_minute () const { return _beats_per_minute / _note_type; }
/** audio samples per beat /** audio samples per beat
* @param sr samplerate * @param sr samplerate
*/ */
@ -221,14 +220,14 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
double a_func (double end_tpm, double c_func) const; double a_func (double end_tpm, double c_func) const;
double c_func (double end_tpm, double end_time) const; double c_func (double end_tpm, double end_time) const;
double pulse_tempo_at_time (const double& time) const; double _tempo_at_time (const double& time) const;
double time_at_pulse_tempo (const double& pulse_tempo) const; double _time_at_tempo (const double& tempo) const;
double pulse_tempo_at_pulse (const double& pulse) const; double _tempo_at_pulse (const double& pulse) const;
double pulse_at_pulse_tempo (const double& pulse_tempo) const; double _pulse_at_tempo (const double& tempo) const;
double pulse_at_time (const double& time) const; double _pulse_at_time (const double& time) const;
double time_at_pulse (const double& pulse) const; double _time_at_pulse (const double& pulse) const;
/* this value provides a fractional offset into the bar in which /* this value provides a fractional offset into the bar in which
the tempo section is located in. A value of 0.0 indicates that the tempo section is located in. A value of 0.0 indicates that

View file

@ -204,58 +204,58 @@ TempoSection::set_type (Type type)
_type = type; _type = type;
} }
/** returns the tempo in whole pulses per minute at the zero-based (relative to session) frame. /** returns the tempo in beats per minute at the zero-based (relative to session) frame.
*/ */
double double
TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return pulses_per_minute(); return beats_per_minute();
} }
return pulse_tempo_at_time (frame_to_minute (f - frame(), frame_rate)); return _tempo_at_time (frame_to_minute (f - frame(), frame_rate));
} }
/** returns the zero-based frame (relative to session) /** returns the zero-based frame (relative to session)
where the tempo in whole pulses per minute occurs in this section. where the tempo in beats per minute occurs in this section.
pulse p is only used for constant tempos. pulse p is only used for constant tempos.
note that the tempo map may have multiple such values. note that the tempo map may have multiple such values.
*/ */
framepos_t framepos_t
TempoSection::frame_at_tempo (const double& ppm, const double& p, const framecnt_t& frame_rate) const TempoSection::frame_at_tempo (const double& bpm, const double& p, const framecnt_t& frame_rate) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return ((p - pulse()) * frames_per_pulse (frame_rate)) + frame(); return ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
} }
return minute_to_frame (time_at_pulse_tempo (ppm), frame_rate) + frame(); return minute_to_frame (_time_at_tempo (bpm), frame_rate) + frame();
} }
/** returns the tempo in whole pulses per minute at the zero-based (relative to session) beat. /** returns the tempo in beats per minute at the zero-based (relative to session) pulse.
*/ */
double double
TempoSection::tempo_at_pulse (const double& p) const TempoSection::tempo_at_pulse (const double& p) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
return pulses_per_minute(); return beats_per_minute();
}
double const ppm = pulse_tempo_at_pulse (p - pulse());
return ppm;
} }
/** returns the zero-based beat (relative to session) return _tempo_at_pulse (p - pulse());
where the tempo in whole pulses per minute occurs given frame f. frame f is only used for constant tempos. }
/** returns the zero-based pulse (relative to session)
where the tempo in qn beats per minute occurs given frame f. frame f is only used for constant tempi.
note that the session tempo map may have multiple beats at a given tempo. note that the session tempo map may have multiple beats at a given tempo.
*/ */
double double
TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const framecnt_t& frame_rate) const TempoSection::pulse_at_tempo (const double& bpm, const framepos_t& f, const framecnt_t& frame_rate) const
{ {
if (_type == Constant || _c_func == 0.0) { if (_type == Constant || _c_func == 0.0) {
double const pulses = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse(); double const pulses = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
return pulses; return pulses;
} }
return pulse_at_pulse_tempo (ppm) + pulse(); return _pulse_at_tempo (bpm) + pulse();
} }
/** returns the zero-based pulse (relative to session origin) /** returns the zero-based pulse (relative to session origin)
@ -269,7 +269,7 @@ TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate)
return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse(); return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
} }
return pulse_at_time (frame_to_minute (f - frame(), frame_rate)) + pulse(); return _pulse_at_time (frame_to_minute (f - frame(), frame_rate)) + pulse();
} }
/** returns the zero-based frame (relative to session start frame) /** returns the zero-based frame (relative to session start frame)
@ -284,7 +284,7 @@ TempoSection::frame_at_pulse (const double& p, const framecnt_t& frame_rate) con
return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame(); return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
} }
return minute_to_frame (time_at_pulse (p - pulse()), frame_rate) + frame(); return minute_to_frame (_time_at_pulse (p - pulse()), frame_rate) + frame();
} }
/* /*
@ -363,17 +363,17 @@ https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Te
*/ */
/* /*
compute this ramp's function constant using the end tempo (in whole pulses per minute) compute this ramp's function constant using the end tempo (in qn beats per minute)
and duration (pulses into global start) of some later tempo section. and duration (pulses into global start) of some later tempo section.
*/ */
double double
TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate) TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate)
{ {
double const log_tempo_ratio = log (end_bpm / pulses_per_minute()); double const log_tempo_ratio = log (end_bpm / beats_per_minute());
return pulses_per_minute() * (expm1 (log_tempo_ratio)) / (end_pulse - pulse()); return (beats_per_minute() * expm1 (log_tempo_ratio)) / ((end_pulse - pulse()) * _note_type);
} }
/* compute the function constant from some later tempo section, given tempo (whole pulses/min.) and distance (in frames) from session origin */ /* compute the function constant from some later tempo section, given tempo (quarter notes/min.) and distance (in frames) from session origin */
double double
TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const
{ {
@ -394,58 +394,58 @@ TempoSection::frame_to_minute (const framepos_t& frame, const framecnt_t& frame_
/* position function */ /* position function */
double double
TempoSection::a_func (double end_ppm, double c_func) const TempoSection::a_func (double end_bpm, double c_func) const
{ {
return log (end_ppm / pulses_per_minute()) / c_func; return log (end_bpm / beats_per_minute()) / c_func;
} }
/*function constant*/ /*function constant*/
double double
TempoSection::c_func (double end_ppm, double end_time) const TempoSection::c_func (double end_bpm, double end_time) const
{ {
return log (end_ppm / pulses_per_minute()) / end_time; return log (end_bpm / beats_per_minute()) / end_time;
} }
/* tempo in ppm at time in minutes */ /* tempo in bpm at time in minutes */
double double
TempoSection::pulse_tempo_at_time (const double& time) const TempoSection::_tempo_at_time (const double& time) const
{ {
return exp (_c_func * time) * pulses_per_minute(); return exp (_c_func * time) * beats_per_minute();
} }
/* time in minutes at tempo in ppm */ /* time in minutes at tempo in bpm */
double double
TempoSection::time_at_pulse_tempo (const double& pulse_tempo) const TempoSection::_time_at_tempo (const double& tempo) const
{ {
return log (pulse_tempo / pulses_per_minute()) / _c_func; return log (tempo / beats_per_minute()) / _c_func;
} }
/* pulse at tempo in ppm */ /* pulse at tempo in bpm */
double double
TempoSection::pulse_at_pulse_tempo (const double& pulse_tempo) const TempoSection::_pulse_at_tempo (const double& tempo) const
{ {
return (pulse_tempo - pulses_per_minute()) / _c_func; return (tempo - beats_per_minute()) / (_c_func * _note_type);
} }
/* tempo in ppm at pulse */ /* tempo in bpm at pulse */
double double
TempoSection::pulse_tempo_at_pulse (const double& pulse) const TempoSection::_tempo_at_pulse (const double& pulse) const
{ {
return (pulse * _c_func) + pulses_per_minute(); return (pulse * _note_type * _c_func) + beats_per_minute();
} }
/* pulse at time in minutes */ /* pulse at time in minutes */
double double
TempoSection::pulse_at_time (const double& time) const TempoSection::_pulse_at_time (const double& time) const
{ {
return expm1 (_c_func * time) * (pulses_per_minute() / _c_func); return expm1 (_c_func * time) * (beats_per_minute() / (_c_func * _note_type));
} }
/* time in minutes at pulse */ /* time in minutes at pulse */
double double
TempoSection::time_at_pulse (const double& pulse) const TempoSection::_time_at_pulse (const double& pulse) const
{ {
return log1p ((_c_func * pulse) / pulses_per_minute()) / _c_func; return log1p ((_c_func * pulse * _note_type) / beats_per_minute()) / _c_func;
} }
/***********************************************************************/ /***********************************************************************/
@ -1269,14 +1269,14 @@ TempoMap::recompute_tempi (Metrics& metrics)
} }
if (prev_t) { if (prev_t) {
if (t->position_lock_style() == AudioTime) { if (t->position_lock_style() == AudioTime) {
prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute(), t->frame(), _frame_rate));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate)); t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate));
} }
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse(), _frame_rate));
t->set_frame (prev_t->frame_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)); t->set_frame (prev_t->frame_at_tempo (t->beats_per_minute(), t->pulse(), _frame_rate));
} }
} }
@ -1559,7 +1559,7 @@ TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame
} }
if ((prev_t) && t->frame() > frame) { if ((prev_t) && t->frame() > frame) {
/* t is the section past frame */ /* t is the section past frame */
const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type(); const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate);
const Tempo ret_tempo (ret_bpm, prev_t->note_type()); const Tempo ret_tempo (ret_bpm, prev_t->note_type());
return ret_tempo; return ret_tempo;
} }
@ -1590,7 +1590,7 @@ framepos_t
TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
{ {
TempoSection* prev_t = 0; TempoSection* prev_t = 0;
const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type(); const double tempo_ppm = tempo.beats_per_minute();
Metrics::const_iterator i; Metrics::const_iterator i;
@ -1603,14 +1603,14 @@ TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) con
continue; continue;
} }
const double t_ppm = t->beats_per_minute() / t->note_type(); const double t_ppm = t->beats_per_minute();
if (t_ppm == tempo_ppm) { if (t_ppm == tempo_ppm) {
return t->frame(); return t->frame();
} }
if (prev_t) { if (prev_t) {
const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type(); const double prev_t_ppm = prev_t->beats_per_minute();
if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) { if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
return prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate); return prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
@ -1632,9 +1632,8 @@ TempoMap::tempo_at_beat (const double& beat) const
Glib::Threads::RWLock::ReaderLock lm (lock); Glib::Threads::RWLock::ReaderLock lm (lock);
const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat); const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat); const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
const double note_type = prev_t->note_type();
return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type); return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()), prev_t->note_type());
} }
double double
@ -2208,7 +2207,7 @@ TempoMap::check_solved (const Metrics& metrics) const
} }
/* precision check ensures tempo and frames align.*/ /* precision check ensures tempo and frames align.*/
if (t->frame() != prev_t->frame_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)) { if (t->frame() != prev_t->frame_at_tempo (t->beats_per_minute(), t->pulse(), _frame_rate)) {
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
return false; return false;
} }
@ -2318,10 +2317,10 @@ TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const fram
continue; continue;
} }
if (t->position_lock_style() == MusicTime) { if (t->position_lock_style() == MusicTime) {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse(), _frame_rate));
t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate)); t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute(), t->frame(), _frame_rate));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate)); t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
} }
@ -2332,7 +2331,7 @@ TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const fram
} }
if (section_prev) { if (section_prev) {
section_prev->set_c_func (section_prev->compute_c_func_frame (section->beats_per_minute() / section_prev->note_type(), frame, _frame_rate)); section_prev->set_c_func (section_prev->compute_c_func_frame (section->beats_per_minute(), frame, _frame_rate));
if (!section->locked_to_meter()) { if (!section->locked_to_meter()) {
section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate)); section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
} }
@ -2386,10 +2385,10 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
continue; continue;
} }
if (t->position_lock_style() == MusicTime) { if (t->position_lock_style() == MusicTime) {
prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute(), t->pulse(), _frame_rate));
t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate)); t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
} else { } else {
prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate)); prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute(), t->frame(), _frame_rate));
if (!t->locked_to_meter()) { if (!t->locked_to_meter()) {
t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate)); t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
} }
@ -2400,7 +2399,7 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
} }
if (section_prev) { if (section_prev) {
section_prev->set_c_func (section_prev->compute_c_func_pulse (section->beats_per_minute() / section_prev->note_type(), pulse, _frame_rate)); section_prev->set_c_func (section_prev->compute_c_func_pulse (section->beats_per_minute(), pulse, _frame_rate));
section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate)); section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
} }
@ -3571,7 +3570,7 @@ TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) con
} }
if (ts_after) { if (ts_after) {
return (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type()); return (60.0 * _frame_rate) / ts_at->tempo_at_frame (frame, _frame_rate);
} }
/* must be treated as constant tempo */ /* must be treated as constant tempo */
return ts_at->frames_per_beat (_frame_rate); return ts_at->frames_per_beat (_frame_rate);
@ -3847,7 +3846,7 @@ TempoMap::dump (const Metrics& metrics, std::ostream& o) const
o << "current : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl; o << "current : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
if (prev_t) { if (prev_t) {
o << "previous : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl; o << "previous : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
o << "calculated : " << prev_t->tempo_at_pulse (t->pulse()) * prev_t->note_type() << " | " << prev_t->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << " | " << prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl; o << "calculated : " << prev_t->tempo_at_pulse (t->pulse()) << " | " << prev_t->pulse_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate) << " | " << prev_t->frame_at_tempo (t->beats_per_minute(), t->pulse(), _frame_rate) << std::endl;
} }
prev_t = t; prev_t = t;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {