_type = type;
}
-/** returns the tempo in beats per minute at the zero-based (relative to session) minute.
+/** returns the tempo on note types per minute at the zero-based (relative to session) minute.
*/
double
TempoSection::tempo_at_minute (const double& m) const
}
/** returns the zero-based minute (relative to session)
- where the tempo in beats per minute occurs in this section.
+ where the tempo in note types per minute occurs in this section.
pulse p is only used for constant tempi.
note that the tempo map may have multiple such values.
*/
return _time_at_tempo (bpm) + minute();
}
-/** returns the tempo in beats per minute at the zero-based (relative to session) pulse.
+
+/** returns the tempo in note types per minute at the supplied pulse.
*/
double
TempoSection::tempo_at_pulse (const double& p) const
return _tempo_at_pulse (p - pulse());
}
-/** 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.
+/** returns the pulse where the tempo in note types per minute occurs given minute m.
+ minute m is only used for constant tempi.
+ note that the session tempo map may have multiple locations where a given tempo occurs.
*/
double
TempoSection::pulse_at_tempo (const double& bpm, const double& m) const
return _pulse_at_tempo (bpm) + pulse();
}
-/** returns the zero-based pulse (relative to session origin)
- where the zero-based frame (relative to session)
- lies.
+/** returns the pulse at the supplied session-relative minute.
*/
-double
-TempoSection::pulse_at_frame (const framepos_t& f) const
-{
- return pulse_at_minute (minute_at_frame (f));
-}
-
double
TempoSection::pulse_at_minute (const double& m) const
{
return _pulse_at_time (m - minute()) + pulse();
}
-/** returns the zero-based frame (relative to session start frame)
- where the zero-based pulse (relative to session start)
- falls.
+/** returns the minute (relative to session start) at the supplied pulse.
*/
-
-framepos_t
-TempoSection::frame_at_pulse (const double& p) const
-{
- return frame_at_minute (minute_at_pulse (p));
-}
-
double
TempoSection::minute_at_pulse (const double& p) const
{
*/
/*
- 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.
+ compute this ramp's function constant from some tempo-pulse point
+ end tempo (in note types per minute)
+ duration (pulses into global start) of some other position.
*/
double
TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse) const
return (beats_per_minute() * expm1 (log_tempo_ratio)) / ((end_pulse - pulse()) * _note_type);
}
-/* compute the function constant from some later tempo section, given tempo (quarter notes/min.) and distance (in frames) from session origin */
+/* compute the function constant from some tempo-time point.
+ tempo (note types/min.)
+ distance (in minutes) from session origin
+*/
double
TempoSection::compute_c_func_minute (const double& end_bpm, const double& end_minute) const
{
return log (end_bpm / beats_per_minute()) / end_time;
}
-/* tempo in bpm at time in minutes */
+/* tempo in note types per minute at time in minutes */
double
TempoSection::_tempo_at_time (const double& time) const
{
return exp (_c_func * time) * beats_per_minute();
}
-/* time in minutes at tempo in bpm */
+/* time in minutes at tempo in note types per minute */
double
TempoSection::_time_at_tempo (const double& tempo) const
{
return log (tempo / beats_per_minute()) / _c_func;
}
-/* pulse at tempo in bpm */
+/* pulse at tempo in note types per minute */
double
TempoSection::_pulse_at_tempo (const double& tempo) const
{
return ((tempo - beats_per_minute()) / _c_func) / _note_type;
}
-/* tempo in bpm at pulse */
+/* tempo in note types per minute at pulse */
double
TempoSection::_tempo_at_pulse (const double& pulse) const
{
/*
Tempo Map Overview
- The Shaggs - Things I Wonder
- https://www.youtube.com/watch?v=9wQK6zMJOoQ
-
- Tempo is the rate of the musical pulse.
- Meter divides pulse into measures and beats.
+ Tempo determines the rate of musical pulse determined by its components
+ note types per minute - the rate per minute of the whole note divisor _note_type
+ note type - the division of whole notes (pulses) which occur at the rate of note types per minute.
+ Meter divides the musical pulse into measures and beats according to its components
+ divisions_per_bar
+ note_divisor
+
+ TempoSection - translates between time, musical pulse and tempo.
+ has a musical location in whole notes (pulses).
+ has a time location in minutes.
+ Note that 'beats' in Tempo::beats_per_minute() are in fact note types per minute.
+ (In the rest of tempo map,'beat' usually refers to accumulated BBT beats (pulse and meter based).
+
+ MeterSection - translates between BBT, meter-based beat and musical pulse.
+ has a musical location in whole notes (pulses)
+ has a musical location in meter-based beats
+ has a musical location in BBT time
+ has a time location expressed in minutes.
- TempoSection - provides pulse in the form of beats_per_minute() - the number of quarter notes in one minute.
- Note that 'beats' in Tempo::beats_per_minute() are quarter notes (pulse based). In the rest of tempo map,
- 'beat' usually refers to accumulated BBT beats (pulse and meter based).
-
- MeterSecion - divides pulse into measures (via divisions_per_bar) and beats (via note_divisor).
-
- Both tempo and meter have a pulse position and a frame position.
- Meters also have a beat position, which is always 0.0 for the first one.
TempoSection and MeterSection may be locked to either audio or music (position lock style).
- The lock style determines the 'true' position of the section wich is used to calculate the other postion parameters of the section.
-
- The first tempo and first meter are special. they must move together, and must be locked to audio.
- Audio locked tempos which lie before the first meter are made inactive.
- They will be re-activated if the first meter is again placed before them.
-
- With tempo sections potentially being ramped, meters provide a way of mapping beats to whole pulses without
- referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
- sb->beat() - meter->beat() / meter->note_divisor().
- Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
- two meters is of course
- (meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
+ The lock style determines the location type to be kept as a reference when location is recalculated.
- Beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
- Beat to frame conversion of course requires the use of meter and tempo.
+ The first tempo and meter are special. they must move together, and are locked to audio.
+ Audio locked tempi which lie before the first meter are made inactive.
- Remembering that ramped tempo sections interact, it is important to avoid referring to any other tempos when moving tempo sections,
- Here, beats (meters) are used to determine the new pulse (see predict_tempo_position())
+ Recomputing the map is the process where the 'missing' location types are calculated.
+ We construct the tempo map by first using the locked location type of each section
+ to determine non-locked location types (pulse or minute position).
+ We then use this map to find the pulse or minute position of each meter (again depending on lock style).
- Recomputing the map is the process where the 'missing' position
- (tempo pulse or meter pulse & beat in the case of AudioTime, frame for MusicTime) is calculated.
- We construct the tempo map by first using the frame or pulse position (depending on position lock style) of each tempo.
- We then use this tempo map (really just the tempos) to find the pulse or frame position of each meter (again depending on lock style).
-
- Having done this, we can now find any musical duration by selecting the tempo and meter covering the position (or tempo) in question
- and querying its appropriate meter/tempo.
+ Having done this, we can now traverse the Metrics list by pulse or minute
+ to query its relevant meter/tempo.
It is important to keep the _metrics in an order that makes sense.
Because ramped MusicTime and AudioTime tempos can interact with each other,
beat_at_frame (frame_at_beat (beat)) != beat due to the time quantization of frame_at_beat().
Doing the second one will result in a beat distance error of up to 0.5 audio samples.
- So instead work in pulses and/or beats and only use beat position to caclulate frame position (e.g. after tempo change).
- For audio-locked objects, use frame position to calculate beat position.
+ frames_between_quarter_notes () eliminats this effect when determining time duration
+ from Beats distance, or instead work in quarter-notes and/or beats and convert to frames last.
- The above pointless example would then do:
- beat_at_pulse (pulse_at_beat (beat)) to avoid rounding.
+ The above pointless example could instead do:
+ beat_at_quarter_note (quarter_note_at_beat (beat)) to avoid rounding.
+
+ The Shaggs - Things I Wonder
+ https://www.youtube.com/watch?v=9wQK6zMJOoQ
*/
struct MetricSectionSorter {
return prev_t->minute_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse());
}
-/** Returns a Tempo corresponding to the supplied frame.
+/** Returns a Tempo corresponding to the supplied frame position.
* @param frame The audio frame.
* @return a Tempo according to the tempo map at the supplied frame.
*
}
}
- return prev_t->minute();
+ return prev_t->pulse();
}
-/** Returns a Tempo corresponding to the supplied BBT (meter-based) beat.
- * @param beat The BBT (meter-based) beat.
+/** Returns a Tempo corresponding to the supplied position in quarter-note beats.
+ * @param qn the position in quarter note beats.
+ * @return the Tempo at the supplied quarter-note.
*/
Tempo
-TempoMap::tempo_at_beat (const double& beat) const
+TempoMap::tempo_at_quarter_note (const double& qn) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
- const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
- return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()), prev_t->note_type());
+ return tempo_at_pulse_locked (_metrics, qn / 4.0);
}
-/** Returns a BBT (meter-based) beat corresponding to the supplied Tempo.
- * @param tempo The tempo.
+/** Returns the position in quarter-note beats corresponding to the supplied Tempo.
+ * @param tempo the tempo.
+ * @return the position in quarter-note beats where the map bpm
+ * is equal to that of the Tempo. currently ignores note_type.
*/
double
-TempoMap::beat_at_tempo (const Tempo& tempo) const
+TempoMap::quarter_note_at_tempo (const Tempo& tempo) const
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- const double pulse = pulse_at_tempo_locked (_metrics, tempo);
- return beat_at_pulse_locked (_metrics, pulse);
+ return pulse_at_tempo_locked (_metrics, tempo) * 4.0;;
}
+
/** Returns the whole-note pulse corresponding to the supplied BBT (meter-based) beat.
+ * @param metrics the list of metric sections used to calculate the pulse.
* @param beat The BBT (meter-based) beat.
+ * @return the whole-note pulse at the supplied BBT (meter-based) beat.
*
* a pulse or whole note is the base musical position of a MetricSection.
* it is equivalent to four quarter notes.
*
*/
-double
-TempoMap::pulse_at_beat (const double& beat) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return pulse_at_beat_locked (_metrics, beat);
-}
-
double
TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
{
}
/** Returns the BBT (meter-based) beat corresponding to the supplied whole-note pulse .
+ * @param metrics the list of metric sections used to calculate the beat.
* @param pulse the whole-note pulse.
+ * @return the meter-based beat at the supplied whole-note pulse.
*
* a pulse or whole note is the base musical position of a MetricSection.
* it is equivalent to four quarter notes.
*/
-double
-TempoMap::beat_at_pulse (const double& pulse) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return beat_at_pulse_locked (_metrics, pulse);
-}
-
double
TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
{
return ret;
}
-double
-TempoMap::pulse_at_frame (const framepos_t& frame) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
- return pulse_at_minute_locked (_metrics, minute_at_frame (frame));
-}
-
/* tempo section based */
double
TempoMap::pulse_at_minute_locked (const Metrics& metrics, const double& minute) const
return pulses_in_section + prev_t->pulse();
}
-framepos_t
-TempoMap::frame_at_pulse (const double& pulse) const
-{
- Glib::Threads::RWLock::ReaderLock lm (lock);
-
- return frame_at_minute (minute_at_pulse_locked (_metrics, pulse));
-}
-
/* tempo section based */
double
TempoMap::minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const
/** Returns the BBT (meter-based) beat corresponding to the supplied BBT time.
* @param bbt The BBT time (meter-based).
+ * @return bbt The BBT beat (meter-based) at the supplied BBT time.
*
*/
double
/** Returns the BBT time corresponding to the supplied BBT (meter-based) beat.
* @param beat The BBT (meter-based) beat.
+ * @return The BBT time (meter-based) at the supplied meter-based beat.
*
*/
Timecode::BBT_Time
return ret;
}
-/** Returns the whole-note pulse corresponding to the supplied BBT time (meter-based).
+/** Returns the quarter-note beat corresponding to the supplied BBT time (meter-based).
* @param bbt The BBT time (meter-based).
+ * @return the quarter note beat at the supplied BBT time
+ *
+ * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
*
- * a pulse or whole note is the basic musical position of a MetricSection.
- * it is equivalent to four quarter notes.
* while the input uses meter, the output does not.
*/
double
-TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
+TempoMap::quarter_note_at_bbt (const Timecode::BBT_Time& bbt)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return pulse_at_bbt_locked (_metrics, bbt);
+ return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
}
double
-TempoMap::pulse_at_bbt_rt (const Timecode::BBT_Time& bbt)
+TempoMap::quarter_note_at_bbt_rt (const Timecode::BBT_Time& bbt)
{
- Glib::Threads::RWLock::ReaderLock lm (lock);
+ Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
if (!lm.locked()) {
- throw std::logic_error ("TempoMap::pulse_at_bbt_rt() could not lock tempo map");
+ throw std::logic_error ("TempoMap::quarter_note_at_bbt_rt() could not lock tempo map");
}
- return pulse_at_bbt_locked (_metrics, bbt);
+ return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
}
double
return ret;
}
-/** Returns the BBT time (meter-based) corresponding to the supplied whole-note pulse.
- * @param pulse The whole-note pulse.
+
+/** Returns the BBT time corresponding to the supplied quarter-note beat.
+ * @param qn the quarter-note beat.
+ * @return The BBT time (meter-based) at the supplied meter-based beat.
+ *
+ * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
*
- * a pulse or whole note is the basic musical position of a MetricSection.
- * it is equivalent to four quarter notes.
- * while the input uses meter, the output does not.
*/
Timecode::BBT_Time
-TempoMap::bbt_at_pulse (const double& pulse)
+TempoMap::bbt_at_quarter_note (const double& qn)
{
Glib::Threads::RWLock::ReaderLock lm (lock);
- return bbt_at_pulse_locked (_metrics, pulse);
+ return bbt_at_pulse_locked (_metrics, qn / 4.0);
}
+/** Returns the BBT time (meter-based) corresponding to the supplied whole-note pulse position.
+ * @param metrics The list of metric sections used to determine the result.
+ * @param pulse The whole-note pulse.
+ * @return The BBT time at the supplied whole-note pulse.
+ *
+ * a pulse or whole note is the basic musical position of a MetricSection.
+ * it is equivalent to four quarter notes.
+ * while the output uses meter, the input does not.
+ */
Timecode::BBT_Time
TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
{
/** Returns the BBT time corresponding to the supplied frame position.
* @param frame the position in audio samples.
+ * @return the BBT time at the frame position .
*
*/
BBT_Time
return ret;
}
-/** Returns the frame corresponding to the supplied BBT time.
+/** Returns the frame position corresponding to the supplied BBT time.
* @param bbt the position in BBT time.
+ * @return the frame position at bbt.
*
*/
framepos_t
/**
* Returns the quarter-note beat position corresponding to the supplied frame.
*
- * @param frame The distance in frames relative to session 0 whose quarter note distance you would like.
+ * @param frame the position in frames.
* @return The quarter-note position of the supplied frame. Ignores meter.
*
- * Plugin APIs don't count ticks in the same way PROGRAM_NAME does.
- * We use ticks per beat whereas the rest of the world uses ticks per quarter note.
- * This is more or less the VST's ppqPos (a scalar you use to obtain tick position
- * in whatever ppqn you're using).
- *
*/
double
TempoMap::quarter_note_at_frame (const framepos_t frame)
}
/**
- * Returns the frame corresponding to the supplied quarter-note beat position.
+ * Returns the frame position corresponding to the supplied quarter-note beat.
*
- * @param quarter_note The quarter-note relative to session 0 whose frame position you would like.
- * @return The frame position of the supplied quarter-note. Ignores meter.
+ * @param quarter_note the quarter-note position.
+ * @return the frame position of the supplied quarter-note. Ignores meter.
*
*
*/
/** Returns the quarter-note beats corresponding to the supplied BBT (meter-based) beat.
* @param beat The BBT (meter-based) beat.
+ * @return The quarter-note position of the supplied BBT (meter-based) beat.
*
- * a quarter-note is the musical unit of Evoral::Beats.
+ * a quarter-note may be compared with and assigned to Evoral::Beats.
*
*/
double
/** Returns the BBT (meter-based) beat position corresponding to the supplied quarter-note beats.
* @param quarter_note The position in quarter-note beats.
+ * @return the BBT (meter-based) beat position of the supplied quarter-note beats.
*
* a quarter-note is the musical unit of Evoral::Beats.
*
return beat_at_pulse_locked (metrics, quarter_note / 4.0);
}
-/** Returns the distance in frames between two supplied quarter-note beats.
+/** Returns the duration in frames between two supplied quarter-note beat positions.
* @param start the first position in quarter-note beats.
* @param end the end position in quarter-note beats.
+ * @return the frame distance ober the quarter-note beats duration.
*
* use this rather than e.g.
* frame_at-quarter_note (end_beats) - frame_at_quarter_note (start_beats).
}
void
-TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
+TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame)
{
/*
Ts (future prev_t) Tnext
| |
| [drag^] |
|----------|----------
- e_f pulse(frame)
+ e_f qn_beats(frame)
*/
Metrics future_map;
const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
- const double start_pulse = prev_t->pulse_at_frame (frame);
- const double end_pulse = prev_t->pulse_at_frame (end_frame);
+ const double start_pulse = prev_t->pulse_at_minute (minute_at_frame (frame));
+ const double end_pulse = prev_t->pulse_at_minute (minute_at_frame (end_frame));
double new_bpm;
double frame_ratio = 1.0;
double pulse_ratio = 1.0;
- const double pulse_pos = prev_t->frame_at_pulse (pulse);
+ const double pulse_pos = frame;
if (prev_to_prev_t) {
if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
/** Returns the exact bbt-based beat corresponding to the bar, beat or quarter note subdivision nearest to
* the supplied frame, possibly returning a negative value.
+ *
* @param frame The session frame position.
* @param sub_num The subdivision to use when rounding the beat.
* A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
* 0 indicates that the returned beat should not be rounded (equivalent to quarter_note_at_frame()).
* @return The beat position of the supplied frame.
*
+ * when working to a musical grid, the use of sub_nom indicates that
+ * the position should be interpreted musically.
+ *
+ * it effectively snaps to meter bars, meter beats or quarter note divisions
+ * (as per current gui convention) and returns a musical position independent of frame rate.
+ *
* If the supplied frame lies before the first meter, the return will be negative,
* in which case the returned beat uses the first meter (for BBT subdivisions) and
* the continuation of the tempo curve (backwards).
*
- * This function uses both tempo and meter.
+ * This function is sensitive to tempo and meter.
*/
double
TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
/** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
* the supplied frame, possibly returning a negative value.
- * Supplying a frame position with a non-zero sub_num is equivalent to supplying
- * a quarter-note musical position without frame rounding (see below)
*
* @param frame The session frame position.
* @param sub_num The subdivision to use when rounding the quarter note.
* 0 indicates that the returned quarter note should not be rounded (equivalent to quarter_note_at_frame()).
* @return The quarter note position of the supplied frame.
*
+ * When working to a musical grid, the use of sub_nom indicates that
+ * the frame position should be interpreted musically.
+ *
+ * it effectively snaps to meter bars, meter beats or quarter note divisions
+ * (as per current gui convention) and returns a musical position independent of frame rate.
+ *
* If the supplied frame lies before the first meter, the return will be negative,
* in which case the returned quarter note uses the first meter (for BBT subdivisions) and
* the continuation of the tempo curve (backwards).
*
- * This function uses both tempo and meter.
+ * This function is tempo-sensitive.
*/
double
TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)