def set_audio_output(self, output_number, element_string): """Sets audio output.""" if output_number not in STEREO_OUTPUTS: raise Exception( f'{R}Output number invalid!. Available options: \n{STEREO_OUTPUTS}{RST}' ) output_obj = STEREO_OUTPUTS[output_number] out_target_element = get_element( self.root, f'LiveSet.{element_string}.DeviceChain.AudioOutputRouting.Target', silent_error=True) if not isinstance(out_target_element, ElementTree.Element): out_target_element = get_element( # ableton 8 sets use "MasterChain" for master track. self.root, f'LiveSet.{element_string}.MasterChain.AudioOutputRouting.Target' ) lower_display_string_element = get_element( self.root, f'LiveSet.{element_string}.MasterChain.AudioOutputRouting.LowerDisplayString' ) else: lower_display_string_element = get_element( self.root, f'LiveSet.{element_string}.DeviceChain.AudioOutputRouting.LowerDisplayString' ) out_target_element.set('Value', output_obj['target']) lower_display_string_element.set('Value', output_obj['lower_display_string']) print( f"{G}Set {element_string} to {output_obj['lower_display_string']}")
def list_plugins(self): """Iterates through all plugin references and checks paths for VSTs.""" for plugin_element in self.root.iter('PluginDesc'): if plugin_element.findall('./VstPluginInfo'): name = get_element(plugin_element, 'VstPluginInfo.FileName', attribute='Value') path = self._parse_hex_path( get_element(plugin_element, 'VstPluginInfo.Dir.Data').text) if not path: print(f"{Y}Couldn't parse absolute path for {name}") continue # Some plugin paths end in the os path separator, others don't. if path[-1] == os.path.sep: full_path = f'{path}{name}' else: full_path = f'{path}{os.path.sep}{name}' exists = pathlib.Path(full_path).exists() color = G if exists else R print( f'{color}Plugin: {name}, {Y}Plugin folder path: {full_path}, {color}Exists: {exists}' ) elif plugin_element.findall('./AuPluginInfo'): name = get_element(plugin_element, 'AuPluginInfo.Name', attribute='Value') manufacturer = get_element(plugin_element, 'AuPluginInfo.Manufacturer', attribute='Value') print( f"{Y}Audio Units do not store paths. Plugin {manufacturer}: {name} cannot be verified." )
def get_bpm(self): """Gets bpm. Note, float numbers can appear to have trailing digits which can be misleading.""" ableton_10_bpm = 'LiveSet.MasterTrack.DeviceChain.Mixer.Tempo.Manual' ableton_9_bpm = 'LiveSet.MasterTrack.MasterChain.Mixer.Tempo.ArrangerAutomation.Events.FloatEvent' bpm_elem = get_element(self.root, ableton_10_bpm, attribute='Value', silent_error=True) if not bpm_elem: bpm_elem = get_element(self.root, ableton_9_bpm, attribute='Value') self.bpm = round(float(bpm_elem), 6) return self.bpm
def get_bpm(self): """Gets bpm.""" bpm = 'LiveSet.MasterTrack.DeviceChain.Mixer.Tempo.Manual' pre_10_bpm = 'LiveSet.MasterTrack.MasterChain.Mixer.Tempo.ArrangerAutomation.Events.FloatEvent' bpm_elem = get_element(self.root, bpm, attribute='Value', silent_error=True) if not bpm_elem: bpm_elem = get_element(self.root, pre_10_bpm, attribute='Value') self.bpm = round(float(bpm_elem), 6) return self.bpm
def __init__(self, track_root): self.track_root = track_root self.type = track_root.tag self.name = get_element(track_root, 'Name.UserName', attribute='Value') if not self.name: self.name = get_element(track_root, 'Name.EffectiveName', attribute='Value') self.id = track_root.get('Id') self.group_id = get_element(track_root, 'TrackGroupId', attribute='Value') # Guessing 'Sesstion' was a typo early on and got stuck to not break backwards compatibility self.width = get_element( track_root, 'DeviceChain.Mixer.ViewStateSesstionTrackWidth', attribute='Value') # Lane height in arrangement view will be automation lane 0 self.height = get_element( track_root, 'DeviceChain.AutomationLanes.AutomationLanes.AutomationLane.LaneHeight', attribute='Value') self.color = get_element(track_root, 'ColorIndex', attribute='Value') self.unfolded = get_element(track_root, 'TrackUnfolded', attribute='Value', silent_error=True) # Ableton 10 if not self.unfolded: folded = get_element(track_root, 'DeviceChain.Mixer.IsFolded', attribute='Value') # Ableton 9/8 self.unfolded = 'false' if folded == 'true' else 'true'
def set_audio_output(self, output_number, element_string): """Sets audio output.""" if output_number not in STEREO_OUTPUTS: raise Exception( f'{R}Output number invalid!. Available options: \n{STEREO_OUTPUTS}{RST}' ) output_obj = STEREO_OUTPUTS[output_number] out_target_element = get_element( self.root, f'LiveSet.{element_string}.DeviceChain.AudioOutputRouting.Target') lower_display_string_element = get_element( self.root, f'LiveSet.{element_string}.DeviceChain.AudioOutputRouting.LowerDisplayString' ) out_target_element.set('Value', output_obj['target']) lower_display_string_element.set('Value', output_obj['lower_display_string']) print( f"{G}Set {element_string} to {output_obj['lower_display_string']}")
def list_samples(self): """Iterates through all sample references and checks absolute and relative paths.""" for sample_element in self.root.iter('SampleRef'): name = get_element(sample_element, 'FileRef.Name', attribute='Value') print(f'{C}Sample name: {name}') relative_path, from_project_root = self.check_relative_path( name, sample_element) if relative_path: rel_exists = pathlib.Path(relative_path).exists() color = G if rel_exists else R print( f'\t{color}Relative path: {Y}{self.project_root_folder}{os.path.sep}{M}{from_project_root}, ' f'{color}Exists: {rel_exists}') abs_path = self._parse_hex_path( get_element(sample_element, 'FileRef.Data').text) abs_exists = pathlib.Path(abs_path).exists() if abs_path else None color = G if abs_exists else R print( f'\t{color}Absolute path: {Y}{abs_path}, {color}Exists: {abs_exists}' )
def check_relative_path(self, name, sample_element): """Constructs absolute path from project root and relative path stored in set.""" if not self.project_root_folder: print( f'{R}Error, project root folder is undefined, cant find relative paths.' ) return relative_path_enabled = get_element(sample_element, 'FileRef.HasRelativePath', attribute='Value') relative_path_type = get_element(sample_element, 'FileRef.RelativePathType', attribute='Value') if relative_path_enabled == 'true' and relative_path_type == '3': relative_path_element = get_element(sample_element, 'FileRef.RelativePath') sub_directory_path = [] for path in relative_path_element: sub_directory_path.append(path.get('Dir')) from_project_root = f'{os.path.sep.join(sub_directory_path)}{os.path.sep}{name}' full_path = self.project_root_folder / os.path.sep.join( sub_directory_path) / name return full_path, from_project_root return None, None
def load_tracks(self): """Load tracks into AbletonTrack src.""" tracks = get_element(self.root, 'LiveSet.Tracks') for track in tracks: self.tracks.append(AbletonTrack(track))