# 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: ```javascript var timingCallbacks = new abcjs.TimingCallbacks(visualObj, params); ``` | Parameters | Description | | ------------- | ----------- | | visualObj | This is the output of the `renderAbc()` call. It is the music that will be timed. | | params | This is a object. See below for the possible properties. | ## Parameters | Name | Default | Description | | ------------- | ------- | ----------- | | `qpm` | whatever is in the Q: field | Number of beats per minute. | | `extraMeasuresAtBeginning` | 0 | Don't start the callbacks right away, but insert this number of measures first. | | `beatCallback` | null | Called for each beat passing the beat number (starting at 0). | | `eventCallback` | null | Called for each event (either a note, a rest, or a chord, and notes in separate voices are grouped together.) | | `lineEndCallback` | null | Called 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. | | `lineEndAnticipation` | 0 | The 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. | | `beatSubdivisions` | 1 | How 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. ```javascript function beatCallback(beatNumber, totalBeats, totalTime, position, debugInfo) {} ``` |Name|Description| |---|---| | beatNumber | Zero-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. | | totalBeats | The total number of beats (including all repeats) that will be played. | | totalTime | The total number of milliseconds of the tune. | | position | The 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. | | debugInfo | A 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. ```javascript function eventCallback(ev) {} ``` The parameter `ev` is an object that looks like this: ```javascript 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) } ] } ``` #### 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. ```javascript function lineEndCallback(info, event, details) {} ``` The parameter `info` looks like this: ```javascript 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 } ``` The parameter `event` is the standard note event. The parameter `details` looks like this: ```javascript details = { "line": number, // the current line number (zero-based) "endTimings": array // the array of the timings for each line } ``` 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(position, units) This starts the timer that triggers the callbacks. This is called to both start and resume after calling pause. See the `setProgress` method below for explanation of the parameters with one special case: If `position` is undefined then if 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. ### 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(position, 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: