Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
9.2KB

  1. #!/usr/bin/env python
  2. # Copyright (C) 2013 Jonathan Moore Liles #
  3. # #
  4. # This program is free software; you can redistribute it and/or modify it #
  5. # under the terms of the GNU General Public License as published by the #
  6. # Free Software Foundation; either version 2 of the License, or (at your #
  7. # option) any later version. #
  8. # #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT #
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
  11. # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
  12. # more details. #
  13. # #
  14. # You should have received a copy of the GNU General Public License along #
  15. # with This program; see the file COPYING. If not,write to the Free Software #
  16. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
  17. import xml.etree.ElementTree as et
  18. import random
  19. import sys
  20. import os
  21. from datetime import date
  22. import shutil
  23. if len(sys.argv) == 1:
  24. print "Usage: import-ardour-session [PATH_TO_ARDOUR_FILE] [NAME_OF_NON_TIMELINE_PROJECT]"
  25. sys.exit( 1 )
  26. Overwrite=False
  27. i = 1;
  28. if ( sys.argv[i] == "--overwrite" ):
  29. Overwrite = True
  30. i = i + 1
  31. ArdourFilePath = sys.argv[i]
  32. i = i + 1
  33. NonTimelineProjectPath = sys.argv[i]
  34. i = i + 1
  35. try:
  36. os.makedirs( NonTimelineProjectPath );
  37. os.makedirs( NonTimelineProjectPath + "/sources");
  38. except:
  39. if not Overwrite:
  40. print "Output path already exists!"
  41. sys.exit( 1 )
  42. try:
  43. tree = et.parse( ArdourFilePath );
  44. except:
  45. print "Invalid XML input"
  46. sys.exit( 1 )
  47. root = tree.getroot();
  48. Sources = {}
  49. DiskStreams = {}
  50. print "Gathering session info"
  51. if root.tag != "Session":
  52. print "Not an Ardour session?"
  53. sys.exit(1)
  54. print "Ardour session file version is " + root.attrib["version"]
  55. print "This program is known to work with versions <= 3.0.1"
  56. ProjectName = root.attrib["name"]
  57. print "Converting Ardour session \"" + ProjectName + "\" to Non Timeline format. Please be patient."
  58. print "Gathering sources."
  59. for node in root.findall( "./Sources/Source" ):
  60. Sources[node.attrib["id"]] = node;
  61. # print "\tFound source " + node.attrib["name"]
  62. print "Gathering version 3 diskstreams."
  63. for node in root.findall( "./Routes/Route/Diskstream" ):
  64. DiskStreams[node.attrib["id"]] = node;
  65. print "\tFound diskstream " + node.attrib["name"];
  66. print "Gathering version 2 diskstreams."
  67. for node in root.findall( "./DiskStreams/AudioDiskstream" ):
  68. DiskStreams[node.attrib["id"]] = node;
  69. # print "\tFound diskstream " + node.attrib["name"];
  70. print "Gathering version 1 diskstreams."
  71. for node in root.findall( "./DiskStreams/DiskStream" ):
  72. DiskStreams[node.attrib["id"]] = node;
  73. # print "\tFound diskstream " + node.attrib["name"];
  74. LoggableID = 1;
  75. def NewID():
  76. global LoggableID
  77. ID="0x%x" % LoggableID
  78. LoggableID = LoggableID + 1
  79. return ID
  80. History = "{\n"
  81. print "Processing tempo."
  82. for node in root.findall("./TempoMap/Tempo"):
  83. TempoID = NewID()
  84. History += ( "\tTempo_Point " + TempoID + " create :start 0 :tempo " + node.attrib["beats-per-minute"] + "\n")
  85. for node in root.findall("./TempoMap/Meter"):
  86. TimeID = NewID()
  87. try:
  88. BPB = node.attrib["beats-per-bar"]
  89. except:
  90. BPB = node.attrib["divisions-per-bar"]
  91. History += ( "\tTime_Point " + TimeID + " create :start 0 :beats_per_bar " + BPB + " :beat_type " + node.attrib["note-type"] + "\n")
  92. print "Processing playlists."
  93. for node in root.findall( "./Playlists/Playlist" ):
  94. try:
  95. Track = DiskStreams[node.attrib["orig_diskstream_id"]]
  96. except:
  97. try:
  98. Track = DiskStreams[node.attrib["orig-track-id"]]
  99. except:
  100. print "\tSkipping playlist " + node.attrib["name"] + " for unknown diskstream"
  101. continue
  102. if node.attrib["name"] == Track.attrib["playlist"]:
  103. print "\tFound playlist " + node.attrib["name"]
  104. # for chan in range(0, int( Track.attrib["channels"] )):
  105. TrackID = NewID()
  106. SequenceID = NewID()
  107. # if int(Track.attrib["channels"]) > 1:
  108. # TrackName = Track.attrib["name"] + "-" + ( "%i" % chan )
  109. # else:
  110. TrackName = Track.attrib["name"]
  111. Channels = int(Track.attrib["channels"])
  112. History += ( "\tTrack " + TrackID + " create :name \"" + TrackName + "\"" + ( " :sequence " + SequenceID ) + " :color " + ( "%i" % random.randint(256,123123123)) + ( " :inputs %i :outputs %i\n" % ( Channels, Channels ) ) )
  113. History += ( "\tAudio_Sequence " + SequenceID + " create :track " + TrackID + " :name \"" + node.attrib["name"] + "\"\n" )
  114. for n2 in node.findall("./Region"):
  115. RegionID = NewID();
  116. if ( int( Track.attrib["channels"] ) > 1 ):
  117. SourceList = []
  118. APath1 = os.path.dirname(ArdourFilePath) + "/sounds/"
  119. APath2 = os.path.dirname(ArdourFilePath) + "/interchange/" + ProjectName + "/audiofiles/"
  120. for chan in range(0, int( Track.attrib["channels"] )):
  121. SourceName = Sources[n2.attrib["source-" + ( "%i" % chan )]].attrib["name"]
  122. if os.path.exists( APath1 + SourceName):
  123. SourceName = APath1 + SourceName
  124. elif os.path.exists( APath2 + SourceName ):
  125. SourceName = APath2 + SourceName
  126. else:
  127. print "source not found!"
  128. SourceList.append( "'" + SourceName + "'" );
  129. s1,s2,s3 = Sources[n2.attrib["source-0"]].attrib["name"].partition( '%' )
  130. SourceName = s1 + ".wav"
  131. OutputName = NonTimelineProjectPath + "/sources/" + SourceName
  132. if not os.path.exists( OutputName ):
  133. print "Combining multifile source into multichannel source"
  134. os.system( "sox -S -M " + " ".join(SourceList) + " " + "'" + OutputName + "'" )
  135. else:
  136. SourceName = Sources[n2.attrib["source-0"]].attrib["name"];
  137. if not os.path.exists( NonTimelineProjectPath + "/sources/" + SourceName ):
  138. print "\t\tCopying source: " + SourceName;
  139. try:
  140. shutil.copy( os.path.dirname(ArdourFilePath) + "/interchange/" + ProjectName + "/audiofiles/" + SourceName,
  141. NonTimelineProjectPath + "/sources/" )
  142. except:
  143. shutil.copy( os.path.dirname(ArdourFilePath) + "/sounds/" + SourceName,
  144. NonTimelineProjectPath + "/sources/" )
  145. History += ("\tAudio_Region " + RegionID +
  146. " create :source \"" + SourceName +
  147. "\" :start " + n2.attrib["position"] +
  148. " :length " + n2.attrib["length"] +
  149. " :offset " + n2.attrib["start"] +
  150. " :sequence " + SequenceID + "\n")
  151. else:
  152. print "\tSkipping inactive playlist"
  153. History += ("}\n")
  154. print "Comitting to disk."
  155. with open( NonTimelineProjectPath + "/info", 'w' ) as InfoFile:
  156. try:
  157. SampleRate = root.attrib["sample-rate"]
  158. except:
  159. print "Couldn't find sample rate... Using default."
  160. SampleRate = "48000"
  161. 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" )
  162. with open( NonTimelineProjectPath + "/history", 'w' ) as HistoryFile:
  163. HistoryFile.write( History )
  164. print "Done. You've been freed. Go make music!"