Tape Transport

This chapter demonstrates a method for providing bidirectional playback of audio and video files. Since QLab does not have ability to play any file backwards, we will need to use a pair of files: a main file and a reversed version of the file.

The cue targeting the reversed file should have the same cue number as the cue targeting main file prefixed with “R”, e.g. cue “1” and cue “R1”.

Here is a simple example of playback being reversed on cue, using two files:

Action Elapsed Method

A Script cue loads the reverse cue to (the duration of the cue - the action elapsed time of the forwards cue). It then starts the reverse cue and stops the forward cue:

tell application id "com.figure53.QLab.5" to tell front workspace
    stop cue "R101"
    if running of cue "101" is true then load (cue "R101") time ((duration of cue "101") - (action elapsed of cue "101"))
    delay 0.01
    start cue "R101"
    delay 0.1
    stop cue "101"
end tell

To return to regular forward playback there’s another Script cue which works the other way around:

tell application id "com.figure53.QLab.5" to tell front workspace
    stop cue "101"
    if running of cue "R101" is true then load (cue "101") time ((duration of cue "R101") - (action elapsed of cue "R101"))
    start cue "101"
    delay 0.1
    stop cue "R101"
end tell

This could work well for many uses. However, things get considerably more complicated if the speed of playback is varied.

This screen recording shows the reverse cue starting at a position related to the number of seconds since the forward cue was started, ignoring the fact that the playback was sped up and slowed down. This creates a severe discontinuity as we switch from the forward to the reverse cue.

Slice Marker Method

To solve this problem, we need to know the playback time in the forward video file, which cannot be accessed through scripting or OSC. Slice markers are much smarter! QLab will allow Network cues to add slice markers to cues at the exact current playback position, regardless of playback rate, so we can modify the reverse script to delete all slice markers in the forward cue, add a new slice marker, and then read the slice markers back to the script to get the actual time in the file at which the slice marker was added:

--Reverse x 1 Playback
tell application id "com.figure53.QLab.5" to tell front workspace
    set theCue to cue "101"
    set theReverseCue to cue "R101"
    stop theReverseCue
    set the rate of theCue to 1
    set the rate of theReverseCue to 1
    if the running of theCue is true then
        set theOSC to "/cue/" & q number of theCue & "/deleteSliceMarkers"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set theOSC to "/cue/" & q number of theCue & "/addSliceMarker"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set therecord to slice markers of theCue
        if therecord is not {} then
            set theTime to (duration of theCue) - (time of item 1 of therecord)
        else
            set theTime to 0
        end if
        load theReverseCue time theTime
    else if the running of theCue is false then
        load theReverseCue time 0
    end if
    delay 0.1
    start theReverseCue
    delay 0.1
    stop theCue
end tell

Although this looks a lot more complex, it is basically the same script as we used previously. The difference is, instead of reading the action elapsed time to calculate the load time for the reverse cue, we add and then read the location of a marker.

There are no script equivalents for the OSC messages dealing with slice markers, so we send these as plain text to port 53535 using shell scripts. Many OSC methods that don’t have an equivalent AppleScript method can be used in scripts in this way.

We get the slice marker record of the cue with:

set therecord to slice markers of theCue

There is only one slice marker and, therefore only one item in the record; we get the time with:

time of item 1 of therecord

The reverse is not quite as smooth as the previous version, but it does start in the right place and may be usable for any applications that do not require seamless palindromic playback.

Fast Forward to a Location

If we want to fast-forward to a specific place in the video reasonably accurately we need to tell QLab where to slow to a stop.

The fast-forward cue begins by fading the playback rate to 4× speed with a Fade cue.

Rate fade

Again, as soon as we alter the speed of the playback, the action elapsed time is of no use in determining the playback position in the target video file. We can, however, write a slice marker to the file to mark the required location.

--Set Target Time for FF
tell application id "com.figure53.QLab.5" to tell front workspace
    set theTTime to 10
    set theTTime to theTTime - 2 -- subtract slow down time
    set therecord to {time:theTTime, playCount:1}
    set slice markers of cue "101" to therecord
end tell

With this script we just write the slice markers record directly to the forward cue. The time in the record is the time at which we want to resume normal speed playback, minus the duration of the Fade cue that we will use to restore the playback rate to 1.0.

The next cue in the Timeline Group is a Start First Group which contains a Devamp cue set to “start next cue when target reaches end of the current slice.”

Start next cue

The next cue is the Fade cue.

Using this same method on the reversed cue lets us rewind to a location:

Tape Transport

The rest of this tutorial uses the methods above to build a workspace that will allow any Audio or Video cue to be placed in a simulation of a reel-to-reel tape machine with transport buttons.

The mechanics of the workspace are contained in a cue list named “MECHANICS”.

Mechanics

At the top of this cue list are a series of Memo cues that store variables in their cue names and post-wait times. These variables are used to set the behavior of the tape transport.

There are then Group cues containing Script and Network cues for each transport function. Fast forward and rewind functions also have corresponding Group cues which slow them to a stop.

Instead of the Fade cues we used in our previous examples, this cue list uses Network cues with OSC messages. This allows them to use OSC queries to get the cue numbers of the cues from the name of cue “CUE” (which is where the variable for the cue number is stored) to include in the OSC message.

For fast-forwarding:

OSC forward

For rewinding:

OSC rewind

Note that we insert the “R” prefix for the reverse cue just before the OSC query between the pound signs.

We’ll examine a couple of the scripts in detail, which should allow understanding of any of the other scripts in this cue list.

Here’s the script to fast-forward to a target time:

--ffwd until target time
tell application id "com.figure53.QLab.5" to tell front workspace
    --set new mode
    set q name of cue "MODE" to "Fast Forward to target"
    --get the cue nummbers
    set theCue to q list name of cue "CUE"
    set theReverseCue to cue ("R" & theCue)
    set theCue to cue theCue
    --get any required variables and set OSC fade cues to the values
    set theTTime to the post wait of cue "TTIME"
    set theFRate to post wait of cue "FRATE"
    set theUtime to post wait of cue "UTIME"
    set theDtime to post wait of cue "DTIME"
    set the cue target of cue "FDEV" to theCue
    set the duration of cue "FF" to theUtime
    set the duration of cue "FX1" to theDtime
    set the fade to of cue "FF" to theFRate
    set the fade from of cue "FX1" to theFRate
    --set the playback rates to 1x
    set the rate of theReverseCue to 1
    set the rate of theCue to 1
    --If the direction is going to change find the current playtime  of the reverse cue and set the forward cue to it
    if the running of theReverseCue or paused of theReverseCue is true then
        stop theCue
        set theOSC to "/cue/" & q number of theReverseCue & "/deleteSliceMarkers"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set theOSC to "/cue/" & q number of theReverseCue & "/addSliceMarker"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set therecord to slice markers of theReverseCue
        if therecord is not {} then
            set theTime to (duration of theCue) - (time of item 1 of therecord)
            delay 0.1
            load theCue time theTime
        end if
    end if
    --set up the target slice marker
    set theTTime to theTTime - theDtime - 0.5
    set therecord to {time:theTTime, playCount:1}
    set slice markers of theCue to therecord
    set the rate of theCue to 1
    
    start theCue
    delay 0.1
    stop theReverseCue
    delay 0.01
    start cue "FF"
    start cue "FDV"
end tell

The script stores a string as a variable in the cue name of the Memo cue numbered “MODE” so that other scripts can determine which transport function is currently in use.

It then reads the cue number of the Audio or Video cue which is currently assigned to the transport, which is stored in the cue name of cue “CUE”.

It then assigns variables for the forward and reverse cues based on this cue number.

Next, it sets variables using values stored in the post-wait times of the Memo cues to set the time to end the fast-forward operation, the speed of the fast-forward, and how long the speed up and slow downs take.

These variables are then used to set times and rates of the cues which do the actual rate fading.

If the reverse cue is currently running (or paused), the ‘OSC messages in shell scripts’ method described previously is used to set the starting point for the playback of the forward cue.

The target time for the fast-forward to end is then set as a slice marker in the forward cue.

The forward cue is then started, and the reverse cue is stopped. Then, both the Network cue with the OSC fade to speed up the rate of playback and the Devamp cue that will trigger the slowdown and pause when the target time is reached are started.

The stop script is slightly different from the others:

--STOP
tell application id "com.figure53.QLab.5" to tell front workspace
    --get the current Mode
    set theMode to q list name of cue "MODE"
    --set the new mode
    set the q name of cue "MODE" to "stop"
    --get the Cue Numbers
    set theCue to q list name of cue "CUE"
    set theReverseCue to cue ("R" & theCue)
    set theCue to cue theCue
    --get any required variables and set OSC fade cues to the values
    set theTime to post wait of cue "DTIME"
    --bring to a halt from winds
    if theMode is "FFORWARD" then
        start cue "SFF"
        repeat while the running of cue "SFF" is true
            delay 0.1
        end repeat
        
    else if theMode is "REWIND" then
        start cue "SRW"
        repeat while the running of cue "SRW" is true
            delay 0.1
        end repeat
        
    end if
    pause theCue
    pause theReverseCue
end tell
end tell

It begins by getting the current transport mode in use, as it will need this to slow down any fast wind modes before pausing the cues. If a fast wind is currently in progress, it will trigger the cue that will slow that mode down and go into a repeat loop until the slow-down cue has been completed to delay the cues’ pausing. Although pause instructions are sent to both forward and reverse cues, only the one currently playing will recognize the pause.

Tape Transport

The MECHANICS cue list contains all the cues that are necessary to control the transport, but it would be quite difficult to operate things from this list. To make this easier, we will put any pairs of forward and reverse audio or video files, into their own cue list named “TRANSPORT MEDIA” and number them appropriately. The downloadable example workspace contains both an audio and a video example.

Media

The workspace also contains a cue cart called “TRANSPORT” which is laid out like a conventional tape deck control panel.

Buttons

The cues in this cart only start other cues; when any of the cue in this cart are pressed, a number of tasks must be carried out in order. For instance, when the “LOC” cue is pressed, which fast-forwards or rewinds to a target time in the Audio or Video cue, the first thing that must be determined is whether the target time is before or after the current playing time. We also want to change the cues’ colors to indicate the current mode in use.

So, each cue in the cart is a Start cue which starts a cue in a cue list named “INTERLOCKS”:

Interlocks

The STOP cue in the cart starts Group cue “S” which contains only a Script cue with this script:

tell application id "com.figure53.QLab.5" to tell front workspace
    start cue "STOP"
    start cue "DEFCOL"
    delay 0.2
    set the q color of cue "=STOP=" to "magenta"
end tell

The script starts cue “STOP” in the MECHANICS cue list, then starts cue “DEFCOL” in this cue list.

Cue “DEFCOL” is a Timeline Group cue with OSC messages in Network cues that returns all the cues in the TRANSPORT cart to their default colors. It then sets the color of the “STOP” cart cue to magenta to indicate that “STOP” is the current transport mode.

The PLAY cue in the cart starts Group cue “P” which contains only a Script cue with this script:

tell application id "com.figure53.QLab.5" to tell front workspace
    set theMode to q list name of cue "MODE"
    if theMode is in {"REWIND", "FFORWARD"} then
        start cue "STOP"
        repeat while the running of cue "STOP" is true
            delay 0.1
        end repeat
    end if
    start cue "FWD"
    start cue "DEFCOL"
    delay 0.2
    set the q color of cue "=PLY=" to "green"
end tell

This script gets the current transport mode, and if it is a fast wind mode starts cue “STOP”. It waits while the cue “STOP” is running and then starts cue “FWD” in the MECHANICS cue list, clears the colors with cue “DEFCOL”, and sets the color of the “PLAY” cart cue to green.

The cart cues and corresponding scripts for rewind, fast-forward, and reverse work similarly.

The LOC cue in the cart starts Group cue “L” which contains only a Script cue with this script:

tell application id "com.figure53.QLab.5" to tell front workspace
    set theMode to q list name of cue "MODE"
    start cue "STOP"
    repeat while the running of cue "STOP" is true
        delay 0.1
    end repeat
    delay 0.3
    set theCue to q list name of cue "CUE"
    set theReverseCue to cue ("R" & theCue)
    set theCue to cue theCue
    set theTTime to post wait of cue "TTIME"
    
    if the paused of theReverseCue is true then
        set theTime to 0
        set theOSC to "/cue/" & q number of theReverseCue & "/deleteSliceMarkers"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set theOSC to "/cue/" & q number of theReverseCue & "/addSliceMarker"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set therecord to slice markers of theReverseCue
        if therecord is not {} then set theTime to (duration of theCue) - (time of item 1 of therecord)
    else
        set theTime to duration of theCue
        set theOSC to "/cue/" & q number of theCue & "/deleteSliceMarkers"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set theOSC to "/cue/" & q number of theCue & "/addSliceMarker"
        do shell script "echo " & quoted form of theOSC & " | nc -u -w 0 127.0.0.1 53535"
        set therecord to slice markers of theCue
        if therecord is not {} then set theTime to (time of item 1 of therecord)
    end if
     if theTime > theTTime then
        start cue "RWND"
    else
        start cue "FFWD"
    end if
    start cue "DEFCOL"
    delay 0.2
    set the q color of cue "=LOC=" to "yellow"
end tell 

First, the script starts cue “STOP”.

Then, it determines if the locate point is before or after the current playback time and either rewinds or fast-forwards from the current time, determined by the slice marker method previously employed.

It finishes by indicating that the “LOC” cart cue is the current transport mode with the color routines previously described.

The OFF cart cue stops all playback by starting cue “C”. This stops the cue list named TRANSPORT MEDIA, halting all playback, and then resets the button colors to neutral.

The CURRENT CUE cue in the cart starts Group cue “SET” which contains only a Script cue with this script:

tell application id "com.figure53.QLab.5" to tell front workspace
    start cue "OFF"
    set theCue to text returned of (display dialog "Cue Number to Load on Tape Transport?" default answer "")
    set the q name of cue "CUE" to theCue
    set the q name of cue "CURRENT CUE" to theCue
    start cue "OFF"
end tell

This starts cue “OFF” to stop all playback and uses a dialog to ask the user for the cue number of the media to be “loaded” into the transport system.

It then sets the name of “CURRENT CUE” to the variable stored in the cue name of cue “CUE”.

Workspace Demo

The interlocks cue list should provide all the programming logic to allow the buttons to function like a reel-to-reel tape deck. It should be stressed that this chapter is merely intended to demonstrate some principles and techniques for changing the speed and apparent playback direction of cues. The hope is that readers will use this as a starting point for incorporating some of these methods into their own workspaces. The example aims to demonstrate as many of these methods as possible, but it is by no means a finished or polished workspace and shouldn’t be relied upon in its present form for anything beyond exploring the possibilities described.

Here’s a demo of the transport buttons in action:

The workspace can also be programmed as a conventional QLab cue list. This allows the variables for timings and cue loading etc. to be set from the cue list. Here it is being operated from the cue list named “Show Cue List”:

River Video by Mic Pool. All Rights Reserved.

Audio Cue Text by ChatGPT, AI Voiceover by Eleven Labs