By itself, QLab doesn’t know about musical tempo, beats per minute, measure length, or time signature. Since time is just time, though, a little scripting can teach your workspace quite a lot about these concepts.
This cookbook article discusses using tempi in QLab in two ways. First, in Tempo Fugit, we'll explore applying a tempo to Audio or Video cues. Then, in Tempo Facit, we'll build a metronome in QLab.
This technique uses slices to mark bars and beats in an Audio or Video cue, and therefore to establish a tempo "on top of" the cue which you can use in a musical manner. The scripts described here and included in the downloadable example make it easier to work with tempo-based time in a QLab workspace.
One of the demos in the downloadable workspace shows how to create a chase effect using Light cues. This demo requires iLEDMapper, which is a free iOS app that receives Art-Net. You can download iLEDMapper here:
https://apps.apple.com/us/app/iledmapper/id404442976
iLEDMapper also runs on Macs with Apple Silicon processors.
The workspace contains three scripts.
This one is the easiest to use; simply select it and click the GO button or use the keyboard shortcut for GO, which is space by default, or the keyboard shortcut for preview which is V by default. The script will then ask you a few questions:
Once you’ve taken that little quiz, the script will make slices in your chosen cue according to your answers. Then, the script will append the name of the target cue to tell you how much time there is between the slices it just added.
Cue 2 in the example workspace has already been run through the script. It's a click track at 120 BPM with an emphasis every fourth beat. It's been sliced into quarter notes with no offset. Let's use this cue to try some fun things.
Set your workspace to Always Audition by choosing Turn on Always Audition from the Tools menu or by using the keyboard shortcut ⇧⌘A, then start cue 2. It is a click track at 120 BPM with an emphasis every 4th beat.
Now start cue 10. It's a Start First Group cue which creates a loop of Devamp cues and Text cues. The Devamp cues target cue 2. Every time cue 2 passes a marker, the Devamp cues inside cue 10 it will start the following Text cue which puts a beat number on screen. Handy to let your musicians know what beat of the bar they are on!
Leave cue 2 and cue 10 running, then use script A to make some markers in cue 3 that are different than cue 2. Maybe triplets?
Now, run cue 11. This will swap the targets of the Devamp cues inside cue 10 to cue 3 instead. You’ve changed tempo!
Cue 12 will swap right back.
Cue 20 shows off a simple light chase using Devamp cues and Light cues. To see it in action, you can either open the Light Dashboard and look in the Audition tab, or switch off Always Audition and open iLEDMapper on an iOS device that's on the same network as your Mac.
Cue 21 is a different approach to making a light chase, advancing through a second cue list so you can arbitrarily add cues as you’d like.
Cue 22 does some random design, in time. It triggers a random group, 22.5, so something happens every slice.
Here is Script A in full, annotated with comments about what each line or section does:
applescripttell application id "com.figure53.QLab.5" to tell front workspace -- make a list of possible divisions of a measure set beatDivisions to {"Measure", "Eighth Note", "Quarter Note", "Half Note", ¬ "1/8 Triplet", "1/4 Triplet"} as list -- ask which cue to slice (using cue number) set targetCue to text returned of (display dialog "Enter the cue number ¬ of the cue to slice:" default answer " " with title "Slice Cue by Tempo") -- ask at what time in the cue to start slicing set startTime to text returned of (display dialog "Start slicing the cue ¬ at time:" default answer "0" with title "Slice Cue by Tempo") as number -- the script defaults to add slices all the way to the end of the file set endTime to end time of cue targetCue -- ask what tempo to use set BPM to text returned of (display dialog "Enter the desired tempo ¬ in beats per minute (BPM):" default answer "120" with title ¬ "Slice Cue by Tempo") as integer -- use the list above to ask what beat division to use set beatdivision to choose from list beatDivisions with prompt "Choose a beat ¬ division:" default items {"Measure"} as string -- how many beats in a measure? set measureLength to text returned of (display dialog "Enter the number of ¬ beats per measure:" default answer "4" with title "Slice Cue by Tempo") ¬ as integer -- how many beats in a measure? set sliceOffset to text returned of (display dialog "Offset slices ¬ from the beat? Positive numbers will place slices after the beat, ¬ negative numbers will place slices before the beat." default answer "0" ¬ with title "Slice Cue by Tempo") as number -- this section creates the appropriate mathematical representation -- of the selected beat division and measure length if beatdivision as string = "Measure" then set beatDiv to measureLength else if beatdivision as string = "Eighth Note" then set beatDiv to (measureLength / 8) else if beatdivision as string = "Quarter Note" then set beatDiv to (measureLength / 4) else if beatdivision as string = "Half Note" then set beatDiv to (measureLength / 2) else if beatdivision as string = "1/8 Triplet" then set beatDiv to ((measureLength / 4) / 3) else if beatdivision as string = "1/4 Triplet" then set beatDiv to ((measureLength / 2) / 3) end if -- set the slice spacing based on the BPM and the beatDiv above set sliceSpacing to ((60 / BPM) * beatDiv) -- where the first slice should go, not counting offset set currentTrueSlice to (startTime + sliceSpacing) -- where the first slice should go including the offset set currentSlice to (currentTrueSlice + sliceOffset) -- get all the slices already in the cue set allSlices to slice markers of cue targetCue set sliceCount to (count allSlices) -- make an empty list which we'll later fill with slices set sliceArray to {} as list -- iterate through the slices which are already in the cue. -- take all the ones that fall before the startTime. -- and put them into that empty list repeat with eachItem from 1 to sliceCount set eachSlice to item eachItem of allSlices set eachTime to time of eachSlice if eachTime is less than startTime then copy eachSlice to end of sliceArray end if end repeat -- add new slices to the list based on our calcuations above repeat while currentSlice < endTime set sliceAdd to {time:currentSlice, playCount:1} copy sliceAdd to end of sliceArray set currentTrueSlice to (currentTrueSlice + sliceSpacing) set currentSlice to (currentTrueSlice + sliceOffset) end repeat -- replace the current slice markers in the target cue -- with the slices in the list set slice markers of cue targetCue to sliceArray -- rename the target cue by appending some information -- about the slices added by this script set cueName to q name of cue targetCue set newCueName to (cueName & " space between slices is " & sliceSpacing ¬ & " seconds") set q name of cue targetCue to newCueName end tell
This script is a bit less fancy, but can still be very useful. It sets the duration of Audio, Video, Text, Light, or Fade cues to a length based on tempo. It may be easiest to see the value of this script using Video cues which target still images or Light cues.
This script relies on a hotkey trigger, which is F1. Select some cues, for example all of those light cues in cue 22.5, then press F1 on your keyboard. That will set the duration of each selected cue to the length of a single beat at the given tempo.
This one is for Audio cues or Video cues. If you know the original tempo in BPM, you can use this script to adjust the playback rate of the cue to a different tempo. The script will also adjust any slices in the cue too. It can be handy for cues using lots of slices, and cues that are just too slow.
This workspace demonstrates using two click sounds, one for a downbeat and one for a regular beat, to create a metronome in QLab using a looping Playlist Group cue. Audio cues in the Group are separated by Wait cues, where the wait duration is equal to the beat's duration minus the click's duration.
The workspace contains two Script cues. The first one, cue MM, prompts you to enter a tempo and a number of beats per measure, then creates a "metronome" matching those specifications.
For this approach to work, the duration of both clicks must be specific and known. In this example, it's 0.1 seconds.
Here's the script:
applescripttell application id "com.figure53.QLab.5" to tell front workspace set downbeatCue to cue "DwnBt" set dwnBtTarget to file target of downbeatCue set beatCue to cue "Bt" set btTarget to file target of beatCue -- this method requires a fixed, known duration for the click cues set clickDuration to 0.1 -- enforce the that duration for both cues set end time of downbeatCue to clickDuration set end time of beatCue to clickDuration set BPM to text returned of (display dialog "Enter BPM between 20-600:" ¬ default answer "100") as integer set measureLength to text returned of (display dialog "How many beats per ¬ measure?" default answer "4") as integer -- 1 second divided by beats per second -- gives us the duration of one beat in seconds set beatDuration to (1 / (BPM / 60)) -- the wait cue's duration is equal to -- the duration of a beat minus the length of a click set waitDuration to (beatDuration - clickDuration) -- make the cues set newCues to {} as list set downBeat to true repeat measureLength times make type "Audio" set newCue to last item of (selected as list) set q number of newCue to "" if downBeat is true then set file target of newCue to dwnBtTarget set downBeat to false else set file target of newCue to btTarget end if copy newCue to end of newCues make type "Wait" set newCue to last item of (selected as list) set q number of newCue to "" set duration of newCue to waitDuration copy newCue to end of newCues end repeat -- put the cues into a playlist group set selected to newCues make type "Group" set newCue to last item of (selected as list) set q number of newCue to "" set mode of newCue to playlist set playlist loop of newCue to true set q name of newCue to ((measureLength & " Beats at " & BPM & "bpm") ¬ as string) end tell
Cue "110" is an example of a "metronome" created by the script.
The second script in the workspace, cue DV, allows you to "devamp" the metronome by setting the Playlist group to stop looping. Here's that script in detail:
applescripttell application id "com.figure53.QLab.5" to tell front workspace set playlistCue to cue "110" set loopEnabled to playlist loop of playlistCue if loopEnabled is true then set playlist loop of playlistCue to false else -- reset to original state set playlist loop of playlistCue to true end if end tell
If you run the script again, it resets the Playlist group to loop once more.