speedyrazor

Q: Quicktime Pro Applescript - Assign audio channels

Hi, I have been trying to find an applescript which would open a Quicktime Prores file which has multiple audio tracks in, either 8 mono tracks or 6 mono and one strereo track, currently all audio tracks by default have the 'Channels' assigned to mono. I currently have to go in and manually assign every track, using the dropdown menu to Left, Right, Center, LFE, Left Surround, Right Surround, Left Total, Right Total, but was wondering if this could be done with an Applescript as I have lots of these files to do regually. Another post I saw was able to change the 'name' of the tracks but not the 'Channels'.

 

I am on Mavericks with Quicktime 7 Pro.

 

Kind regards.

OS X Mavericks (10.9.2)

Posted on Apr 2, 2014 10:18 PM

Close

Q: Quicktime Pro Applescript - Assign audio channels

  • All replies
  • Helpful answers

  • by Hiroto,Solvedanswer

    Hiroto Hiroto Apr 3, 2014 11:39 PM in response to speedyrazor
    Level 5 (7,276 points)
    Apr 3, 2014 11:39 PM in response to speedyrazor

    Hello

     

    If I understand it correctly, the script listed below will do the job.

     

    Please edit the channel_layouts_map1 and channel_layouts_map2 as you see fit. The former is for 8 mono tracks and the latter is 6 mono tracks and 1 stereo track. Each entry in the map consists of a list of three items such that -

     

    item 1 = (string or int) name of index of target sound track
    item 2 = (string or int) new name for target track (int i denotes original name of sound track i)
    item 3 = (list) list of audio channel layout(s) in the target sound track
    

     

    Currently, script will remap the audio channel layouts and rename the sound track as specified. If you don't want to rename the tracks, specify the same value for item 1 and item 2.

     

    If the script is run in AppleScript Editor, it will ask you to choose movie file(s). If it is saved as applet (droplet), you may drag-and-drop movie file(s) onto it. It uses GUI scripting to reassign audio channel layouts, so you need to enable GUI scripting, that is a bit complicated under 10.9.

     

    cf.

    OS X: Using AppleScript with Accessibility and Security features in Mavericks

    http://support.apple.com/kb/HT5914

     

     

    Briefly tested with QuickTime Player Pro 7.6.6 (1710) (QuickTime version 7.6.6 (1800)) under OS X 10.6.8.

     

    * Script will override the original files. Please make sure you have backups of original files.

     

    Hope this may help,

    H

     

     

    (*
        remap audio channel layouts.applescript
        v0.1
    *)
    on run
        open (choose file with prompt ("Choose movie file(s)") ¬
            of type {"com.apple.quicktime-movie", "public.mpeg-4"} ¬
            with multiple selections allowed)
    end run
    
    on open aa
        set channel_layouts_map1 to {¬
            {"Sound Track 1", "Left", {"Left"}}, ¬
            {"Sound Track 2", "Right", {"Right"}}, ¬
            {"Sound Track 3", "Center", {"Center"}}, ¬
            {"Sound Track 4", "LFE Screen", {"LFE Screen"}}, ¬
            {"Sound Track 5", "Left Surround", {"Left Surround"}}, ¬
            {"Sound Track 6", "Right Surround", {"Right Surround"}}, ¬
            {"Sound Track 7", "Left Total", {"Left Total"}}, ¬
            {"Sound Track 8", "Right Total", {"Right Total"}} ¬
                }
        set channel_layouts_map2 to {¬
            {"Sound Track 1", "Left", {"Left"}}, ¬
            {"Sound Track 2", "Right", {"Right"}}, ¬
            {"Sound Track 3", "Center", {"Center"}}, ¬
            {"Sound Track 4", "LFE Screen", {"LFE Screen"}}, ¬
            {"Sound Track 5", "Left Surround", {"Left Surround"}}, ¬
            {"Sound Track 6", "Right Surround", {"Right Surround"}}, ¬
            {"Sound Track 7", "Left Total + Right Total", {"Left Total", "Right Total"}} ¬
                }
        
        repeat with a in aa
            set f to a's POSIX path
            set k to count_sound_tracks(f, {_close:false})
            if k = 8 then
                remap_audio_channels(f, channel_layouts_map1)
            else if k = 7 then
                remap_audio_channels(f, channel_layouts_map2)
            else
                -- ignore it (just close it)
                close_document(f, {_save:false})
            end if
        end repeat
    end open
    
    on count_sound_tracks(f, {_close:_close})
        (*
            string f : POSIX path of QT movie
            boolean _close: true to close document, false othewise
        *)
        tell application id "com.apple.quicktimeplayer" -- QuickTime Player 7 Pro
            open (f as POSIX file)
            tell (document 1 whose path = f)
                repeat until exists
                    delay 0.2
                end repeat
                set k to count (tracks whose audio channel count > 0)
                if _close then close
            end tell
        end tell
        return k
    end count_sound_tracks
    
    on close_document(f, {_save:_save})
        (*
            string f : POSIX path of QT movie
            boolean _save: true to save document (if modified), false othewise
        *)
        tell application id "com.apple.quicktimeplayer" -- QuickTime Player 7 Pro
            tell (document 1 whose path = f)
                if exists then
                    if _save and modified then save
                    close
                end if
            end tell
        end tell
    end close_document
    
    on remap_audio_channels(f, channel_layouts_map)
        (*
            string f : POSIX path of source movie
            list channel_layouts_map : list of {trk, trk_new, layouts}
                trk = (string or integer) name or index of source sound track
                trk_new = (string or integer) new name for source track (integer i denotes original name of sound track i)
                layouts = list of audio channel layout for channel(s) in source sound track
                    Mono
                    Left
                    Right
                    Center
                    LFE Screen
                    Left Surround
                    Right Surround
                    Left Center
                    Right Center
                    Center Surround
                    Rear Surround Left
                    Rear Surround Right
                    Left Total
                    Right Total
                    Discrete-0
                    Discrete-1
                    Unused
                
                e.g. 1
                   {{"Sound Track 1", "Left", {"Left"}}, ¬
                    {"Sound Track 2", "Right", {"Right"}}, ¬
                    {"Sound Track 3", "Center", {"Center"}}, ¬
                    {"Sound Track 4", "LFE Screen", {"LFE Screen"}}, ¬
                    {"Sound Track 5", "Left Surround", {"Left Surround"}}, ¬
                    {"Sound Track 6", "Right Surround", {"Right Surround"}}, ¬
                    {"Sound Track 7", "Left Total", {"Left Total"}}, ¬
                    {"Sound Track 8", "Right Total", {"Right Total"}}}
    
                e.g. 2
                   {{1, 1, {"Left", "Right"}}, ¬
                    {2, 2, {"Center", "LFE, Screen"}}, ¬
                    {3, 3, {"Left Surround", "Right Surround"}}, ¬
                    {4, 4, {"Left Total", "Right Total"}}}
            
            * this handler behaves as follows:
                1) open f
                2) scan sound tracks of document 1 for each trk and remap the track's audio channel layouts as specified
                3) scan sound tracks of document 1 for each trk and rename the track as specified
                4) save and close document 1
                
                * if specified trk is not found, it is ignored and no remapping is performed on the track.
                * if specified layout is not found, it is ignored and no remapping is performed on the layout.
                * if specified layout count is greater than channel count of the target track, excessive layouts are ignored.
                * if specified layout count is smaller than channel count of target track, excessive channels are ignored.
                * if trk and trk_new denotes the same track, renaming is not performed on the track.
        *)
        script o
            property map : channel_layouts_map
            property pp : {}
            property qq : {}
            
            -- get name and id of sound tracks
            tell application id "com.apple.quicktimeplayer" -- QuickTime Player 7 Pro
                activate
                open (f as POSIX file)
                tell (document 1 whose path = f)
                    repeat until exists
                        delay 0.2
                    end repeat
                    tell (tracks whose audio channel count > 0)
                        set {pp, qq} to {name, id} -- name and id of sound tracks
                    end tell
                end tell
            end tell
            
            -- remap audio channel layouts as specified
            tell application "System Events"
                tell (process 1 whose bundle identifier = "com.apple.quicktimeplayer")
                    -- open movie properties window
                    keystroke "j" using {command down}
                    
                    tell (window 1 whose subrole = "AXDialog") -- properties for movie
                        repeat until exists
                            delay 0.2
                        end repeat
                        repeat with m in my map
                            set {trk, undef, layouts} to m
                            -- [TRK:
                            repeat 1 times
                                if trk's class = integer then
                                    if trk < 1 or trk > (count my pp) then exit repeat -- TRK:
                                    set trk to my pp's item trk
                                end if
                                tell scroll area 1
                                    tell table 1
                                        tell (row 1 whose text field 1's value = trk) -- target sound track whose name = trk
                                            if not (exists) then exit repeat -- TRK:
                                            select
                                        end tell
                                    end tell
                                end tell
                                tell tab group 1
                                    click radio button 3 -- audio settings
                                    tell scroll area 1
                                        tell table 1 -- channel assignment table
                                            set ix to count layouts
                                            repeat with i from 1 to count rows
                                                if i > ix then exit repeat
                                                tell row i -- channel i
                                                    tell pop up button 1
                                                        click
                                                        tell menu 1 -- channel assignment menu
                                                            tell (menu item 1 whose title = layouts's item i)
                                                                if exists then click
                                                            end tell
                                                        end tell
                                                    end tell
                                                end tell
                                            end repeat
                                        end tell
                                    end tell
                                end tell
                            end repeat
                            -- /TRK:]
                        end repeat
                        
                        -- close movie properties window
                        click (button 1 whose subrole = "AXCloseButton")
                    end tell
                end tell
            end tell
            
            -- rename sound tracks as specified
            tell application id "com.apple.quicktimeplayer"
                tell document 1
                    repeat with m in my map
                        -- [RENAME:
                        repeat 1 times
                            set {x, y} to m's items 1 thru 2 -- {old name or index, new name or index}
                            if x's class = integer then
                                if x < 1 or x > (count my pp) then exit repeat -- RENAME:
                            else
                                set x to my _index_of(pp, x)
                                if x = 0 then exit repeat -- RENAME:
                            end if
                            if y's class = integer then
                                if y < 1 or y > (count my pp) then exit repeat -- RENAME:
                                set y to my pp's item y
                            end if
                            set p to my pp's item x
                            set q to my qq's item x
                            if p ≠ y then set track id q's name to y
                        end repeat
                        -- /RENAME:]
                    end repeat
                    if modified then save
                    close
                end tell
            end tell
            
        end script
        tell o to run
    end remap_audio_channels
    
    on _index_of(xx, x) -- renamed _bsearch() v0.1
        (*
            list xx : source list
            anything x : item to be searched in xx
            return integer : the first index of x in xx if {x} is in xx, or 0 if not.
        *)
        script o
            property aa : xx
            local i, j, k
            if {x} is not in my aa then return 0
            set i to 1
            set j to count my aa
            repeat while j > i
                set k to (i + j) div 2
                if {x} is in my aa's items i thru k then
                    set j to k
                else
                    set i to k + 1
                end if
            end repeat
            return i
        end script
        tell o to run
    end _index_of
    
  • by speedyrazor,

    speedyrazor speedyrazor Apr 4, 2014 2:02 AM in response to Hiroto
    Level 1 (0 points)
    Apr 4, 2014 2:02 AM in response to Hiroto

    Hi Hiroto, that is amazing, thank you so much for your time, brilliant!

    I have a couple of questions regarding how this script runs.

     

    1. Your original script opens the quicktime, instantly applies the changes and closes, all taking less than a second. This new script opens the 'Show Movie Properties', then proceedes to go through and select all the correct audio assignments. So my question is, is there a way to do this operation silently, or just because of the way Applescript interfaces with Quicktime, this is the way it has to run?

     

    2. I develop a few Python applications and was looking at using this script in conjuction with a python application I am about to write. I want to feed a file, or files, or folder, into this script from the Python app, and wondered what would be the best way to go about this?

     

    Kind regards.

  • by Hiroto,Helpful

    Hiroto Hiroto Apr 5, 2014 7:13 AM in response to speedyrazor
    Level 5 (7,276 points)
    Apr 5, 2014 7:13 AM in response to speedyrazor

    Hello

     

    As for Q1, after some investigations, the only way I can think of to do this silently is to use QTSetTrackProperty() function [1]. Apparently QuickTime Player 7's AppleScript interface does not provide any means to modify audio channel layout assignment. Even with QTKit.framework [2], it seems only possible to get audio channel assigment information and not to set it. So my answer to your question is no unless you write your own programme to call the said function in C. I'm going to look into this further to see whether it is possible to call this function from rubycocoa script by preparing custom bridgesupport file.

     

    [1] /System/Library/Frameworks/QuickTime.framework/Versions/A/Headers/Movies.h

    [2] /System/Library/Frameworks/QTKit.framework

     

     

    As for Q2, unfortunetly I'm not familiar with python snake. But generally you can execute applescript script by /usr/bin/osascript and osascript can handle run-time arguments if the script is written such as -

     

    on run argv
        -- argv is a list of run-time arguments
    end run
    

     

    For example, to pass file1, file2 and file3 to a script save as a.scpt, you may call the script by -

     

    osascript a.scpt file1 file2 file3
    

     

    See osascript manpage for more details.

     

    In order to amend the script in this thread to meet this calling convention, you'd need to replace the run handler with -

     

    on run argv
        repeat with a in argv
            set a's contents to a as POSIX file as alias
        end repeat
        open argv
    end run
    

     

    Note that file must be given by its full posix path in argument for osascript, for this applescript script simply treats each of them as full posix path literally without honouring current directory or tilde in path.

     

    Hope this may help thus far,

    H

     

    PS. QTSetTrackProperty() function is documented in -

     

    QuickTime Framework Reference

        > Other References

            > QuickTime Movie Properties Reference

     

    although this huge QuickTime Framework Reference (ca. 14mb, last revised on 2006-05-23) is no longer available in apple's server. You may find its html version in Xcode for 10.5 or may find a pdf version in 'net via google.

  • by speedyrazor,

    speedyrazor speedyrazor Apr 5, 2014 9:39 AM in response to Hiroto
    Level 1 (0 points)
    Apr 5, 2014 9:39 AM in response to Hiroto

    Hi Hiroto, thanks again for your time, extremely informative.

    I am trying to get the script working with Python, I have replaced the run handler, and am passing it my file path, but am getting an error: ''execution error: Can\xe2\x80\x99t make file "OSX:Users:me:Desktop:DOWNLOAD:44.mov" into type alias'

     

    I am sending it args = ["/Users/me/Desktop/DOWNLOAD/44.mov"]

    What do I need to change please?

     

    Also the script runs quite slow on my Macboook Pro, not sure if it's my configuration, quicktime mov takes about 3-4 seconds to open, then another 3-4 seconds to start the actions, any reason for this?

     

    I have another quicktime related quistion here also: https://discussions.apple.com/thread/6059292?tstart=0

    Kind regards.

  • by speedyrazor,

    speedyrazor speedyrazor Apr 5, 2014 11:48 AM in response to speedyrazor
    Level 1 (0 points)
    Apr 5, 2014 11:48 AM in response to speedyrazor

    Hi Hiroto, sorry, my mistake I got it working and sending a filepath via osascript, thanks for your help.

    Very interested in finding if there is a 'silent' way to do this process.

    I still have the slow / pause issue, taking 3-4 seconds between each stage, see previous post.

    Kind regards.

  • by Hiroto,Helpful

    Hiroto Hiroto Apr 5, 2014 12:56 PM in response to speedyrazor
    Level 5 (7,276 points)
    Apr 5, 2014 12:56 PM in response to speedyrazor

    Hello

     

    I don't know why it runs so slow in your environment. One thing I'd try is to modify the remap_audio_channels() handler so that the last line -

     

    tell o to run
    

     

    is replaced with -

     

    run script o
    

     

    In other words, to replace -

     

    on remap_audio_channels(f, channel_layouts_map)
        script o
            -- omitted
        end script
        tell o to run
    end remap_audio_channels
    

     

    with -

     

    on remap_audio_channels(f, channel_layouts_map)
        script o
            -- omitted
        end script
        run script o
    end remap_audio_channels
    

     

    This is a known technique to dramatically incease the execution speed of script when it is run as applet. But I don't think you're running the script as applet and so I'm not sure this method would work in this case.

     

    That's all for now.

    Good luck,

    H

  • by DjMute1,

    DjMute1 DjMute1 Jul 3, 2014 11:34 PM in response to Hiroto
    Level 1 (0 points)
    Jul 3, 2014 11:34 PM in response to Hiroto

    Hi Hiroto,

     

    I have a similar issue, but i was given footage that has 2 or 4 audio channels, all of which are marked as "Unused".  I have over 1500 individual clips which can be quite tedious to manually change.  When I stumbled across your script I was very excited.

    I modified the k values to be 2 & 4, respectively and removed the extra channels from the channel_layouts_map1 and 2 to only reflect Left, Right and Surround Left and Right.

    In reviewing the code, everything makes sense; however, it appears that my files are being opened and closed because the count_sound_track is failing.  Is this possibly due to the Unused designation?  It doesn't make sense to me, but I was hoping you could help me with it.

     

    Thanks in advance,

    DjMute1

  • by speedyrazor,

    speedyrazor speedyrazor Apr 25, 2015 11:57 AM in response to DjMute1
    Level 1 (0 points)
    Apr 25, 2015 11:57 AM in response to DjMute1

    Hi, I have been using this Apple Script for a while now and would like to progress this on to a command line application which does exactly the same job. I have been looking at Xcode to build a command line application which I could use but don't know where to get started. Is this even possible?

     

    Kind regards.