Class 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
    • Constructor Summary

      Constructors 
      Constructor Description
      Metronome()
      Create a new metronome with default configuration.
      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.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void adjustStart​(long ms)
      Adds a number of milliseconds to the start time of the metronome.
      static double beatsToMilliseconds​(long beats, double tempo)
      Calculate the number of milliseconds taken by the specified number of beats at the specified tempo.
      double distanceFromBar()
      Determine how far in time the metronome is from its closest bar boundary.
      double distanceFromBeat()
      Determine how far in time the metronome is from the closest beat.
      double distanceFromPhrase()
      Determine how far in time the metronome is from its closest phrase boundary.
      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.
      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.
      static double findClosestDelta​(double delta)
      Figures out the least disruptive phase shift that ends up in a target phase.
      long getBar()
      Get the current bar being played.
      double getBarInterval()
      Get the number of milliseconds a bar lasts given the current configuration and tempo.
      double getBarPhase()
      Determine the distance traveled into the current bar as a phase number in the range [0.0, 1.0).
      int getBarsPerPhrase()
      Get the number of bars per phrase in the metronome's beat grid.
      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 of getBarsPerPhrase().
      long getBeat()
      Get the current beat being played.
      double getBeatInterval()
      Get the number of milliseconds a beat lasts given the current tempo.
      double getBeatPhase()
      Determine the distance traveled into the current beat as a phase number in the range [0.0, 1.0).
      int getBeatsPerBar()
      Get the number of beats per bar in the metronome's beat grid.
      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 of getBeatsPerBar().
      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 of getBeatsPerBar() times getBarsPerPhrase().
      long getInstant()
      Checks when a snapshot was taken; since you are working with a live metronome, always returns the current time.
      String getMarker()
      Returns the current count of the metronome as "phrase.bar.beat".
      long getPhrase()
      Get the current phrase being played.
      double getPhraseInterval()
      Get the number of milliseconds a phrase lasts given the current configuration and tempo.
      double getPhrasePhase()
      Determine the distance traveled into the current phrase as a phase number in the range [0.0, 1.0).
      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.
      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.
      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).
      double getTempo()
      Get the tempo at which this metronome is running.
      long getTimeOfBar​(long bar)
      Determine the millisecond timestamp at which a particular bar will occur.
      long getTimeOfBeat​(long beat)
      Determine the millisecond timestamp at which a particular beat will occur.
      long getTimeOfPhrase​(long phrase)
      Determine the millisecond timestamp at which a particular phrase will occur.
      boolean isDownBeat()
      Checks whether the current beat is the first beat in its bar.
      boolean isPhraseStart()
      Checks whether the current beat is the first beat in its phrase.
      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.
      void jumpToBeat​(long beat)
      Restarts the metronome at the beginning of the specified beat number.
      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.
      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.
      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.
      static double normalizePhase​(double phase)
      Ensure that a phase falls in the range [0.0, 1.0).
      void setBarPhase​(double phase)
      Nudge the metronome so that it has reached the specified part of its current bar.
      void setBarsPerPhrase​(int barsPerPhrase)
      Establish a new number of bars per phrase in the metronome's beat grid.
      void setBeatPhase​(double phase)
      Nudge the metronome so that it has reached the specified part of its current beat.
      void setBeatsPerBar​(int beatsPerBar)
      Establish a new number of beats per bar in the metronome's beat grid.
      void setPhrasePhase​(double phase)
      Nudge the metronome so that it has reached the specified part of its current phrase.
      void setTempo​(double bpm)
      Establish a new tempo for the metronome.
      String toString()  
    • 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:
        getStartTime in interface Snapshot
        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.
        Specified by:
        getTempo in interface Snapshot
        Returns:
        the number of beats per minute being counted
      • 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:
        getBeatsPerBar in interface Snapshot
        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 - if beatsPerBar is not greater than zero
      • getBarsPerPhrase

        public int getBarsPerPhrase()
        Get the number of bars per phrase in the metronome's beat grid.
        Specified by:
        getBarsPerPhrase in interface Snapshot
        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 - if barsPerPhrase is 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 time
        tempo - 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 desired
        start - the time (in milliseconds) at which the metronome started counting
        interval - 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 desired
        start - the time (in milliseconds) at which the metronome started counting
        interval - 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 desiredRatio of 1.0 returns 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 by markerNumber(long, long, double)
        markerPhase - the current phase with respect to the marker, as returned by markerPhase(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 by markerNumber(long, long, double)
        markerPhase - the current phase with respect to the marker, as returned by markerPhase(long, long, double)
        numerator - over how many markers should an oscillation cycle span
        denominator - 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:
        getBeatInterval in interface Snapshot
        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:
        getBarInterval in interface Snapshot
        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:
        getPhraseInterval in interface Snapshot
        Returns:
        the duration of a phrase
      • getBeat

        public long getBeat()
        Get the current beat being played.
        Specified by:
        getBeat in interface Snapshot
        Returns:
        the current beat number, which starts at 1
      • 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:
        getTimeOfBeat in interface Snapshot
        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:
        getBeatPhase in interface Snapshot
        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.
        Specified by:
        getBar in interface Snapshot
        Returns:
        the current bar number, which starts at 1
      • 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:
        getTimeOfBar in interface Snapshot
        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:
        getBarPhase in interface Snapshot
        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.
        Specified by:
        getPhrase in interface Snapshot
        Returns:
        the current phrase number, which starts at 1
      • 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:
        getTimeOfPhrase in interface Snapshot
        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:
        getPhrasePhase in interface Snapshot
        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".
        Specified by:
        getMarker in interface Snapshot
        Returns:
        a concise textual representation of the current metronome position
      • 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 call getSnapshot() and work with that instead.
        Specified by:
        getInstant in interface Snapshot
        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 of getBeatsPerBar().
        Specified by:
        getBeatWithinBar in interface Snapshot
        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:
        isDownBeat in interface Snapshot
        Returns:
        true we 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 of getBeatsPerBar() times getBarsPerPhrase().
        Specified by:
        getBeatWithinPhrase in interface Snapshot
        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:
        isPhraseStart in interface Snapshot
        Returns:
        true if 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 of getBarsPerPhrase().
        Specified by:
        getBarWithinPhrase in interface Snapshot
        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:
        distanceFromBeat in interface Snapshot
        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:
        distanceFromBar in interface Snapshot
        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:
        distanceFromPhrase in interface Snapshot
        Returns:
        the distance in milliseconds from the closest phrase boundary on the metronome's timeline