Class Metronome
- java.lang.Object
-
- org.deepsymmetry.electro.Metronome
-
- All Implemented Interfaces:
Snapshot
public class Metronome extends Object implements Snapshot
A beat management tool. Tell it what BPM you want, and it will compute beat, bar, and phrase timestamps accordingly. If you only need a single piece of information, you can obtain it directly from the metronome. If you need to work with two or more values, you need to call
getSnapshot()and ask the snapshot for them or you will see inconsistent results, since time will move on between each question you ask the metronome itself.Inspired by Jeff Rose's work in Overtone.
- Author:
- James Elliott
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description voidadjustStart(long ms)Adds a number of milliseconds to the start time of the metronome.static doublebeatsToMilliseconds(long beats, double tempo)Calculate the number of milliseconds taken by the specified number of beats at the specified tempo.doubledistanceFromBar()Determine how far in time the metronome is from its closest bar boundary.doubledistanceFromBeat()Determine how far in time the metronome is from the closest beat.doubledistanceFromPhrase()Determine how far in time the metronome is from its closest phrase boundary.static doubleenhancedPhase(long markerNumber, double markerPhase, double desiredRatio)Helper function to calculate phase with respect to multiples or fractions of a marker (beat, bar, or phrase), given the phase with respect to that marker, the marker number, and the desired ratio.static doubleenhancedPhase(long markerNumber, double markerPhase, long numerator, long denominator)Helper function to calculate phase with respect to multiples or fractions of a marker (beat, bar, or phrase), given the phase with respect to that marker, the marker number, and the desired ratio.static doublefindClosestDelta(double delta)Figures out the least disruptive phase shift that ends up in a target phase.longgetBar()Get the current bar being played.doublegetBarInterval()Get the number of milliseconds a bar lasts given the current configuration and tempo.doublegetBarPhase()Determine the distance traveled into the current bar as a phase number in the range [0.0, 1.0).intgetBarsPerPhrase()Get the number of bars per phrase in the metronome's beat grid.intgetBarWithinPhrase()Return the current bar number relative to the start of the phrase: the phrase starts with bar 1, and the range goes up to the value ofgetBarsPerPhrase().longgetBeat()Get the current beat being played.doublegetBeatInterval()Get the number of milliseconds a beat lasts given the current tempo.doublegetBeatPhase()Determine the distance traveled into the current beat as a phase number in the range [0.0, 1.0).intgetBeatsPerBar()Get the number of beats per bar in the metronome's beat grid.intgetBeatWithinBar()Return the current beat number relative to the start of the bar: the down beat is 1, and the range goes up to the value ofgetBeatsPerBar().intgetBeatWithinPhrase()Return the current beat number relative to the start of the phrase: the phrase starts with beat 1, and the range goes up to the value ofgetBeatsPerBar()timesgetBarsPerPhrase().longgetInstant()Checks when a snapshot was taken; since you are working with a live metronome, always returns the current time.StringgetMarker()Returns the current count of the metronome as "phrase.bar.beat".longgetPhrase()Get the current phrase being played.doublegetPhraseInterval()Get the number of milliseconds a phrase lasts given the current configuration and tempo.doublegetPhrasePhase()Determine the distance traveled into the current phrase as a phase number in the range [0.0, 1.0).SnapshotgetSnapshot()Take a snapshot of the current beat, bar, phrase, and phase state, so coherent calculations about them can be performed with respect to a static point in time.SnapshotgetSnapshot(long instant)Take a snapshot of the beat, bar, phrase, and phase state that the metronome would have at the specified millisecond timestamp, so coherent calculations about them can be performed with respect to that static point in time.longgetStartTime()Returns the time at which this metronome was effectively started (tempo changes will shift this, as will a variety of methods which adjust the timeline).doublegetTempo()Get the tempo at which this metronome is running.longgetTimeOfBar(long bar)Determine the millisecond timestamp at which a particular bar will occur.longgetTimeOfBeat(long beat)Determine the millisecond timestamp at which a particular beat will occur.longgetTimeOfPhrase(long phrase)Determine the millisecond timestamp at which a particular phrase will occur.booleanisDownBeat()Checks whether the current beat is the first beat in its bar.booleanisPhraseStart()Checks whether the current beat is the first beat in its phrase.voidjumpToBar(long bar)Restarts the metronome at the start of the specified bar, keeping the beat phase unchanged in case it is being synchronized to an external source.voidjumpToBeat(long beat)Restarts the metronome at the beginning of the specified beat number.voidjumpToPhrase(long phrase)Restarts the metronome at the start of the specified phrase, keeping the beat phase unchanged in case it is being synchronized to an external source.static longmarkerNumber(long instant, long start, double interval)Helper function to calculate the beat, bar, or phrase number in effect at a given instant (in milliseconds) given a timeline starting point (start, also in milliseconds), and the interval (also in milliseconds) between beats, bars, or phrases.static doublemarkerPhase(long instant, long start, double interval)Helper function to calculate the beat, bar, or phrase phase at a given instant (in milliseconds), given a timeline starting point (start, also in milliseconds), and the interval (also in milliseconds) between beats, bars, or phrases.static doublenormalizePhase(double phase)Ensure that a phase falls in the range [0.0, 1.0).voidsetBarPhase(double phase)Nudge the metronome so that it has reached the specified part of its current bar.voidsetBarsPerPhrase(int barsPerPhrase)Establish a new number of bars per phrase in the metronome's beat grid.voidsetBeatPhase(double phase)Nudge the metronome so that it has reached the specified part of its current beat.voidsetBeatsPerBar(int beatsPerBar)Establish a new number of beats per bar in the metronome's beat grid.voidsetPhrasePhase(double phase)Nudge the metronome so that it has reached the specified part of its current phrase.voidsetTempo(double bpm)Establish a new tempo for the metronome.StringtoString()
-
-
-
Constructor Detail
-
Metronome
public Metronome()
Create a new metronome with default configuration. Its start time is now, its tempo is 120.0 beats per minute, counting four beats per bar, and eight bars per phrase.
-
Metronome
public Metronome(Metronome template)
Create a metronome which is a copy of another metronome, that is sharing the same start time, tempo, beats per bar, and bars per phrase. Once created, the metronomes are independent, so changes to one will not affect the other.- Parameters:
template- the metronome whose configuration is to be copied
-
-
Method Detail
-
getStartTime
public long getStartTime()
Returns the time at which this metronome was effectively started (tempo changes will shift this, as will a variety of methods which adjust the timeline).- Specified by:
getStartTimein interfaceSnapshot- Returns:
- the millisecond timestamp at which the beat grid originates.
-
adjustStart
public void adjustStart(long ms)
Adds a number of milliseconds to the start time of the metronome. Useful to nudge it back into synchronization with an external source.- Parameters:
ms- the number of milliseconds to add to the start time
-
getTempo
public double getTempo()
Get the tempo at which this metronome is running.
-
setTempo
public void setTempo(double bpm)
Establish a new tempo for the metronome. The start time will be adjusted so that the current beat and phase are unaffected by the tempo change.- Parameters:
bpm- the number of beats per minute at which the metronome should now run
-
getBeatsPerBar
public int getBeatsPerBar()
Get the number of beats per bar in the metronome's beat grid. The default value is four.- Specified by:
getBeatsPerBarin interfaceSnapshot- Returns:
- the number of beats per bar being counted
-
setBeatsPerBar
public void setBeatsPerBar(int beatsPerBar)
Establish a new number of beats per bar in the metronome's beat grid.- Parameters:
beatsPerBar- a positive number of beats per bar being counted- Throws:
IllegalArgumentException- ifbeatsPerBaris not greater than zero
-
getBarsPerPhrase
public int getBarsPerPhrase()
Get the number of bars per phrase in the metronome's beat grid.- Specified by:
getBarsPerPhrasein interfaceSnapshot- Returns:
- the number of bars per phrase being counted
-
setBarsPerPhrase
public void setBarsPerPhrase(int barsPerPhrase)
Establish a new number of bars per phrase in the metronome's beat grid.- Parameters:
barsPerPhrase- a positive number of bars per phrase being counted- Throws:
IllegalArgumentException- ifbarsPerPhraseis not greater than zero
-
beatsToMilliseconds
public static double beatsToMilliseconds(long beats, double tempo)Calculate the number of milliseconds taken by the specified number of beats at the specified tempo.- Parameters:
beats- the number of beats to timetempo- the number of that play in a minute- Returns:
- the number of milliseconds that would pass while that many beats play at that tempo
-
markerNumber
public static long markerNumber(long instant, long start, double interval)Helper function to calculate the beat, bar, or phrase number in effect at a given instant (in milliseconds) given a timeline starting point (start, also in milliseconds), and the interval (also in milliseconds) between beats, bars, or phrases.- Parameters:
instant- the time (in milliseconds) for which a marker number is desiredstart- the time (in milliseconds) at which the metronome started countinginterval- the time (in milliseconds) between markers- Returns:
- the marker number currently in effect for the metronome at the specified instant
-
markerPhase
public static double markerPhase(long instant, long start, double interval)Helper function to calculate the beat, bar, or phrase phase at a given instant (in milliseconds), given a timeline starting point (start, also in milliseconds), and the interval (also in milliseconds) between beats, bars, or phrases. A marker phase starts at 0.0 at the beginning of the beat, bar, or phrase, rises linearly during the beat, bar, or phrase, but never reaches 1.0, because that is the start of the next beat, bar, or phrase.- Parameters:
instant- the time (in milliseconds) for which a marker phase is desiredstart- the time (in milliseconds) at which the metronome started countinginterval- the time (in milliseconds) between markers- Returns:
- the phase in effect for the specified marker at the specified instant, in the range [0.0, 1.0)
-
enhancedPhase
public static double enhancedPhase(long markerNumber, double markerPhase, double desiredRatio)Helper function to calculate phase with respect to multiples or fractions of a marker (beat, bar, or phrase), given the phase with respect to that marker, the marker number, and the desired ratio. A
desiredRatioof1.0returns the phase unchanged;0.5(1/2) oscillates twice as fast,0.75(3/4) oscillates 4 times every 3 markers...See the Ratios illustration in the Afterglow documentation for more details with graphs.
Only positive values were considered for the ratio when writing this algorithm, the results you'll get if you pass in zero or a negative value, are not likely meaningful.
- Parameters:
markerNumber- the current marker number being considered, as returned bymarkerNumber(long, long, double)markerPhase- the current phase with respect to the marker, as returned bymarkerPhase(long, long, double)desiredRatio- the ratio by which to oscillate the phase- Returns:
- the oscillated phase
- Since:
- 0.1.1
- See Also:
enhancedPhase(long, double, long, long)
-
enhancedPhase
public static double enhancedPhase(long markerNumber, double markerPhase, long numerator, long denominator)Helper function to calculate phase with respect to multiples or fractions of a marker (beat, bar, or phrase), given the phase with respect to that marker, the marker number, and the desired ratio. A ration of 1/1 returns the phase unchanged; 1/2 oscillates twice as fast, 3/4 oscillates 4 times every 3 markers...
See the Ratios illustration in the Afterglow documentation for more details with graphs.
Only positive values were considered for the numerator and denominator when writing this algorithm, the results you'll get if you pass in zero or a negative value, are not likely meaningful.
- Parameters:
markerNumber- the current marker number being considered, as returned bymarkerNumber(long, long, double)markerPhase- the current phase with respect to the marker, as returned bymarkerPhase(long, long, double)numerator- over how many markers should an oscillation cycle spandenominator- how many oscillations should occur in that span- Returns:
- the oscillated phase
- Since:
- 0.1.1
- See Also:
enhancedPhase(long, double, double)
-
normalizePhase
public static double normalizePhase(double phase)
Ensure that a phase falls in the range [0.0, 1.0). Values outside the range will have their non-fractional part discarded.- Parameters:
phase- a phase value that may require normalization to within the unit range- Returns:
- the normalized phase
-
getBeatInterval
public double getBeatInterval()
Get the number of milliseconds a beat lasts given the current tempo.- Specified by:
getBeatIntervalin interfaceSnapshot- Returns:
- the duration of a beat
-
getBarInterval
public double getBarInterval()
Get the number of milliseconds a bar lasts given the current configuration and tempo.- Specified by:
getBarIntervalin interfaceSnapshot- Returns:
- the duration of a bar
-
getPhraseInterval
public double getPhraseInterval()
Get the number of milliseconds a phrase lasts given the current configuration and tempo.- Specified by:
getPhraseIntervalin interfaceSnapshot- Returns:
- the duration of a phrase
-
getBeat
public long getBeat()
Get the current beat being played.
-
jumpToBeat
public void jumpToBeat(long beat)
Restarts the metronome at the beginning of the specified beat number.- Parameters:
beat- the beat to which the metronome should jump; the first beat is beat 1
-
getTimeOfBeat
public long getTimeOfBeat(long beat)
Determine the millisecond timestamp at which a particular beat will occur.- Specified by:
getTimeOfBeatin interfaceSnapshot- Parameters:
beat- the number of the beat whose start time is desired- Returns:
- the time at which the specified beat begins, to the nearest millisecond
-
getBeatPhase
public double getBeatPhase()
Determine the distance traveled into the current beat as a phase number in the range [0.0, 1.0).- Specified by:
getBeatPhasein interfaceSnapshot- Returns:
- the current beat phase
-
findClosestDelta
public static double findClosestDelta(double delta)
Figures out the least disruptive phase shift that ends up in a target phase.- Parameters:
delta- the amount to be added to our current phase to achieve a desired phase- Returns:
- an amount that will yield the same phase while changing our position the least
-
setBeatPhase
public void setBeatPhase(double phase)
Nudge the metronome so that it has reached the specified part of its current beat. If the value supplied is outside the range of a beat phase (less than zero or greater than or equal to one), it will be normalized to fit into that range by ignoring the non-fractional part.- Parameters:
phase- the desired beat phase, in the range [0.0, 1.0).
-
getBar
public long getBar()
Get the current bar being played.
-
jumpToBar
public void jumpToBar(long bar)
Restarts the metronome at the start of the specified bar, keeping the beat phase unchanged in case it is being synchronized to an external source.- Parameters:
bar- the bar to which the metronome should jump; the first bar is bar 1
-
getTimeOfBar
public long getTimeOfBar(long bar)
Determine the millisecond timestamp at which a particular bar will occur.- Specified by:
getTimeOfBarin interfaceSnapshot- Parameters:
bar- the number of the bar whose start time is desired- Returns:
- the time at which the specified bar begins, rounded to the nearest millisecond
-
getBarPhase
public double getBarPhase()
Determine the distance traveled into the current bar as a phase number in the range [0.0, 1.0).- Specified by:
getBarPhasein interfaceSnapshot- Returns:
- the current bar phase
-
setBarPhase
public void setBarPhase(double phase)
Nudge the metronome so that it has reached the specified part of its current bar. If the value supplied is outside the range of a bar phase (less than zero or greater than or equal to one), it will be normalized to fit into that range by ignoring the non-fractional part.- Parameters:
phase- the desired bar phase, in the range [0.0, 1.0).
-
getPhrase
public long getPhrase()
Get the current phrase being played.
-
jumpToPhrase
public void jumpToPhrase(long phrase)
Restarts the metronome at the start of the specified phrase, keeping the beat phase unchanged in case it is being synchronized to an external source.- Parameters:
phrase- the phrase to which the metronome should jump; the first phrase is phrase 1
-
getTimeOfPhrase
public long getTimeOfPhrase(long phrase)
Determine the millisecond timestamp at which a particular phrase will occur.- Specified by:
getTimeOfPhrasein interfaceSnapshot- Parameters:
phrase- the number of the phrase whose start time is desired- Returns:
- the time at which the specified phrase begins, rounded to the nearest millisecond
-
getPhrasePhase
public double getPhrasePhase()
Determine the distance traveled into the current phrase as a phase number in the range [0.0, 1.0).- Specified by:
getPhrasePhasein interfaceSnapshot- Returns:
- the current phrase phase
-
setPhrasePhase
public void setPhrasePhase(double phase)
Nudge the metronome so that it has reached the specified part of its current phrase. If the value supplied is outside the range of a phrase phase (less than zero or greater than or equal to one), it will be normalized to fit into that range by ignoring the non-fractional part.- Parameters:
phase- the desired phrase phase, in the range [0.0, 1.0).
-
getSnapshot
public Snapshot getSnapshot()
Take a snapshot of the current beat, bar, phrase, and phase state, so coherent calculations about them can be performed with respect to a static point in time.- Returns:
- a representation of the detailed metronome state at the current moment
-
getSnapshot
public Snapshot getSnapshot(long instant)
Take a snapshot of the beat, bar, phrase, and phase state that the metronome would have at the specified millisecond timestamp, so coherent calculations about them can be performed with respect to that static point in time.- Parameters:
instant- the point in time which this snapshot should capture- Returns:
- a representation of the detailed metronome state at the specified moment
-
getMarker
public String getMarker()
Returns the current count of the metronome as "phrase.bar.beat".
-
getInstant
public long getInstant()
Checks when a snapshot was taken; since you are working with a live metronome, always returns the current time. If you are doing computations around this, you probably want to callgetSnapshot()and work with that instead.- Specified by:
getInstantin interfaceSnapshot- Returns:
- the current system time in milliseconds
-
getBeatWithinBar
public int getBeatWithinBar()
Return the current beat number relative to the start of the bar: the down beat is 1, and the range goes up to the value ofgetBeatsPerBar().- Specified by:
getBeatWithinBarin interfaceSnapshot- Returns:
- the beat number within the current bar being counted
-
isDownBeat
public boolean isDownBeat()
Checks whether the current beat is the first beat in its bar.- Specified by:
isDownBeatin interfaceSnapshot- Returns:
truewe are currently in the first beat of a bar
-
getBeatWithinPhrase
public int getBeatWithinPhrase()
Return the current beat number relative to the start of the phrase: the phrase starts with beat 1, and the range goes up to the value ofgetBeatsPerBar()timesgetBarsPerPhrase().- Specified by:
getBeatWithinPhrasein interfaceSnapshot- Returns:
- the beat number within the current phrase being counted
-
isPhraseStart
public boolean isPhraseStart()
Checks whether the current beat is the first beat in its phrase.- Specified by:
isPhraseStartin interfaceSnapshot- Returns:
trueif we are currently in the first beat of a phrase
-
getBarWithinPhrase
public int getBarWithinPhrase()
Return the current bar number relative to the start of the phrase: the phrase starts with bar 1, and the range goes up to the value ofgetBarsPerPhrase().- Specified by:
getBarWithinPhrasein interfaceSnapshot- Returns:
- the bar number within the current phrase being counted
-
distanceFromBeat
public double distanceFromBeat()
Determine how far in time the metronome is from the closest beat. The result will be positive if the beat has already occurred, and negative if it is coming up.- Specified by:
distanceFromBeatin interfaceSnapshot- Returns:
- the distance in milliseconds from the closest beat on the metronome's timeline
-
distanceFromBar
public double distanceFromBar()
Determine how far in time the metronome is from its closest bar boundary. The result will be positive if the bar has already started, and negative if it is coming up.- Specified by:
distanceFromBarin interfaceSnapshot- Returns:
- the distance in milliseconds from the closest bar boundary on the metronome's timeline
-
distanceFromPhrase
public double distanceFromPhrase()
Determine how far in time the metronome is from its closest phrase boundary. The result will be positive if the phrase has already started, and negative if it is coming up.- Specified by:
distanceFromPhrasein interfaceSnapshot- Returns:
- the distance in milliseconds from the closest phrase boundary on the metronome's timeline
-
-