File size: 8,381 Bytes
af6912c |
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# 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:
<example-tune-book v-if="abcjsReady" :callbacks="callbacks" :tune-id="32"></example-tune-book>
<timing-callbacks ref="timingCallbacks" target="#abc"></timing-callbacks>
<script>
import { waitForAbcjs } from '../../../wait-for-abcjs';
export default {
async mounted() {
await waitForAbcjs()
this.abcjsReady = true;
setTimeout(() => {
this.callbacks = [this.$refs.timingCallbacks];
}, 500);
},
data() {
return {
abcjsReady: false,
callbacks: [],
};
},
}
</script>
|