Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Applescript to extract and export individual Audio Tracks

Hi, I have been searching for a solution to an Applescript to take a Quicktime file and extract and export out all the individual audio tracks out to seperate wavs. So, for example, I have a Quicktime mov with multichannel audio, 6 mono channels and 1 stereo, which currently I go into 'Show Movie Properties', select each audio track in turn, click on the 'Extract' button then export that out matching the original audios spec, so in this case it was mono, 24bit, wav.

So I am looking for an Applescript which would batch this.


Kind regards.

OS X Mavericks (10.9.2)

Posted on Apr 4, 2014 2:12 AM

Reply
3 replies

Apr 7, 2014 6:41 PM in response to speedyrazor

Hello


I took me a while to get the knack of QTKit. The AppleScript script listed below, which is indeed a simple wrapper of rubycocoa script, will extract sound tracks of specified files silently without using QuickTime Player 7.


It will let you choose movie file(s) and output directory and then extract each sound track from chosen files and save it as movie file in the specified directory. Currently it does NOT export sound track as wav file, for I'm yet to understand how to define export setting in QTKit. If you're familiar with python, you'd be able to do the same thing using pyobjc.


Please see comments in script for the current naming convention of extracted sound tracks. A log file is created in the output directory.


I'm going to try to revise the code so that it can export sound track as wav file of desired specifications.


Hope this may help somehow,

H



on run
    open (choose file with prompt ("Choose movie file(s)") with multiple selections allowed)
end run

on open aa
    set outdir to (choose folder with prompt "Choose output folder")'s POSIX path
    repeat with a in aa
        set a's contents to a's POSIX path
    end repeat
    extract_sound_tracks(aa, outdir)
end open

on extract_sound_tracks(infiles, outdir)
    (*
        list infiles : list of POSIX path of input movie files
        string outdir : POSIX path of output directory
    *)
    set args to ""
    repeat with a in {outdir} & infiles
        set args to args & a's quoted form & space
    end repeat
    do shell script "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby <<'EOF' - " & args & "
require 'FileUtils'
require 'osx/cocoa'
OSX.require_framework 'QTKit'
include OSX

def log(logf, s)
    File.open(logf, 'a') do |a|
        a.puts '%-26s%s' % [Time.now.strftime('%F %T%z'), s]
    end
end

def extract_sound_tracks(infile, outdir)
    # 
    #     string infile : POSIX path of input movie file
    #     string outdir : POSIX path of output directory where extracted sound files are saved
    # 
    #     * this method extracts each sound track of infile and saves it as mov file in outdir with name 
    #     source file name & '_[' & sound track index & ']_' & sound track name & '.mov'.
    #     
    #     E.g., given source file name = a.mov, its 3rd sound track named 'Center' will be saved in
    #     outdir/a.mov_[3]_Center.mov
    #
    #     * outdir is created if not present
    #     
    outdir = File.readlink(outdir) if File.symlink?(outdir)
    FileUtils.mkdir_p outdir unless File.exists?(outdir)
    raise RuntimeError, %Q[#{outdir}: Not a directory.] unless File.directory?(outdir)
    logf = %Q[#{outdir}/#{Time.now.strftime('%F_extract_sound_tracks_log.txt')}]

    err = OCObject.new
    mov = QTMovie.objc_send(
        :movieWithAttributes, {
                QTMovieFileNameAttribute => infile,
                QTMovieOpenAsyncOKAttribute => NSNumber.numberWithBool(false),
            },
        :error, err)
    unless mov
        log(logf, %Q[# Failed to load movie: %s] % [infile])
        log(logf, err ? err.to_s : 'err = nil')
        return
    end
    
    mov_name = mov.attributeForKey(QTMovieDisplayNameAttribute)
    mov.tracksOfMediaType(QTMediaTypeSound).each_with_index do |trk, i|
        trk_id = trk.attributeForKey(QTTrackIDAttribute)
        trk_name = trk.attributeForKey(QTTrackDisplayNameAttribute)
        trk_range = trk.attributeForKey(QTTrackRangeAttribute)
        
        mov1 = QTMovie.movie    # new movie
        mov1.objc_send(:setAttribute, NSNumber.numberWithBool(true), :forKey, QTMovieEditableAttribute)
        mov1.objc_send(
            :insertSegmentOfTrack, trk,
            :fromRange, trk_range.QTTimeRangeValue,
            :scaledToRange, trk_range.QTTimeRangeValue)
            
        outfile = outdir + '/' + ('%s_[%d]_%s.mov' % [mov_name, i + 1, trk_name])
        err = OCObject.new
        r = mov1.objc_send(
            :writeToFile, outfile,
            :withAttributes, {
                    QTMovieFlatten => NSNumber.numberWithBool(true),
                },
            :error, err)
        if r
            log(logf, %Q[Extracted track %d (%s) of %s => %s] % [trk_id, trk_name, infile, outfile])
        else
            log(logf, %Q[# Failed to save track %d (%s) of %s in %s] % [trk_id, trk_name, infile, outfile])
            log(logf, err ? err.to_s : 'err = nil')
        end
    end
end

raise ArgumentError, %Q[Usage: #{File.basename($0)} outdir infile [infile ...]] unless ARGV.length > 1
outdir = ARGV.shift
ARGV.each { |f| extract_sound_tracks(f, outdir) }
EOF"
end extract_sound_tracks

Apr 11, 2014 10:08 PM in response to speedyrazor

Hello again.


It turned out to be more involved than I thought to define export settings programmatically. So, for now, here's a very simple version to export to wav file using default settings that QuickTime sees fit. In my brief experiments, I found limitations as follows:


a) It does not export to multi-channel wave file other than mono and stereo (2.0). If original sound track is of multi-channel > 2.0, audio channels will be mixed down to stereo 2.0.


b) If original sound track does not use lossless codec, such as AAC, AC3 etc, resulting LPCM sample sise (bit depth) will be 16-bit whereas sample rate (frequency) will (or may) be preserved as the original. If original sound track uses lossless codec, such as ALAC, resulting LPCM will preserve the original sample size and sample rate.


If you're fine with these limitations, the following script might help.


Tested with QuickTime 7.6.6 (1800) under 10.6.8.


Regards,

H



(*
    Export each sound track of movie file to wav file
*)
on run
    open (choose file with prompt ("Choose movie file(s)") with multiple selections allowed)
end run

on open aa
    set outdir to (choose folder with prompt "Choose output folder")'s POSIX path
    repeat with a in aa
        set a's contents to a's POSIX path
    end repeat
    extract_sound_tracks(aa, outdir)
end open

on extract_sound_tracks(infiles, outdir) -- export as wav
    (*
        list infiles : list of POSIX path of input movie files
        string outdir : POSIX path of output directory
    *)
    set args to ""
    repeat with a in {outdir} & infiles
        set args to args & a's quoted form & space
    end repeat
    do shell script "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby <<'EOF' - " & args & "
require 'FileUtils'
require 'osx/cocoa'
OSX.require_framework 'QTKit'
include OSX

def log(logf, s)
    File.open(logf, 'a') do |a|
        a.puts '%-26s%s' % [Time.now.strftime('%F %T%z'), s]
    end
end

def extract_sound_tracks(infile, outdir)
    # 
    #     string infile : POSIX path of input movie file
    #     string outdir : POSIX path of output directory where extracted sound files are saved
    # 
    #     * this method extracts each sound track of infile and saves it as wav file in outdir with name 
    #     source file name & '_[' & sound track index & ']_' & sound track name & '.wav'.
    #     
    #     E.g., given source file name = a.mov, its 3rd sound track named 'Center' will be saved in
    #     outdir/a.mov_[3]_Center.wav
    #
    #     * outdir is created if not present
    #     
    outdir = File.readlink(outdir) if File.symlink?(outdir)
    FileUtils.mkdir_p outdir unless File.exists?(outdir)
    raise RuntimeError, %Q[#{outdir}: Not a directory.] unless File.directory?(outdir)
    logf = %Q[#{outdir}/#{Time.now.strftime('%F_extract_sound_tracks_log.txt')}]

    err = OCObject.new
    mov = QTMovie.objc_send(
        :movieWithAttributes, {
                QTMovieFileNameAttribute => infile,
                QTMovieOpenAsyncOKAttribute => NSNumber.numberWithBool(false),
            },
        :error, err)
    unless mov
        log(logf, '# Failed to load movie: %s' % [infile])
        log(logf, err ? err.to_s : 'err = nil')
        return
    end
    
    mov_name = mov.attributeForKey(QTMovieDisplayNameAttribute)
    mov.tracksOfMediaType(QTMediaTypeSound).each_with_index do |trk, i|
        trk_id = trk.attributeForKey(QTTrackIDAttribute)
        trk_name = trk.attributeForKey(QTTrackDisplayNameAttribute)
        trk_range = trk.attributeForKey(QTTrackRangeAttribute)
        
        mov1 = QTMovie.movie    # new movie
        mov1.objc_send(:setAttribute, NSNumber.numberWithBool(true), :forKey, QTMovieEditableAttribute)
        mov1.objc_send(
            :insertSegmentOfTrack, trk,
            :fromRange, trk_range.QTTimeRangeValue,
            :scaledToRange, trk_range.QTTimeRangeValue)
            
        outfile = outdir + '/' + ('%s_[%d]_%s.wav' % [mov_name, i + 1, trk_name])
        err = OCObject.new
        r = mov1.objc_send(
            :writeToFile, outfile,
            :withAttributes, {
                    QTMovieExport => NSNumber.numberWithBool(true),
                    QTMovieExportType => NSNumber.numberWithLong(KQTFileTypeWave),
                },
            :error, err)
        if r
            log(logf, 'Extracted track %d (%s) of %s => %s' % [trk_id, trk_name, infile, outfile])
        else
            log(logf, '# Failed to save track %d (%s) of %s in %s' % [trk_id, trk_name, infile, outfile])
            log(logf, err ? err.to_s : 'err = nil')
        end
    end
end

raise ArgumentError, %Q[Usage: #{File.basename($0)} outdir infile [infile ...]] unless ARGV.length > 1
outdir = ARGV.shift
ARGV.each { |f| extract_sound_tracks(f, outdir) }
EOF"
end extract_sound_tracks

Applescript to extract and export individual Audio Tracks

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.