def _check_if_is_mpe_grouping_track(self): self.mpeGroupedTracksMasterTrackModel = self._check_if_is_mpe_grouping_track_iterator() self.isMPEGroupingTrack = self.mpeGroupedTracksMasterTrackModel is not None log_message("GroupMasterTrackModel created! id:",self.itemId, "is isMPEGroupingTrack:",self.isMPEGroupingTrack, "thamastertrack:",self.mpeGroupedTracksMasterTrackModel) if self.isMPEGroupingTrack: def setDelayedNameChange(): def masterTracksNameChanged(): self.item.name = self.mpeGroupedTracksMasterTrackModel.s_name + " MPEGroup" return True InstanceContainer.add_delayed_callback("renameMPEGroup-"+self.itemModelPointer, masterTracksNameChanged, [], {}) setDelayedNameChange() self.mpeGroupedTracksMasterTrackModel.add_s_name_listener(setDelayedNameChange) def setDelayedColorChange(): def masterTracksColorChanged(): self.item.color = self.mpeGroupedTracksMasterTrackModel.item.color return True InstanceContainer.add_delayed_callback("recolorMPEGroup-" + self.itemModelPointer, masterTracksColorChanged, [], {}) setDelayedColorChange() self.mpeGroupedTracksMasterTrackModel.item.add_color_listener(setDelayedColorChange) return True
def set_output_routing_type_by_types_display_name(self, type_display_name): """ { "returns": "bool", "args": [ { "type": "str", "defaultValue": null, "optional": false, "name": "type_display_name", "str": "" } ], "kwargs": {}, "desc": "Tries to set track's output_routing_type to routing type with display_name value of arg str." } """ itemByName = None for tempRoutingType in self.item.available_output_routing_types: if tempRoutingType.display_name == type_display_name: itemByName = tempRoutingType if itemByName is not None: # log_message("Found, trying to set..") self.item.output_routing_type = itemByName return True else: log_message("[Warning] set_output_routing_type_by_channel_display_name on MidiTrack:", self.itemModelPointer, "can't find output_routing_type with display_name:", type_display_name) return False
def set_input_routing_channel_by_channel_display_name(self, channel_display_name): """ { "returns": "bool", "args": [ { "type": "str", "defaultValue": null, "optional": false, "name": "channel_display_name", "str": "" } ], "kwargs": {}, "desc": "Tries to set track's input_routing_channel to routing channel with display_name value of arg str." } """ itemByName = None for tempRoutingChannel in self.item.available_input_routing_channels: if tempRoutingChannel.display_name == channel_display_name: itemByName = tempRoutingChannel if itemByName is not None: # log_message("Found, trying to set..",itemByName," named:",itemByName.display_name,"on item:",self.itemModelPointer,"named",self.s_name) self.item.input_routing_channel = itemByName return True else: log_message("[Warning] set_input_routing_channel_by_channel_display_name on MidiTrack:", self.itemModelPointer, "can't find input_routing_channel with display_name:", channel_display_name) return False
def _handle_track_list(self): self.item = self.parentItemModel.item.tracks log_message("Weeee, tracks changed! len now:",len(self.item)) tracksToFind = self._trackModels.keys()[:] for x in range(0,len(self.item)): #log_message("Checking itemId:",x) tempTrack = self.item[x] tempTrackImp = str(tempTrack._live_ptr) if tempTrackImp in tracksToFind: #log_message("Track:",x,tempTrack.name,"exists! x!=itemId:",x != self._trackModels[tempTrackImp].itemId) tracksToFind.remove(tempTrackImp) if x != self._trackModels[tempTrackImp].itemId: self._trackModels[tempTrackImp].itemId = x else: #log_message("New track added!") if tempTrack.is_foldable: self._trackModels[tempTrackImp] = GroupMasterTrackModel(tempTrack, x, self) elif tempTrack.has_midi_input: self._trackModels[tempTrackImp] = MidiTrackModel(tempTrack, x, self) else: self._trackModels[tempTrackImp] = TrackModel(tempTrack, x, self) for tempDeletedTrackLptr in tracksToFind: log_message("Found deleted track:", tempDeletedTrackLptr,"had itemId:",self._trackModels[tempDeletedTrackLptr].itemId) self._trackModels[tempDeletedTrackLptr].disconnect() del self._trackModels[tempDeletedTrackLptr]
def add_delayed_callback(self, key, callback, params, keywordParams={}, rewriteExisting=True, delayCycles=1): """ Adds a delayed callback to the queue. Key identifies the callback, params and keywordParams are passed to the callback on calling. If rewriteExisting is true, an existing callback with the key will be overwritten, otherwise the new callback won't be added. delayCycles determines for how many cycles the calling will be delayed. """ if rewriteExisting or key not in self._delayedCallbacks: self._delayedCallbacks[key] = {'func': callback, 'params': params, 'keywordParams': keywordParams, 'delayCycles': delayCycles} else: log_message("Not adding cb to queue, rewriteExisting=False and key:",key,"exists already!")
def __init__(self, c_instance): versionStr = "Live_{0}_{1}_{2}".format(self.application.get_major_version(), self.application.get_minor_version(), self.application.get_bugfix_version()) #Call the ableton.v2.control_surface.control_surface init super(MPE_Util, self).__init__(c_instance) # Initialize the required instances to the InstanceContainer. InstanceContainer.song = self.song InstanceContainer.itemModelDataHandler = ItemModelDataHandler.ItemModelDataHandler("MPE_Util") self.delayedCallbackHandler = DelayedCallbackHandler() InstanceContainer.add_delayed_callback = self.delayedCallbackHandler.add_delayed_callback InstanceContainer.get_delayed_callback_exists = self.delayedCallbackHandler.get_delayed_callback_exists with self.component_guard(): self.songModel = SongModel(self.song) self.parse() log_message("MPE_Util running on",versionStr) self.show_message("MPEUtil loaded!")
def _mix_with_class(self, toMixWithClassName, *args, **kwargs): """ Adds specific functionality to the TrackModel instance. toMixWithClassName is a name of a class from itemmodelmixins package """ if toMixWithClassName in globals(): tempMixedClass = globals()[toMixWithClassName] # log_message("WEEEEE, would mix:",self.itemType, "with:",toMixWithClassName, "class:", tempMixedClass) cls = self.__class__ # self.__class__ = cls.__class__(cls.__name__+"_"+toMixWithClassName, (cls, tempMixedClass), {}) self.__class__ = cls.__class__(cls.__name__, (cls, tempMixedClass), {}) tempMixedClassesInitName = "_" + toMixWithClassName + "_init" if hasattr(self, tempMixedClassesInitName): # log_message("Calling tempMixedClassesInitName:",tempMixedClassesInitName) getattr(self, tempMixedClassesInitName)(*args, **kwargs) else: log_message("[ERROR!] Can't find toMixWithClasses:", toMixWithClassName, "init-method by name:", tempMixedClassesInitName) else: log_message("ERROR! Can't mix with class:", toMixWithClassName, "not found from globals()!")
def _name_changed_callback(self): postfixFound = False if self._listenToPostfixes != None: freshName = self.item.name for tempPostfixRegexStr, tempCallbackFn in self._listenToPostfixes.iteritems(): #log_message("Checking for fresh name: ",freshName, "with regexstatement: ", tempPostfixRegexStr) if not postfixFound: match = re.search(tempPostfixRegexStr, freshName, re.IGNORECASE) if match: log_message("Found match!! command: ",match.group('command'), "and num_arg:", match.group('num_arg')); def delayedCallbackToFixName(newName): self.item.name = newName return True InstanceContainer.add_delayed_callback("CallbackForPostfixNameFix", delayedCallbackToFixName, [match.group('item_name')], {}) postfixFound = True InstanceContainer.add_delayed_callback("CallbackForPostfixMethodCall", tempCallbackFn, [match], {}, delayCycles=2) if not postfixFound: self._update_s_name()
def __init__(self, *a, **kw): super(MidiTrackModel, self).__init__(*a, **kw) self.itemType = "Track.MidiTrack" if self.foundExternalData is not None: log_message("Weeee, track:",self.itemId,self.itemModelPointer,"found external data:",self.foundExternalData) if 'isMPEMasterTrack' in self.foundExternalData and self.foundExternalData['isMPEMasterTrack'] is True: log_message("In externalData for MidiTrackModel:",self.itemModelPointer, "isMpeMasterTrack is found True! setting delayed call.") def callbackForDelayedMPEMasterStatusUpdate(): log_message("Loading a mpeMasterTrack, after delay, calling:", "self.create_mpe_input_tracks(loadingTracks=True)") self.create_mpe_input_tracks(loadingTracks=True) return True InstanceContainer.add_delayed_callback("callbackToLoadMPESubtracksFor"+self.itemModelPointer, callbackForDelayedMPEMasterStatusUpdate, [], {}, delayCycles=2) elif 'isMPESubTrack' in self.foundExternalData and self.foundExternalData['isMPESubTrack'] is True: self._mpeChannelId = self.foundExternalData['_mpeChannelId'] elif 'isGhostMidiInputTrack' in self.foundExternalData and self.foundExternalData['isGhostMidiInputTrack'] is True: log_message("In externalData for MidiTrackModel:", self.itemModelPointer, "isGhostMidiInputTrack is found True! Mixing..") self._mix_with_class("GhostMidiInputTrackMix")
def create_mpe_input_tracks(self, loadingTracks=False, inputTrackCount=None): """ Mixes the MidiTrackModel with MPEMasterTrackMixIn class. loadingTracks is True when a Live set is loaded, inputTrackCount may be given as a parameter, otherwise read from conf. Creates new midi tracks, or loads existing ones, and routes them to act as MPE input channels for this tracks instrument via utilizing the MPESubTrackMixIn class. """ if loadingTracks: existingMpeTracks = [] for tempOldMPESubTrackModelIMP in self.foundExternalData["_mpeSubtracks"]: #log_message("Loading subtrack with imp:",tempOldMPESubTrackModelIMP) if tempOldMPESubTrackModelIMP in InstanceContainer.itemModelDataHandler.loadedItemModelPointersToCurrentItemModels: existingMpeTracks.append( InstanceContainer.itemModelDataHandler.loadedItemModelPointersToCurrentItemModels[ tempOldMPESubTrackModelIMP]) else: log_message("[ERROR!] unable to find old imp:", tempOldMPESubTrackModelIMP, "from loadedImpsToCurrentImps:", InstanceContainer.itemModelDataHandler.loadedItemModelPointersToCurrentItemModels) #How many channels we'll create if inputTrackCount is not None: num_of_input_channels = inputTrackCount else: num_of_input_channels = conf.defaultMpeChannelCount self._mix_with_class("MPEMasterTrackMix") self.item.arm = True if not loadingTracks: tempTrackIdList = [] for x in range(1, num_of_input_channels + 1): tempChannel_id = self.itemId + x InstanceContainer.songModel.item.create_midi_track(tempChannel_id) tempTrackIdList.append((tempChannel_id, x)) def set_mpeSubtrackPhase1(song, channelIdTupleList): for riseChannelId, mpeChannelId in channelIdTupleList: trackItem = song.tracks[riseChannelId] self._add_mpe_subtrack(self.parentItemModel.get_track_model_by_IMP(trackItem._live_ptr), mpeChannelId, creatingTrack=True) return True keyForCallbackPhase1 = "createMpe-Track_" + self.item.name + "_cb_for_phase1" InstanceContainer.add_delayed_callback(keyForCallbackPhase1, set_mpeSubtrackPhase1, (InstanceContainer.songModel.item, tempTrackIdList), {}) else: log_message("Creating mpeMastertrack-stuff, we got self.foundExternalData:", self.foundExternalData) for tempSubtrackModel in existingMpeTracks: self._add_mpe_subtrack(tempSubtrackModel) if conf.utilizeGhostInputTrack: # GhostInputTrack may be utilized to get the Arm -button to be displayed on track in Live's GUI. It is a # midi track with no input and no output. This way the MPE Master track records clips in sync with its input # tracks, and the clips can be fired in sync too. In future, the clips may be simultaneously edited as well # If configured to use the GhostInputTrack, if it isn't utilized already, create it if it doesn't exist, and # set it as input_routing_type when it's ready. if self.item.input_routing_type.display_name != "GhostMidiInput": def updateInputToGhost(): self.set_input_routing_type_by_types_display_name( InstanceContainer.songModel._ghostMidiInputTrack.item.name) if InstanceContainer.songModel._ghostMidiInputTrack is None: InstanceContainer.add_delayed_callback("create_GhostMidiInputTrack", InstanceContainer.songModel._create_ghostMidiInputTrack, [], {}, delayCycles=4) InstanceContainer.songModel.add_ghostMidiInputTrack_listener(updateInputToGhost) elif not hasattr(InstanceContainer.songModel._ghostMidiInputTrack, "itemModelPointer"): InstanceContainer.songModel.add_ghostMidiInputTrack_listener(updateInputToGhost) else: updateInputToGhost() else: self.set_input_routing_type_by_types_display_name(self._mpeControllerInputTypeName) self.item.current_monitoring_state = 2
def callbackForDelayedMPEMasterStatusUpdate(): log_message("Loading a mpeMasterTrack, after delay, calling:", "self.create_mpe_input_tracks(loadingTracks=True)") self.create_mpe_input_tracks(loadingTracks=True) return True