QLab Script - make a list of audio files

Contents

This is an "external script" - see QLab Scripts and Macros

 
# Make a list of audio files 

--

set theExplanation to "This script creates a text file on the Desktop with a list of all the audio files used as targets in the current QLab workspace, " & ¬
    "removing duplicates and sorting alphabetically. It then opens the file in TextEdit."

--

(* This script is not designed to be run from within QLab!
 
v1.0: 18/09/09 Rich Walsh (with help)
v1.1: 19/09/09 General tidy up
v1.2: 19/09/09 Corrected erroneous bug accusation
v1.3: 27/09/09 Changed routine to handle missing targets following changes in QLab 2.2.4; added some reassuring messages
v1.4: 12/10/09 Snow Leopard can't "get running", so rewrote a sequence; also improved efficiency: now pulls a list if Audio Cues directly,
        rather than checking if every cue is an Audio Cue; fixed possible trap with TIDs; switched to using POSIX form for file targets for consistency
        with other scripts
v1.5: 16/10/09 Now "tested" in Snow Leopard; switched to writing the file directly, rather than using TextEdit
v1.6: 27/10/09 Added progress counter
v1.7: 17/11/09 Found (much) faster way of processing files
v1.8: 11/01/10 Corrected minor typos; added tell front workspace for elegance; wrapped text for better wiki experience;
        implemented dialogTitle for cross-script pillaging; new explanation format

<<< Last tested with: QLab 2.2.6; Mac OS 10.5.8 & 10.6.2 >>> *)

-- ###FIXME### QLab and/or the "script runner" is, generally, increasingly unresponsive to scripts the more cues there are in a workspace

-- Declarations

global dialogTitle
set dialogTitle to "Make a list of audio files"

-- Preamble

display dialog theExplanation & return & return & "It may take a little while to run; are you sure you wish to proceed?" with title dialogTitle with icon 1 ¬
    buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel"

-- Grab the current time and format it appropriately to append it to the filename
-- Written with help from http://www.fluther.com/disc/22258/applescript-get-and-reformat-current-date-then-insert-it-in-any/
 
set currentTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to "" -- Can't assume this!
set {year:y, month:m, day:d, time string:t} to (current date)
set dateString to (y * 10000 + m * 100 + d) as string
set timeString to (t) as string
set theTime to ¬
    (text items 3 thru 4 of dateString) & "-" & ¬
    (text items 5 thru 6 of dateString) & "-" & ¬
    (text items 7 thru 8 of dateString) & " " & ¬
    (text items 1 thru 2 of timeString) & ¬
    (text items 4 thru 5 of timeString)
set AppleScript's text item delimiters to currentTIDs
 
-- Check QLab is running
 
tell application "System Events"
    set qLabIsRunning to count (every process whose name is "QLab")
end tell
if qLabIsRunning is 0 then
    display dialog "QLab is not running." with title dialogTitle with icon 0 buttons {"OK"} default button "OK" giving up after 5
    return
end if
 
tell application "QLab"
 
    activate
 
    -- Get the workspace name for later, and also protect against no open workspace
 
    try
        set workspaceName to q number of front workspace -- This actually gets the name of the workspace
    on error
        display dialog "There is no workspace open in QLab." with title dialogTitle with icon 0 buttons {"OK"} default button "OK" giving up after 5
        return
    end try
 
    display dialog "One moment caller..." with title dialogTitle with icon 1 buttons {"OK"} default button "OK" giving up after 1
 
    set startTime to time of (current date)
 
    -- Extract array of cue targets from QLab ("audioFiles"), skipping duplicates
 
    tell front workspace
 
        set audioFiles to {}
 
        -- First, the easy ones
 
        set validTargets to file target of every cue whose (q type is "Audio" and broken is false)
        set validTargetsRef to a reference to validTargets
        set countValidTargets to count validTargetsRef
        repeat with i from 1 to countValidTargets
            set eachTarget to item i of validTargetsRef
            set targetFile to (POSIX path of (eachTarget as alias)) as string -- Convert to POSIX
            if targetFile is not in audioFiles then
                copy targetFile to end of audioFiles
            end if
            if i mod 100 is 0 and (countValidTargets - i) > 50 then -- Countdown timer (and opportunity to escape)
                set timeTaken to ((time of (current date)) - startTime) as integer
                set timeString to my makeMMSS(timeTaken)
                if application "QLab" is frontmost then
                    display dialog (("Time elapsed: " & timeString & " - " & i as string) & " of " & countValidTargets as string) & " valid Audio Cues done..." with title ¬
                        dialogTitle with icon 1 buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" giving up after 1
                end if
            end if
        end repeat
 
        -- Now, broken cues
 
        set brokenCues to every cue whose (q type is "Audio" and broken is true)
        set brokenCuesRef to a reference to brokenCues
        set countBrokenCues to count brokenCuesRef
        repeat with i from 1 to countBrokenCues
            set eachCue to item i of brokenCuesRef
            try -- This try protects against cues that have never had targets
                set targetFile to (file target of eachCue as string)
                if targetFile is "missing value" then -- This string will be returned by cues whose targets have become invalid
                    set eachName to q name of eachCue
                    if eachName is "" then
                        set missingName to "?? (no name given)"
                    else
                        set missingName to "\"" & eachName & "\""
                    end if
                    set targetFile to " ****Missing file target for previously valid cue named " & missingName & "**** "
                    if targetFile is not in audioFiles then
                        copy targetFile to end of audioFiles
                    end if
                end if
            end try
            if i mod 10 is 0 and (countBrokenCues - i) > 5 then -- Countdown timer (and opportunity to escape)
                set timeTaken to ((time of (current date)) - startTime) as integer
                set timeString to my makeMMSS(timeTaken)
                if application "QLab" is frontmost then
                    display dialog (("Time elapsed: " & timeString & " - " & i as string) & " of " & countBrokenCues as string) ¬
                        & " broken Audio Cues done..." with title dialogTitle with icon 1 ¬
                        buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" giving up after 1
                end if
            end if
        end repeat
 
    end tell
 
end tell
 
-- Sort the list
 
set sortedList to my simple_sort(audioFiles)
 
-- Create text from array with carriage returns between cue targets ("theText")
 
set AppleScript's text item delimiters to return
set theText to sortedList as text
set AppleScript's text item delimiters to currentTIDs
 
-- Create a string of the full path of the text file to be created
 
set newFile to "" & (path to desktop) & "QLab | " & workspaceName & " | Audio files in use | " & theTime & ".txt"
 
-- Make the file
 
copy (open for access newFile with write permission) to theOpenFile
write theText to theOpenFile
close access theOpenFile
 
-- Open it in TextEdit
 
tell application "TextEdit"
    activate
    open file (newFile)
    set zoomed of front window to true
    set timeTaken to ((time of (current date)) - startTime) as integer
    set timeString to my makeNiceT(timeTaken)
    display dialog "Done. 
 
(That took " & timeString & ".)" with title dialogTitle with icon 1 buttons {"OK"} default button "OK" giving up after 60
end tell
 
-- Subroutines
 
on makeMMSS(howLong)
    set howManyMinutes to howLong div 60
    set minuteString to (howManyMinutes as string)
    set howManySeconds to howLong mod 60 as integer
    if howManySeconds > 9 then
        set secondString to (howManySeconds as string)
    else
        set secondString to "0" & (howManySeconds as string)
    end if
    return minuteString & ":" & secondString
end makeMMSS
 
on makeNiceT(howLong)
    if howLong is 0 then
        return "less than a second"
    end if
    set howManyHours to howLong div 3600
    if howManyHours is 0 then
        set hourString to ""
    else if howManyHours is 1 then
        set hourString to "1 hour"
    else
        set hourString to (howManyHours as string) & " hours"
    end if
    set howManyMinutes to (howLong mod 3600) div 60
    if howManyMinutes is 0 then
        set minuteString to ""
    else if howManyMinutes is 1 then
        set minuteString to "1 minute"
    else
        set minuteString to (howManyMinutes as string) & " minutes"
    end if
    set howManySeconds to howLong mod 60 as integer
    if howManySeconds is 0 then
        set secondString to ""
    else if howManySeconds is 1 then
        set secondString to "1 second"
    else
        set secondString to (howManySeconds as string) & " seconds"
    end if
    if hourString is not "" then
        if minuteString is not "" and secondString is not "" then
            set theAmpersand to ", "
        else if minuteString is not "" or secondString is not "" then
            set theAmpersand to " and "
        else
            set theAmpersand to ""
        end if
    else
        set theAmpersand to ""
    end if
    if minuteString is not "" and secondString is not "" then
        set theOtherAmpersand to " and "
    else
        set theOtherAmpersand to ""
    end if
    return hourString & theAmpersand & minuteString & theOtherAmpersand & secondString
end makeNiceT
 
-- This subroutine was taken from http://www.macosxautomation.com/applescript/sbrt/sbrt-05.html
 
on simple_sort(my_list)
    set the index_list to {}
    set the sorted_list to {}
    repeat (the number of items in my_list) times
        set the low_item to ""
        repeat with i from 1 to (number of items in my_list)
            if i is not in the index_list then
                set this_item to item i of my_list as text
                if the low_item is "" then
                    set the low_item to this_item
                    set the low_item_index to i
                else if this_item comes before the low_item then
                    set the low_item to this_item
                    set the low_item_index to i
                end if
            end if
        end repeat
        set the end of sorted_list to the low_item
        set the end of the index_list to the low_item_index
    end repeat
    return the sorted_list
end simple_sort
 
(* END: Make a list of audio files *)