mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 04:06:26 +01:00
tempo doc explains that currently Tempo::beats_per_minute means something else.
- Tempo beats_per_minute() is currently implemented as note types per minute. a further patch will change Tempo to reflect this and provide some helpers.
This commit is contained in:
parent
2f593e3af9
commit
e52f90357e
2 changed files with 53 additions and 54 deletions
|
|
@ -50,14 +50,14 @@ class TempoMap;
|
||||||
class LIBARDOUR_API Tempo {
|
class LIBARDOUR_API Tempo {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @param bpm Beats Per Minute
|
* @param npm Note Types per minute
|
||||||
* @param type Note Type (default `4': quarter note)
|
* @param type Note Type (default `4': quarter note)
|
||||||
*/
|
*/
|
||||||
Tempo (double bpm, double type=4.0) // defaulting to quarter note
|
Tempo (double npm, double type=4.0) // defaulting to quarter note
|
||||||
: _beats_per_minute (bpm), _note_type(type) {}
|
: _beats_per_minute (npm), _note_type(type) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
quarter note beats as distinct from a beat derived from meter and pulse.
|
note types per minute.
|
||||||
*/
|
*/
|
||||||
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; }
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ TempoSection::set_type (Type type)
|
||||||
_type = type;
|
_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
|
double
|
||||||
TempoSection::tempo_at_minute (const double& m) const
|
TempoSection::tempo_at_minute (const double& m) const
|
||||||
|
|
@ -241,7 +241,7 @@ TempoSection::tempo_at_minute (const double& m) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns the zero-based minute (relative to session)
|
/** 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.
|
pulse p is only used for constant tempi.
|
||||||
note that the tempo map may have multiple such values.
|
note that the tempo map may have multiple such values.
|
||||||
*/
|
*/
|
||||||
|
|
@ -254,7 +254,8 @@ TempoSection::minute_at_tempo (const double& bpm, const double& p) const
|
||||||
|
|
||||||
return _time_at_tempo (bpm) + minute();
|
return _time_at_tempo (bpm) + minute();
|
||||||
}
|
}
|
||||||
/** returns the tempo in beats per minute at the supplied pulse.
|
|
||||||
|
/** returns the tempo in note types per minute at the supplied pulse.
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
TempoSection::tempo_at_pulse (const double& p) const
|
TempoSection::tempo_at_pulse (const double& p) const
|
||||||
|
|
@ -267,8 +268,8 @@ TempoSection::tempo_at_pulse (const double& p) const
|
||||||
return _tempo_at_pulse (p - pulse());
|
return _tempo_at_pulse (p - pulse());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns the pulse where the tempo in beats per minute occurs given frame f.
|
/** returns the pulse where the tempo in note types per minute occurs given minute m.
|
||||||
frame f is only used for constant tempi.
|
minute m is only used for constant tempi.
|
||||||
note that the session tempo map may have multiple locations where a given tempo occurs.
|
note that the session tempo map may have multiple locations where a given tempo occurs.
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
|
|
@ -382,8 +383,9 @@ https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Te
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
compute this ramp's function constant using the end tempo (in qn beats per minute)
|
compute this ramp's function constant from some tempo-pulse point
|
||||||
and duration (pulses into global start) of some later tempo section.
|
end tempo (in note types per minute)
|
||||||
|
duration (pulses into global start) of some other position.
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse) const
|
TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse) const
|
||||||
|
|
@ -392,7 +394,10 @@ TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pul
|
||||||
return (beats_per_minute() * expm1 (log_tempo_ratio)) / ((end_pulse - pulse()) * _note_type);
|
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
|
double
|
||||||
TempoSection::compute_c_func_minute (const double& end_bpm, const double& end_minute) const
|
TempoSection::compute_c_func_minute (const double& end_bpm, const double& end_minute) const
|
||||||
{
|
{
|
||||||
|
|
@ -413,28 +418,28 @@ TempoSection::c_func (double end_bpm, double end_time) const
|
||||||
return log (end_bpm / beats_per_minute()) / end_time;
|
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
|
double
|
||||||
TempoSection::_tempo_at_time (const double& time) const
|
TempoSection::_tempo_at_time (const double& time) const
|
||||||
{
|
{
|
||||||
return exp (_c_func * time) * beats_per_minute();
|
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
|
double
|
||||||
TempoSection::_time_at_tempo (const double& tempo) const
|
TempoSection::_time_at_tempo (const double& tempo) const
|
||||||
{
|
{
|
||||||
return log (tempo / beats_per_minute()) / _c_func;
|
return log (tempo / beats_per_minute()) / _c_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pulse at tempo in bpm */
|
/* pulse at tempo in note types per minute */
|
||||||
double
|
double
|
||||||
TempoSection::_pulse_at_tempo (const double& tempo) const
|
TempoSection::_pulse_at_tempo (const double& tempo) const
|
||||||
{
|
{
|
||||||
return ((tempo - beats_per_minute()) / _c_func) / _note_type;
|
return ((tempo - beats_per_minute()) / _c_func) / _note_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tempo in bpm at pulse */
|
/* tempo in note types per minute at pulse */
|
||||||
double
|
double
|
||||||
TempoSection::_tempo_at_pulse (const double& pulse) const
|
TempoSection::_tempo_at_pulse (const double& pulse) const
|
||||||
{
|
{
|
||||||
|
|
@ -603,47 +608,38 @@ MeterSection::get_state() const
|
||||||
/*
|
/*
|
||||||
Tempo Map Overview
|
Tempo Map Overview
|
||||||
|
|
||||||
The Shaggs - Things I Wonder
|
Tempo determines the rate of musical pulse determined by its components
|
||||||
https://www.youtube.com/watch?v=9wQK6zMJOoQ
|
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
|
||||||
|
|
||||||
Tempo is the rate of the musical pulse.
|
TempoSection - translates between time, musical pulse and tempo.
|
||||||
Meter divides pulse into measures and beats.
|
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).
|
||||||
|
|
||||||
TempoSection - provides pulse in the form of beats_per_minute() - the number of quarter notes in one minute.
|
MeterSection - translates between BBT, meter-based beat and musical pulse.
|
||||||
Note that 'beats' in Tempo::beats_per_minute() are quarter notes (pulse based). In the rest of tempo map,
|
has a musical location in whole notes (pulses)
|
||||||
'beat' usually refers to accumulated BBT beats (pulse and meter based).
|
has a musical location in meter-based beats
|
||||||
|
has a musical location in BBT time
|
||||||
|
has a time location expressed in minutes.
|
||||||
|
|
||||||
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).
|
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 lock style determines the location type to be kept as a reference when location is recalculated.
|
||||||
|
|
||||||
The first tempo and first meter are special. they must move together, and must be locked to audio.
|
The first tempo and meter are special. they must move together, and are locked to audio.
|
||||||
Audio locked tempos which lie before the first meter are made inactive.
|
Audio locked tempi 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
|
Recomputing the map is the process where the 'missing' location types are calculated.
|
||||||
referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
|
We construct the tempo map by first using the locked location type of each section
|
||||||
sb->beat() - meter->beat() / meter->note_divisor().
|
to determine non-locked location types (pulse or minute position).
|
||||||
Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
|
We then use this map to find the pulse or minute position of each meter (again depending on lock style).
|
||||||
two meters is of course
|
|
||||||
(meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
|
|
||||||
|
|
||||||
Beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
|
Having done this, we can now traverse the Metrics list by pulse or minute
|
||||||
Beat to frame conversion of course requires the use of meter and tempo.
|
to query its relevant meter/tempo.
|
||||||
|
|
||||||
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' 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.
|
|
||||||
|
|
||||||
It is important to keep the _metrics in an order that makes sense.
|
It is important to keep the _metrics in an order that makes sense.
|
||||||
Because ramped MusicTime and AudioTime tempos can interact with each other,
|
Because ramped MusicTime and AudioTime tempos can interact with each other,
|
||||||
|
|
@ -680,11 +676,14 @@ MeterSection::get_state() const
|
||||||
beat_at_frame (frame_at_beat (beat)) != beat due to the time quantization of frame_at_beat().
|
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.
|
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).
|
frames_between_quarter_notes () eliminats this effect when determining time duration
|
||||||
For audio-locked objects, use frame position to calculate beat position.
|
from Beats distance, or instead work in quarter-notes and/or beats and convert to frames last.
|
||||||
|
|
||||||
The above pointless example would then do:
|
The above pointless example could instead do:
|
||||||
beat_at_pulse (pulse_at_beat (beat)) to avoid rounding.
|
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 {
|
struct MetricSectionSorter {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue