#!/usr/bin/env python2 # Copyright (C) 2013 Jonathan Moore Liles # # # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the # # Free Software Foundation; either version 2 of the License, or (at your # # option) any later version. # # # # This program is distributed in the hope that it will be useful, but WITHOUT # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # # You should have received a copy of the GNU General Public License along # # with This program; see the file COPYING. If not,write to the Free Software # # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # import xml.etree.ElementTree as et import random import sys import os from datetime import date import shutil if len(sys.argv) == 1: print( "Usage: import-ardour-session [PATH_TO_ARDOUR_FILE] [NAME_OF_NON_TIMELINE_PROJECT]" ) sys.exit( 1 ) Overwrite=False i = 1; if ( sys.argv[i] == "--overwrite" ): Overwrite = True i = i + 1 ArdourFilePath = sys.argv[i] i = i + 1 NonTimelineProjectPath = sys.argv[i] i = i + 1 try: os.makedirs( NonTimelineProjectPath ); os.makedirs( NonTimelineProjectPath + "/sources"); except: if not Overwrite: print( "Output path already exists!" ) sys.exit( 1 ) try: tree = et.parse( ArdourFilePath ); except: print( "Invalid XML input" ) sys.exit( 1 ) root = tree.getroot(); Sources = {} DiskStreams = {} print( "Gathering session info" ) if root.tag != "Session": print( "Not an Ardour session?" ) sys.exit(1) print( "Ardour session file version is " + root.attrib["version"] ) print( "This program is known to work with versions <= 3.0.1" ) ProjectName = root.attrib["name"] print( "Converting Ardour session \"" + ProjectName + "\" to Non Timeline format. Please be patient." ) print( "Gathering sources." ) for node in root.findall( "./Sources/Source" ): Sources[node.attrib["id"]] = node; # print( "\tFound source " + node.attrib["name"] ) print( "Gathering version 3 diskstreams." ) for node in root.findall( "./Routes/Route/Diskstream" ): DiskStreams[node.attrib["id"]] = node; print( "\tFound diskstream " + node.attrib["name"] ) print( "Gathering version 2 diskstreams." ) for node in root.findall( "./DiskStreams/AudioDiskstream" ): DiskStreams[node.attrib["id"]] = node; # print( "\tFound diskstream " + node.attrib["name"]; ) print( "Gathering version 1 diskstreams." ) for node in root.findall( "./DiskStreams/DiskStream" ): DiskStreams[node.attrib["id"]] = node; # print( "\tFound diskstream " + node.attrib["name"]; ) LoggableID = 1; def NewID(): global LoggableID ID="0x%x" % LoggableID LoggableID = LoggableID + 1 return ID History = "{\n" print( "Processing tempo." ) for node in root.findall("./TempoMap/Tempo"): TempoID = NewID() History += ( "\tTempo_Point " + TempoID + " create :start 0 :tempo " + node.attrib["beats-per-minute"] + "\n") for node in root.findall("./TempoMap/Meter"): TimeID = NewID() try: BPB = node.attrib["beats-per-bar"] except: BPB = node.attrib["divisions-per-bar"] History += ( "\tTime_Point " + TimeID + " create :start 0 :beats_per_bar " + BPB + " :beat_type " + node.attrib["note-type"] + "\n") print( "Processing playlists." ) for node in root.findall( "./Playlists/Playlist" ): try: Track = DiskStreams[node.attrib["orig_diskstream_id"]] except: try: Track = DiskStreams[node.attrib["orig-track-id"]] except: print( "\tSkipping playlist " + node.attrib["name"] + " for unknown diskstream" ) continue if node.attrib["name"] == Track.attrib["playlist"]: print( "\tFound playlist " + node.attrib["name"] ) # for chan in range(0, int( Track.attrib["channels"] )): TrackID = NewID() SequenceID = NewID() # if int(Track.attrib["channels"]) > 1: # TrackName = Track.attrib["name"] + "-" + ( "%i" % chan ) # else: TrackName = Track.attrib["name"] Channels = int(Track.attrib["channels"]) History += ( "\tTrack " + TrackID + " create :name \"" + TrackName + "\"" + ( " :sequence " + SequenceID ) + " :color " + ( "%i" % random.randint(256,123123123)) + ( " :inputs %i :outputs %i\n" % ( Channels, Channels ) ) ) History += ( "\tAudio_Sequence " + SequenceID + " create :track " + TrackID + " :name \"" + node.attrib["name"] + "\"\n" ) for n2 in node.findall("./Region"): RegionID = NewID(); if ( int( Track.attrib["channels"] ) > 1 ): SourceList = [] APath1 = os.path.dirname(ArdourFilePath) + "/sounds/" APath2 = os.path.dirname(ArdourFilePath) + "/interchange/" + ProjectName + "/audiofiles/" for chan in range(0, int( Track.attrib["channels"] )): SourceName = Sources[n2.attrib["source-" + ( "%i" % chan )]].attrib["name"] if os.path.exists( APath1 + SourceName): SourceName = APath1 + SourceName elif os.path.exists( APath2 + SourceName ): SourceName = APath2 + SourceName else: print( "source not found!" ) SourceList.append( "'" + SourceName + "'" ); s1,s2,s3 = Sources[n2.attrib["source-0"]].attrib["name"].partition( '%' ) SourceName = s1 + ".wav" OutputName = NonTimelineProjectPath + "/sources/" + SourceName if not os.path.exists( OutputName ): print( "Combining multifile source into multichannel source" ) os.system( "sox -S -M " + " ".join(SourceList) + " " + "'" + OutputName + "'" ) else: SourceName = Sources[n2.attrib["source-0"]].attrib["name"]; if not os.path.exists( NonTimelineProjectPath + "/sources/" + SourceName ): print( "\t\tCopying source: " + SourceName ) try: shutil.copy( os.path.dirname(ArdourFilePath) + "/interchange/" + ProjectName + "/audiofiles/" + SourceName, NonTimelineProjectPath + "/sources/" ) except: shutil.copy( os.path.dirname(ArdourFilePath) + "/sounds/" + SourceName, NonTimelineProjectPath + "/sources/" ) History += ("\tAudio_Region " + RegionID + " create :source \"" + SourceName + "\" :start " + n2.attrib["position"] + " :length " + n2.attrib["length"] + " :offset " + n2.attrib["start"] + " :sequence " + SequenceID + "\n") else: print( "\tSkipping inactive playlist" ) History += ("}\n") print( "Comitting to disk." ) with open( NonTimelineProjectPath + "/info", 'w' ) as InfoFile: try: SampleRate = root.attrib["sample-rate"] except: print( "Couldn't find sample rate... Using default." ) SampleRate = "48000" InfoFile.write( "created by\n\tNon-Timeline 1.2.0\ncreated on\n\t" + date.today().ctime() + "\nversion\n\t2\nsample rate\n\t" + SampleRate + "\n" ) with open( NonTimelineProjectPath + "/history", 'w' ) as HistoryFile: HistoryFile.write( History ) print( "Done. You've been freed. Go make music!" )