# Timing Callbacks

This runs an animation timer and does callbacks at various intervals. This allows you to do various effects that are timed with beats or playing notes.

# Creation

To use this create an instance of it:

var timingCallbacks = new abcjs.TimingCallbacks(visualObj, params);
1
ParametersDescription
visualObjThis is the output of the renderAbc() call. It is the music that will be timed.
paramsThis is a object. See below for the possible properties.

# Parameters

NameDefaultDescription
qpmwhatever is in the Q: fieldNumber of beats per minute.
extraMeasuresAtBeginning0Don't start the callbacks right away, but insert this number of measures first.
beatCallbacknullCalled for each beat passing the beat number (starting at 0).
eventCallbacknullCalled for each event (either a note, a rest, or a chord, and notes in separate voices are grouped together.)
lineEndCallbacknullCalled at the end of each line. (This is useful if you want to be sure the music is scrolled into view at the right time.) See lineEndAnticipation for more details.
lineEndAnticipation0The number of milliseconds for the lineEndCallback to anticipate end of the line. That is, if you want to get the callback half a second before the end of the line, use 500.
beatSubdivisions1How many callbacks should happen for each beat. This allows finer control in the client, for instance, to handle a progress bar.

# Callbacks

# beatCallback

This is called once for every beat in the tune. It is called one additional time when the tune is finished.

function beatCallback(beatNumber, totalBeats, totalTime, position, debugInfo) {}
1
NameDescription
beatNumberZero-based beat number. Usually this will increment sequentially and regularly, but if javascript is paused long enough (for instance, if the browser tab is changed), then there may be a number of these calls at once when it catches up.
totalBeatsThe total number of beats (including all repeats) that will be played.
totalTimeThe total number of milliseconds of the tune.
positionThe interpolated position of the cursor if the beat occurs between notes. This is an object with the attributes { left: , top: , height: } This can be used to smooth out the cursor by moving it on the beat callbacks. The higher the number of beatSubdivisions the smoother the cursor will be.
debugInfoA hash of some extra info that might be useful in figuring out why the callback was triggered.

# eventCallback

This is called once for every "event" in time - either a note or a rest. If there are multiple notes at the same time, then it is only called once for that group of notes.

function eventCallback(ev) {}
1

The parameter ev is an object that looks like this:

ev = {
    "type": "event", // This is always "event"

    "milliseconds": number, // The number of milliseconds from the beginning of the piece
    "millisecondsPerMeasure": number, // The number of milliseconds per measure

    "line": number, // The current "line", that is, the staff system.
    "measureNumber": number, // The measure number. Resets per line, so the first measure number on a line is zero.

    "top": number, // The number of pixels from the top of the svg that the note appears.
    "height": number, // The height of the note, in pixels. 
    "left": number, // The number of pixels from the left edge of the svg.
    "width": number, // The width of the note

    "elements": [  ], // Array of the actual elements on the page that are represented by the note or notes.
    "startCharArray": [ number ], // the character position in the original abc string
    "endCharArray": [ number ], // the character position in the original abc string
    "midiPitches": [ // Array of the currently playing pitches
        {
            "pitch": number, // The pitch number (based on the midi standard, i.e. middle C is 60)
            "durationInMeasures": number, // the note value as a fraction. (that is, a quarter note is 0.025)
            "volume": number, // The volume expressed as a number between 0 and 127
            "instrument": number // The instrument number (based on the midi standard, i.e. acoustic_grand_piano is 0)
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# Notes:

  • The startCharArray and endCharArray are arrays because there is more than one location in the abc string if there is more than one voice.

  • The format of the elements array is subject to change in future versions.

  • This is called one last time with passing in null at the end of the tune. On that call eventCallback can return the string "continue" to keep the timer from stopping. This is useful if you want to play on repeat - in theory you would probably have another call to seek().

  • This function can be a Promise or not.

# lineEndCallback

This will be called as the cursor is approaching the end of a line of music. This is useful if there is more than a screen's worth of music; it can be used to scroll the page at the right time.

function lineEndCallback(info, event, details) {}
1

The parameter info looks like this:

info = {
    "milliseconds": number, // current milliseconds from beginning of piece
    "top": number, // The number of pixels from the top of the svg to the top of the cursor
    "bottom": number // The number of pixels from the top of the svg to the bottom of the cursor
}
1
2
3
4
5

The parameter event is the standard note event.

The parameter details looks like this:

details = {
    "line": number, // the current line number (zero-based)
    "endTimings": array // the array of the timings for each line
}
1
2
3
4

The endTimings array elements are of the same type as the info parameter.

# Functions

These are the entry points that can be called on the timingCallbacks object.

# start(offsetPercent)

This starts the timer that triggers the callbacks. This is called to both start and resume after calling pause.

offsetPercent valueDescription
undefinedIf the previous call was to pause(), then the animation continues from where it left off. If there was no pause, then the animation starts from the beginning.
From 0 to 1The percentage into the animation to jump to. This is like doing a seek first.

# pause()

Pauses the animation. Calling start() afterwards will resume from where it left off.

# stop()

Stop the animation. After calling this, the next call to start() will start at the beginning.

# reset()

Move the timer back to the beginning, so the animation starts over. This can be called either when the animation is currently running or when it is paused.

# setProgress(percent, units)

Change the position of the animation. This allows random access to any place in the tune.

If the second parameter is not present, then units equals "percent". The possible values are:

  • "percent": The percent passed in is a number between 0 and 1. This can be called either when the animation is currently running or when it is paused.

  • "seconds": The seconds from the beginning of the tune. If this is passed the end of the tune it is changed to the end.

  • "beats": The beats from the beginning of the tune. If this is passed the end of the tune it is changed to the end.

# replaceTarget(visualObj)

If the underlying music changes on the fly, this replaces the current object without having to destroy the object and start over. visualObj is the return value from renderAbc.

# Example

Paste in any ABC you want here then click "start" to see what is returned by the timing callbacks:

timer = new abcjs.TimingCallbacks(visualObj, {
beatCallback: function() {...},
eventCallback: function() {...},
lineEndCallback: function() {...}
}

Output Stream:

Last Updated: 4/18/2021, 4:17:13 PM
Contributors: Paul Rosen