Browse Source

support for patroneo groups

master
Nils 4 years ago
parent
commit
9125a9a9fa
  1. 8
      template/engine/api.py
  2. 31
      template/engine/sequencer.py

8
template/engine/api.py

@ -78,7 +78,7 @@ class Callbacks(object):
def _dataChanged(self): def _dataChanged(self):
"""Only called from within the callbacks. """Only called from within the callbacks or template api.
This is about data the user cares about. In other words this is the indicator if you need This is about data the user cares about. In other words this is the indicator if you need
to save again. to save again.
@ -130,7 +130,8 @@ class Callbacks(object):
def _setPlaybackTicks(self): def _setPlaybackTicks(self):
"""This gets called very very often. Any connected function needs to watch closely """This gets called very very often (~60 times per second).
Any connected function needs to watch closely
for performance issues""" for performance issues"""
ppqn = cbox.Transport.status().pos_ppqn ppqn = cbox.Transport.status().pos_ppqn
status = playbackStatus() status = playbackStatus()
@ -237,12 +238,13 @@ class Callbacks(object):
"""New track, delete track, reorder """New track, delete track, reorder
Sent the current track order as list of ids, combined with their structure. Sent the current track order as list of ids, combined with their structure.
This is also used when tracks get created or deleted, also on initial load. This is also used when tracks get created or deleted, also on initial load.
This also includes the pattern.
""" """
session.data.updateJackMetadataSorting() session.data.updateJackMetadataSorting()
lst = [track.export() for track in session.data.tracks] lst = [track.export() for track in session.data.tracks]
for func in self.numberOfTracksChanged: for func in self.numberOfTracksChanged:
func(lst) func(lst)
self._dataChanged() #includes _historyChanged
def _metronomeChanged(self): def _metronomeChanged(self):
"""returns a dictionary with meta data such as the mute-state and the track name""" """returns a dictionary with meta data such as the mute-state and the track name"""

31
template/engine/sequencer.py

@ -88,6 +88,7 @@ class Score(Data):
#Tracks #Tracks
def addTrack(self, name:str=""): def addTrack(self, name:str=""):
"""Create and add a new track. Not an existing one"""
track = Score.TrackClass(parentData=self, name=name) track = Score.TrackClass(parentData=self, name=name)
assert track.sequencerInterface assert track.sequencerInterface
self.tracks.append(track) self.tracks.append(track)
@ -96,6 +97,7 @@ class Score(Data):
def deleteTrack(self, track): def deleteTrack(self, track):
track.sequencerInterface.prepareForDeletion() track.sequencerInterface.prepareForDeletion()
self.tracks.remove(track) self.tracks.remove(track)
return track #for undo
def updateJackMetadataSorting(self): def updateJackMetadataSorting(self):
"""Add this to you "tracksChanged" or "numberOfTracksChanged" callback. """Add this to you "tracksChanged" or "numberOfTracksChanged" callback.
@ -105,12 +107,16 @@ class Score(Data):
self.tracks changed and subsequent sorting. Multiple track changes in a row are common, self.tracks changed and subsequent sorting. Multiple track changes in a row are common,
therefore the place to update jack order is in the API, where the new track order is also therefore the place to update jack order is in the API, where the new track order is also
sent to the UI. sent to the UI.
We also check if the track is 'deactivated' by probing track.cboxMidiOutUuid.
Patroneo uses prepareForDeletion to deactive the tracks standalone track but keeps the
interface around for later use.
""" """
order = {portName:index for index, portName in enumerate(track.sequencerInterface.cboxPortName() for track in self.tracks)} order = {portName:index for index, portName in enumerate(track.sequencerInterface.cboxPortName() for track in self.tracks if track.sequencerInterface.cboxMidiOutUuid)}
try: try:
cbox.JackIO.Metadata.set_all_port_order(order) cbox.JackIO.Metadata.set_all_port_order(order)
except Exception as e: #No Jack Meta Data except Exception as e: #No Jack Meta Data or Error with ports.
logger.error(e) logger.error(e)
def trackById(self, trackId:int): def trackById(self, trackId:int):
@ -195,6 +201,8 @@ class _Interface(object):
def _isNameAvailable(self, name:str): def _isNameAvailable(self, name:str):
"""Check if the name is free. If not increment""" """Check if the name is free. If not increment"""
name = ''.join(ch for ch in name if ch.isalnum() or ch in (" ", "_", "-")) #sanitize
name = " ".join(name.split()) #remove double spaces
while name in [tr.sequencerInterface.name for tr in self.parentData.tracks]: while name in [tr.sequencerInterface.name for tr in self.parentData.tracks]:
beforeLastChar = name[-2] beforeLastChar = name[-2]
lastChar = name[-1] lastChar = name[-1]
@ -319,7 +327,7 @@ class SequencerInterface(_Interface): #Basically the midi part of a track.
def _processAfterInit(self): def _processAfterInit(self):
#Create midi out and cbox track #Create midi out and cbox track
logger.info("Creating empty SequencerInterface instance") logger.info(f"Creating empty SequencerInterface instance for {self._name}")
super()._processAfterInit() super()._processAfterInit()
self.cboxMidiOutUuid = cbox.JackIO.create_midi_output(self._name) self.cboxMidiOutUuid = cbox.JackIO.create_midi_output(self._name)
self.calfboxTrack.set_external_output(self.cboxMidiOutUuid) self.calfboxTrack.set_external_output(self.cboxMidiOutUuid)
@ -346,6 +354,7 @@ class SequencerInterface(_Interface): #Basically the midi part of a track.
def name(self, value): def name(self, value):
if not value in (track.sequencerInterface.name for track in self.parentData.tracks): if not value in (track.sequencerInterface.name for track in self.parentData.tracks):
self._name = self._isNameAvailable(value) self._name = self._isNameAvailable(value)
if self.cboxMidiOutUuid: #we could be deactivated
cbox.JackIO.rename_midi_output(self.cboxMidiOutUuid, self._name) cbox.JackIO.rename_midi_output(self.cboxMidiOutUuid, self._name)
def cboxPortName(self)->str: def cboxPortName(self)->str:
@ -360,7 +369,14 @@ class SequencerInterface(_Interface): #Basically the midi part of a track.
undo. That is why we bother setting calfboxTrack to None undo. That is why we bother setting calfboxTrack to None
again. again.
""" """
if not self.calfboxTrack: #maybe non-template part deactivated it, like Patroneo groups
return
try:
portlist = cbox.JackIO.get_connected_ports(self.cboxPortName()) portlist = cbox.JackIO.get_connected_ports(self.cboxPortName())
except: #port not found.
portlist = []
self._beforeDeleteThisJackMidiWasConnectedTo = portlist self._beforeDeleteThisJackMidiWasConnectedTo = portlist
self.calfboxTrack.set_external_output("") self.calfboxTrack.set_external_output("")
@ -411,6 +427,15 @@ class SequencerInterface(_Interface): #Basically the midi part of a track.
self._subtracks[key].setSubtrack(blobs) self._subtracks[key].setSubtrack(blobs)
def deleteSubtrack(self, key):
"""Remove a subtrack.
Return for a potential undo"""
self._subtracks[key].prepareForDeletion()
toDelete = self._subtracks[key]
del self._subtracks[key]
return toDelete
#Save / Load / Export #Save / Load / Export
def serialize(self)->dict: def serialize(self)->dict:
"""Generate Data to save as json""" """Generate Data to save as json"""

Loading…
Cancel
Save