def __init__(self, app): self._app = app self._playlist = [] self._shuffle_list = [] self.active_preset = None self.next_preset = None self._playlist_data = None self._loader = PatternLoader(self) self.available_pattern_classes = self._loader.all_patterns() self.last_active_preset = self._app.settings.get("last-preset", None) self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.name = app.args.playlist if self.name is None: self.name = self._app.settings.get("mixer").get( "last_playlist", None) if self.name is None or self.name == "": self.filetype = "playlist" self.filename = "" self.initialized = False else: filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, ".json"])) JSONDict.__init__(self, 'playlist', filepath, True) self.open()
def open(self): try: self.load(False) except ValueError: print "Error loading %s" % self.filename return False self._loader = PatternLoader(self) self._preset_classes = self._loader.load() self._playlist_file_version = self.data.get( "file-version", 1) # Version 1 didn't have this key self._playlist_data = self.data.get('playlist', []) self._playlist = [] self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.generate_playlist() self.initialized = True self.changed() return True
def open(self): try: self.load(False) except ValueError: print "Error loading %s" % self.filename return False self._loader = PatternLoader(self) self.available_pattern_classes = self._loader.all_patterns() self._playlist_file_version = self.data.get("file-version", 1) # Version 1 didn't have this key self._playlist_data = self.data.get('playlist', []) self._playlist = [] self.last_active_preset = self._app.settings.get("last-preset", None) self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.generate_playlist() self.initialized = True self.changed() return True
def __init__(self, app): self._app = app self._playlist = [] self._shuffle_list = [] self.active_preset = None self.next_preset = None self._playlist_data = None self._loader = PatternLoader(self) self.available_pattern_classes = self._loader.all_patterns() self.last_active_preset = self._app.settings.get("last-preset", None) self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.name = app.args.playlist if self.name is None: self.name = self._app.settings.get("mixer").get("last_playlist", None) if self.name is None or self.name == "": self.filetype = "playlist" self.filename = "" self.initialized = False else: filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, ".json"])) JSONDict.__init__(self, 'playlist', filepath, True) self.open()
class Playlist(JSONDict): """ Manages the available presets and the current playlist of presets. """ def changed(self): # Ugh. At boot-up the emit() method isn't present on Qt signals. This is # a hack around that. emit = getattr(self._app.playlist_changed, 'emit', None) if emit is not None: emit() def __init__(self, app): self._app = app self._playlist = [] self._shuffle_list = [] self.active_preset = None self.next_preset = None self._playlist_data = None self._loader = PatternLoader(self) self.available_pattern_classes = self._loader.all_patterns() self.last_active_preset = self._app.settings.get("last-preset", None) self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.name = app.args.playlist if self.name is None: self.name = self._app.settings.get("mixer").get( "last_playlist", None) if self.name is None or self.name == "": self.filetype = "playlist" self.filename = "" self.initialized = False else: filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, ".json"])) JSONDict.__init__(self, 'playlist', filepath, True) self.open() def create_new(self, filename): if self.initialized: self.save() self.clear_playlist() self.data = dict() self.set_filename(filename) self.load(True) self.open() self.data["file-version"] = 2 def set_filename(self, filename): self.name = os.path.split(filename)[1].replace(".json", "") self.filename = filename def open(self): try: self.load(False) except ValueError: print("Error loading %s" % self.filename) return False self._playlist_file_version = self.data.get( "file-version", 1) # Version 1 didn't have this key self._playlist_data = self.data.get('playlist', []) self._playlist = [] self.active_preset = None self.next_preset = None self.generate_playlist() self.initialized = True self.changed() return True def get_preset_from_json_data(self, data, slug): inst = self._loader.all_patterns()[data['classname']][1](self._app, slug) inst._reset() return inst def load_preset_from_file(self, preset_slug): # TODO: We should have a library of functions for getting common app paths. preset_path = os.path.join(os.getcwd(), "data", "presets", "".join([preset_slug, ".json"])) preset_data = None if os.path.exists(preset_path): try: with open(preset_path, "r") as f: preset_data = json.load(f) except: log.warn("Error loading data from preset %s" % preset_path) else: log.warn("Pattern %s could not be found, skipping..." % preset_slug) return preset_data def generate_playlist(self): log.info("Populating playlist (version %d)..." % self._playlist_file_version) if len(self._playlist_data) == 0: self._playlist = [] if self._playlist_file_version != 2: # Uncomment the block below to upgrade a legacy playlist # log.error("Upgrading this playlist to version 2!") # # new_playlist_data = deepcopy(self.data) # new_playlist_data["playlist"] = list() # new_playlist_data["file-version"] = 2 # # for entry in self._playlist_data: # if entry['classname'] in self._loader.all_patterns(): # slug = slugify(entry['name']) # filepath = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) # if os.path.exists(filepath): # slug += "-1" # filepath = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) # with open(filepath, "w") as f: # entry["file-type"] = "preset" # entry["file-version"] = 1 # json.dump(entry, f, indent=4, sort_keys=True) # # new_playlist_data['playlist'].append(slug) # # # Uncomment the following to generate a version-2 playlist from a version-1 playlist # filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, "_separate_presets", ".json"])) # with open(filepath, "w") as f: # json.dump(new_playlist_data, f, indent=4, sort_keys=True) log.error("Upgrade this playlist to version 2!") return # TODO: This is kind of dumb, we have to load the JSON twice -- once to figure out # what class the preset is, then again in the class (as JSONDict) for preset_slug in self._playlist_data: preset_data = self.load_preset_from_file(preset_slug) if preset_data and preset_data[ 'classname'] in self._loader.all_patterns(): self._playlist.append( self.get_preset_from_json_data(preset_data, preset_slug)) self.initialized = True self.playlist_mutated() log.info("Done") return self._playlist # TODO: This is ta temporary hack; we should actually just watch the dir for changes and keep a cache def get_all_preset_slugs(self): slugs = [] for f in os.listdir(os.path.join(os.getcwd(), "data", "presets")): slug, ext = os.path.splitext(f) if ext == ".json": slugs.append(slug) return slugs # TODO: This is ta temporary hack; we should actually just watch the dir for changes and keep a cache def get_all_preset_names(self): names = [] preset_root = os.path.join(os.getcwd(), "data", "presets") for f in os.listdir(preset_root): slug, ext = os.path.splitext(f) try: preset_path = os.path.join(preset_root, f) with open(preset_path, "r") as f: preset_data = json.load(f) preset_name = preset_data.get("name", None) if preset_name: names.append(preset_name) else: log.warn( "Skipping preset %s because it doesn't have a name" % preset_path) except: log.error("Could not load preset %s" % slug) return names @QtCore.pyqtSlot() def playlist_mutated(self): """ This should get called when the playlist is mutated in some way (presets dragged around, dis/enabled, deleted, duplicated, added, etc) It also gets called from advance() at the end of a transition, etc """ if self.active_preset is None: if self.last_active_preset is not None: self.active_preset = self.get_preset_by_name( self.last_active_preset) self.last_active_preset = None if self.active_preset is None: if len(self._playlist) > 0: self.active_preset = self._playlist[0] else: # Nothing going on here! self.next_preset = None return # Check if we just deleted the active preset if self.active_preset not in self._playlist: self.active_preset = self.next_preset self.update_next_preset() # Generate the shuffle list if self._shuffle: self.generate_shuffle() if self.next_preset is None: # Initialize _next. We probably went from a playlist of length 0 to 1. if self._shuffle and len(self._playlist) > 1: self.next_preset = self._playlist[self._shuffle_list.pop()] elif len(self._playlist) == 0: self.next_preset = None elif len(self._playlist) == 1: self.next_preset = self.active_preset else: self.next_preset = self._playlist[1] else: # Update the next pointer self.update_next_preset() def update_next_preset(self): if len(self._playlist) == 0: self.next_preset = None self.active_preset = None elif len(self._playlist) == 1: if self.active_preset is None: self.active_preset = self._playlist[0] self.next_preset = self.active_preset else: active_idx = self._playlist.index(self.active_preset) candidate = (active_idx + 1) % len(self._playlist) while not self._playlist[candidate].parameter( 'allow-playback').get(): candidate = (candidate + 1) % len(self._playlist) # This should never happen but I don't like infinite loops if candidate == active_idx: break self.next_preset = self._playlist[candidate] self.changed() def shuffle_mode(self, shuffle=True): """ Enables or disables playlist shuffle """ self._shuffle = shuffle self.update_next_preset() def generate_shuffle(self): """ Creates a shuffle list """ self._shuffle_list = list(range(len(self._playlist))) if len(self._shuffle_list) == 0: return # Remove disallowed presets from the shuffle list self._shuffle_list = [ idx for idx in self._shuffle_list if self._playlist[idx].parameter('allow-playback').get() ] random.shuffle(self._shuffle_list) active_idx = self._playlist.index(self.active_preset) if active_idx in self._shuffle_list: self._shuffle_list.remove(active_idx) def reload_presets(self): """Attempts to reload all preset classes in the playlist""" self.available_pattern_classes = self._loader.reload() while len(self._playlist) > 0: inst = self._playlist.pop(0) inst.clear_parameters() del inst gc.collect() self.generate_playlist() self.changed() def disable_presets_by_class(self, class_name): for p in self._playlist: if p.__class__.__name__ == class_name: p.disabled = True log.error("Disabling %s because the preset is crashing." % p.name()) def module_reloaded(self, module_name): to_rebuild = [(i, p) for (i, p) in enumerate(self._playlist) if p.__module__ == module_name] for idx, preset in to_rebuild: preset_data = self.load_preset_from_file(preset.slug()) new_inst = self.get_preset_from_json_data(preset_data, preset.slug()) self._playlist[idx] = new_inst if self.active_preset is preset: self.active_preset = new_inst if self.next_preset is preset: self.next_preset = new_inst def save(self, save_all_presets=True): if not self.initialized: return log.info("Saving playlist") playlist = [] for preset in self._playlist: playlist.append(preset.slug()) if save_all_presets: preset.save() self.data['playlist'] = playlist self.data["file-version"] = 2 # Superclass write to file self._app.settings.get("mixer")["last_playlist"] = self.name self._app.settings["last-preset"] = self.active_preset.name() JSONDict.save(self) def get(self): return self._playlist def advance(self): """ Advances the playlist """ self.active_preset = self.next_preset if self._shuffle: if len(self._shuffle_list) == 0: self.generate_shuffle() self.next_preset = self._playlist[self._shuffle_list.pop()] else: self.update_next_preset() self.changed() def __len__(self): return len(self._playlist) def get_active_preset(self): if len(self._playlist) == 0: return None else: return self.active_preset def get_next_preset(self): if len(self._playlist) == 0: return None else: return self.next_preset def get_preset_by_index(self, idx): if len(self._playlist) == 0: return None else: return self._playlist[idx] def get_preset_by_name(self, name): for preset in self._playlist: if preset.name() == name: return preset return None def set_active_preset_by_name(self, name): #TODO: Support transitions other than jump cut for i, preset in enumerate(self._playlist): if preset.name() == name: preset._reset() self.active_preset = preset self._app.mixer._elapsed = 0.0 # Hack self.update_next_preset() return def set_next_preset_by_name(self, name): for i, preset in enumerate(self._playlist): if preset.name() == name: self._next = preset self.changed() return def reorder_playlist_by_names(self, names): """ Pass in a list of preset names to reorder. """ current = dict([(preset.name(), preset) for preset in self._playlist]) new = [] for name in names: new.append(current[name]) self._playlist = new self.playlist_mutated() self.changed() def get_available_patterns(self): self.available_pattern_classes = self._loader.all_patterns() return sorted(self.available_pattern_classes.keys()) def preset_name_exists(self, name): return True if name in [p.name() for p in self._playlist] else False def add_existing_preset(self, name): # TODO: Should we support multiple instances of the same preset on a playlist? for p in self._playlist: if p.name() == name: log.error("Cannot add a preset to the same playlist twice!") return False slug = slugify(name) preset_data = {} preset_path = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) try: with open(preset_path, "r") as f: preset_data = json.load(f) except: log.error("Could not load preset %s" % name) return False self._playlist.append(self.get_preset_from_json_data( preset_data, slug)) if self.active_preset == self.next_preset: self.update_next_preset() self.changed() return True # TODO: Fix this to support slugs def add_preset(self, classname, name, idx=None): """ Adds a new preset instance to the playlist. Classname must be a currently loaded preset class. Name must be unique. If idx is specified, the preset will be inserted at the position idx, else it will be appended to the end of the playlist. """ if classname not in list(self.available_pattern_classes.keys()): log.error("Tried to add nonexistent preset class %s" % classname) return False if self.preset_name_exists(name): log.error("Tried to add a preset that already exists: %s" % name) return False inst = self.available_pattern_classes[classname][1](self._app, slugify(name)) inst.set_name(name) inst.save() inst._reset() if idx is not None: self._playlist.insert(idx, inst) else: self._playlist.append(inst) if self.active_preset == self.next_preset: self.update_next_preset() self.changed() return True def remove_preset(self, name): """ Removes an existing instance from the playlist """ if not self.preset_name_exists(name): return False pl = [(i, p) for i, p in enumerate(self._playlist) if p.name() == name] assert len(pl) == 1 self._playlist.remove(pl[0][1]) self.playlist_mutated() self.changed() return True def clone_preset(self, old_name): old = self.get_preset_by_name(old_name) classname = old.__class__.__name__ new_name = old_name candidate = new_name i = 2 while self.get_preset_by_name(candidate): candidate = new_name + " (" + str(i) + ")" i += 1 new_name = candidate self.add_preset(classname, new_name, self._playlist.index(old) + 1) new = self.get_preset_by_name(new_name) for name, param in old.get_parameters().items(): new.parameter(name).set_from_str(param.get_as_str()) self.playlist_mutated() self.changed() def clear_playlist(self): self._playlist = [] self.playlist_mutated() self.changed() def rename_preset(self, old_name, new_name): pl = [i for i, p in enumerate(self._playlist) if p.name() == old_name] if len(pl) != 1: return False inst = self._playlist[pl[0]] inst.set_name(new_name) inst.save() self.changed() def generate_default_playlist(self): """ Wipes out the existing playlist and adds one instance of each preset """ self.clear_playlist() for cn in list(self.available_pattern_classes.keys()): name = cn + "-1" inst = self.available_pattern_classes[cn][1](self._app.mixer, name=name) inst.setup() self._playlist.append(inst) self.playlist_mutated() self.changed() def suggest_preset_name(self, classname): """ Returns an unused preset name based on the classname, in the form "Classname-N", where N is an integer. """ i = 1 name = classname + "-" + str(i) while self.preset_name_exists(name): i += 1 name = classname + "-" + str(i) return name
class Playlist(JSONDict): """ Manages the available presets and the current playlist of presets. """ def changed(self): # Ugh. At boot-up the emit() method isn't present on Qt signals. This is # a hack around that. emit = getattr(self._app.playlist_changed, 'emit', None) if emit is not None: emit() def __init__(self, app): self._app = app self._playlist = [] self._shuffle_list = [] self.active_preset = None self.next_preset = None self._playlist_data = None self.name = app.args.playlist if self.name is None: self.name = self._app.settings.get("mixer").get("last_playlist", None) if self.name is None or self.name == "": self.filetype = "playlist" self.filename = "" self.initialized = False else: filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, ".json"])) JSONDict.__init__(self, 'playlist', filepath, True) self.open() def create_new(self, filename): if self.initialized: self.save() self.clear_playlist() self.data = dict() self.set_filename(filename) self.load(True) self.open() self.data["file-version"] = 2 def set_filename(self, filename): self.name = os.path.split(filename)[1].replace(".json", "") self.filename = filename def open(self): try: self.load(False) except ValueError: print "Error loading %s" % self.filename return False self._loader = PatternLoader(self) self.available_pattern_classes = self._loader.all_patterns() self._playlist_file_version = self.data.get("file-version", 1) # Version 1 didn't have this key self._playlist_data = self.data.get('playlist', []) self._playlist = [] self.last_active_preset = self._app.settings.get("last-preset", None) self.active_preset = None self.next_preset = None self._shuffle = self._app.settings['mixer']['shuffle'] self._shuffle_list = [] self.generate_playlist() self.initialized = True self.changed() return True def get_preset_from_json_data(self, data, slug): inst = self._loader.all_patterns()[data['classname']][1](self._app, slug) inst._reset() return inst def load_preset_from_file(self, preset_slug): # TODO: We should have a library of functions for getting common app paths. preset_path = os.path.join(os.getcwd(), "data", "presets", "".join([preset_slug, ".json"])) preset_data = None if os.path.exists(preset_path): try: with open(preset_path, "r") as f: preset_data = json.load(f) except: log.warn("Error loading data from preset %s" % preset_path) else: log.warn("Pattern %s could not be found, skipping..." % preset_slug) return preset_data def generate_playlist(self): log.info("Populating playlist (version %d)..." % self._playlist_file_version) if len(self._playlist_data) == 0: self._playlist = [] if self._playlist_file_version != 2: # Uncomment the block below to upgrade a legacy playlist # log.error("Upgrading this playlist to version 2!") # # new_playlist_data = deepcopy(self.data) # new_playlist_data["playlist"] = list() # new_playlist_data["file-version"] = 2 # # for entry in self._playlist_data: # if entry['classname'] in self._loader.all_patterns(): # slug = slugify(entry['name']) # filepath = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) # if os.path.exists(filepath): # slug += "-1" # filepath = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) # with open(filepath, "w") as f: # entry["file-type"] = "preset" # entry["file-version"] = 1 # json.dump(entry, f, indent=4, sort_keys=True) # # new_playlist_data['playlist'].append(slug) # # # Uncomment the following to generate a version-2 playlist from a version-1 playlist # filepath = os.path.join(os.getcwd(), "data", "playlists", "".join([self.name, "_separate_presets", ".json"])) # with open(filepath, "w") as f: # json.dump(new_playlist_data, f, indent=4, sort_keys=True) log.error("Upgrade this playlist to version 2!") return # TODO: This is kind of dumb, we have to load the JSON twice -- once to figure out # what class the preset is, then again in the class (as JSONDict) for preset_slug in self._playlist_data: preset_data = self.load_preset_from_file(preset_slug) if preset_data and preset_data['classname'] in self._loader.all_patterns(): self._playlist.append(self.get_preset_from_json_data(preset_data, preset_slug)) self.initialized = True self.playlist_mutated() log.info("Done") return self._playlist # TODO: This is ta temporary hack; we should actually just watch the dir for changes and keep a cache def get_all_preset_slugs(self): slugs = [] for f in os.listdir(os.path.join(os.getcwd(), "data", "presets")): slug, ext = os.path.splitext(f) if ext == ".json": slugs.append(slug) return slugs # TODO: This is ta temporary hack; we should actually just watch the dir for changes and keep a cache def get_all_preset_names(self): names = [] preset_root = os.path.join(os.getcwd(), "data", "presets") for f in os.listdir(preset_root): slug, ext = os.path.splitext(f) try: preset_path = os.path.join(preset_root, f) with open(preset_path, "r") as f: preset_data = json.load(f) preset_name = preset_data.get("name", None) if preset_name: names.append(preset_name) else: log.warn("Skipping preset %s because it doesn't have a name" % preset_path) except: log.error("Could not load preset %s" % slug) return names @QtCore.Slot() def playlist_mutated(self): """ This should get called when the playlist is mutated in some way (presets dragged around, dis/enabled, deleted, duplicated, added, etc) It also gets called from advance() at the end of a transition, etc """ if self.active_preset is None: if self.last_active_preset is not None: self.active_preset = self.get_preset_by_name(self.last_active_preset) self.last_active_preset = None if self.active_preset is None: if len(self._playlist) > 0: self.active_preset = self._playlist[0] else: # Nothing going on here! self.next_preset = None return # Check if we just deleted the active preset if self.active_preset not in self._playlist: self.active_preset = self.next_preset self.update_next_preset() # Generate the shuffle list if self._shuffle: self.generate_shuffle() if self.next_preset is None: # Initialize _next. We probably went from a playlist of length 0 to 1. if self._shuffle and len(self._playlist) > 1: self.next_preset = self._playlist[self._shuffle_list.pop()] elif len(self._playlist) == 0: self.next_preset = None elif len(self._playlist) == 1: self.next_preset = self.active_preset else: self.next_preset = self._playlist[1] else: # Update the next pointer self.update_next_preset() def update_next_preset(self): if len(self._playlist) == 0: self.next_preset = None self.active_preset = None elif len(self._playlist) == 1: if self.active_preset is None: self.active_preset = self._playlist[0] self.next_preset = self.active_preset else: active_idx = self._playlist.index(self.active_preset) candidate = (active_idx + 1) % len(self._playlist) while not self._playlist[candidate].parameter('allow-playback').get(): candidate = (candidate + 1) % len(self._playlist) # This should never happen but I don't like infinite loops if candidate == active_idx: break self.next_preset = self._playlist[candidate] self.changed() def shuffle_mode(self, shuffle=True): """ Enables or disables playlist shuffle """ self._shuffle = shuffle self.update_next_preset() def generate_shuffle(self): """ Creates a shuffle list """ self._shuffle_list = range(len(self._playlist)) if len(self._shuffle_list) == 0: return # Remove disallowed presets from the shuffle list self._shuffle_list = [idx for idx in self._shuffle_list if self._playlist[idx].parameter('allow-playback').get()] random.shuffle(self._shuffle_list) active_idx = self._playlist.index(self.active_preset) if active_idx in self._shuffle_list: self._shuffle_list.remove(active_idx) def reload_presets(self): """Attempts to reload all preset classes in the playlist""" self.available_pattern_classes = self._loader.reload() while len(self._playlist) > 0: inst = self._playlist.pop(0) inst.clear_parameters() del inst gc.collect() self.generate_playlist() self.changed() def disable_presets_by_class(self, class_name): for p in self._playlist: if p.__class__.__name__ == class_name: p.disabled = True log.error("Disabling %s because the preset is crashing." % p.name()) def module_reloaded(self, module_name): to_rebuild = [(i, p) for (i, p) in enumerate(self._playlist) if p.__module__ == module_name] for idx, preset in to_rebuild: preset_data = self.load_preset_from_file(preset.slug()) new_inst = self.get_preset_from_json_data(preset_data, preset.slug()) self._playlist[idx] = new_inst if self.active_preset is preset: self.active_preset = new_inst if self.next_preset is preset: self.next_preset = new_inst def save(self, save_all_presets=True): log.info("Saving playlist") playlist = [] for preset in self._playlist: playlist.append(preset.slug()) if save_all_presets: preset.save() self.data['playlist'] = playlist # Superclass write to file self._app.settings.get("mixer")["last_playlist"] = self.name JSONDict.save(self) def get(self): return self._playlist def advance(self): """ Advances the playlist """ self.active_preset = self.next_preset if self._shuffle: if len(self._shuffle_list) == 0: self.generate_shuffle() self.next_preset = self._playlist[self._shuffle_list.pop()] else: self.update_next_preset() self.changed() def __len__(self): return len(self._playlist) def get_active_preset(self): if len(self._playlist) == 0: return None else: return self.active_preset def get_next_preset(self): if len(self._playlist) == 0: return None else: return self.next_preset def get_preset_by_index(self, idx): if len(self._playlist) == 0: return None else: return self._playlist[idx] def get_preset_by_name(self, name): for preset in self._playlist: if preset.name() == name: return preset return None def set_active_preset_by_name(self, name): #TODO: Support transitions other than jump cut for i, preset in enumerate(self._playlist): if preset.name() == name: preset._reset() self.active_preset = preset self._app.mixer._elapsed = 0.0 # Hack self.update_next_preset() return def set_next_preset_by_name(self, name): for i, preset in enumerate(self._playlist): if preset.name() == name: self._next = preset self.changed() return def reorder_playlist_by_names(self, names): """ Pass in a list of preset names to reorder. """ current = dict([(preset.name(), preset) for preset in self._playlist]) new = [] for name in names: new.append(current[name]) self._playlist = new self.playlist_mutated() self.changed() def get_available_patterns(self): self.available_pattern_classes = self._loader.all_patterns() return sorted(self.available_pattern_classes.keys()) def preset_name_exists(self, name): return True if name in [p.name() for p in self._playlist] else False def add_existing_preset(self, name): # TODO: Should we support multiple instances of the same preset on a playlist? for p in self._playlist: if p.name() == name: log.error("Cannot add a preset to the same playlist twice!") return False slug = slugify(name) preset_data = {} preset_path = os.path.join(os.getcwd(), "data", "presets", "".join([slug, ".json"])) try: with open(preset_path, "r") as f: preset_data = json.load(f) except: log.error("Could not load preset %s" % name) return False self._playlist.append(self.get_preset_from_json_data(preset_data, slug)) if self.active_preset == self.next_preset: self.update_next_preset() self.changed() return True # TODO: Fix this to support slugs def add_preset(self, classname, name, idx=None): """ Adds a new preset instance to the playlist. Classname must be a currently loaded preset class. Name must be unique. If idx is specified, the preset will be inserted at the position idx, else it will be appended to the end of the playlist. """ if classname not in self.available_pattern_classes.keys(): log.error("Tried to add nonexistent preset class %s" % classname) return False if self.preset_name_exists(name): log.error("Tried to add a preset that already exists: %s" % name) return False inst = self.available_pattern_classes[classname][1](self._app, slugify(name)) inst.set_name(name) inst.save() inst._reset() if idx is not None: self._playlist.insert(idx, inst) else: self._playlist.append(inst) if self.active_preset == self.next_preset: self.update_next_preset() self.changed() return True def remove_preset(self, name): """ Removes an existing instance from the playlist """ if not self.preset_name_exists(name): return False pl = [(i, p) for i, p in enumerate(self._playlist) if p.name() == name] assert len(pl) == 1 self._playlist.remove(pl[0][1]) self.playlist_mutated() self.changed() return True def clone_preset(self, old_name): old = self.get_preset_by_name(old_name) classname = old.__class__.__name__ new_name = old_name candidate = new_name i = 2 while self.get_preset_by_name(candidate): candidate = new_name + " (" + str(i) + ")" i += 1 new_name = candidate self.add_preset(classname, new_name, self._playlist.index(old) + 1) new = self.get_preset_by_name(new_name) for name, param in old.get_parameters().iteritems(): new.parameter(name).set_from_str(param.get_as_str()) self.playlist_mutated() self.changed() def clear_playlist(self): self._playlist = [] self.playlist_mutated() self.changed() def rename_preset(self, old_name, new_name): pl = [i for i, p in enumerate(self._playlist) if p.name() == old_name] if len(pl) != 1: return False inst = self._playlist[pl[0]] inst.set_name(new_name) inst.save() self.changed() def generate_default_playlist(self): """ Wipes out the existing playlist and adds one instance of each preset """ self.clear_playlist() for cn in self.available_pattern_classes.keys(): name = cn + "-1" inst = self.available_pattern_classes[cn][1](self._app.mixer, name=name) inst.setup() self._playlist.append(inst) self.playlist_mutated() self.changed() def suggest_preset_name(self, classname): """ Returns an unused preset name based on the classname, in the form "Classname-N", where N is an integer. """ i = 1 name = classname + "-" + str(i) while self.preset_name_exists(name): i += 1 name = classname + "-" + str(i) return name