From 1fef445f5af32d23798716f6ea0c8b62fa98457a Mon Sep 17 00:00:00 2001 From: Nils <> Date: Fri, 10 Apr 2020 23:02:53 +0200 Subject: [PATCH] try to fix looping. not there yet --- engine/api.py | 61 +++++++++++++++++++++++++++++++++----------------- engine/main.py | 15 +++++++++---- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/engine/api.py b/engine/api.py index 3333f05..e875c0b 100644 --- a/engine/api.py +++ b/engine/api.py @@ -200,9 +200,39 @@ def startEngine(nsmClient): for track in session.data.tracks: callbacks._trackMetaDataChanged(track) #for colors, scale and simpleNoteNames - session.data.buildAllTracks() + session.data.buildAllTracks(buildSongDuration=True) #will set to max track length, we always have a song duration. + + updatePlayback() + + +def _loopOff(): + session.data.buildSongDuration() #no parameter removes the loop + updatePlayback() + session.inLoopMode = None + callbacks._loopChanged(None, None, None) + +def _loopNow(): + now = cbox.Transport.status().pos_ppqn + _setLoop(now) + +def _setLoop(loopMeasureAroundPpqn): + if loopMeasureAroundPpqn < 0: + _loopOff() + return + + loopStart, loopEnd = session.data.buildSongDuration(loopMeasureAroundPpqn) updatePlayback() + session.inLoopMode = (loopStart, loopEnd) + + assert loopStart <= loopMeasureAroundPpqn < loopEnd + if not playbackStatus(): + cbox.Transport.play() + + oneMeasureInTicks = (session.data.howManyUnits * session.data.whatTypeOfUnit) / session.data.subdivisions + + measurenumber, rest = divmod(loopStart, oneMeasureInTicks) + callbacks._loopChanged(int(measurenumber), loopStart, loopEnd) def toggleLoop(): """Plays the current measure as loop. @@ -211,26 +241,9 @@ def toggleLoop(): session.inLoopMode is a tuple (start, end) """ if session.inLoopMode: - session.data.buildSongDuration() #no parameter removes the loop - updatePlayback() - session.inLoopMode = None - callbacks._loopChanged(None, None, None) + _loopOff() else: - now = loopMeasureAroundPpqn=cbox.Transport.status().pos_ppqn - loopStart, loopEnd = session.data.buildSongDuration(now) - - updatePlayback() - session.inLoopMode = (loopStart, loopEnd) - - assert loopStart <= now < loopEnd - if not playbackStatus(): - cbox.Transport.play() - - oneMeasureInTicks = (session.data.howManyUnits * session.data.whatTypeOfUnit) / session.data.subdivisions - - measurenumber, rest = divmod(loopStart, oneMeasureInTicks) - callbacks._loopChanged(int(measurenumber), loopStart, loopEnd) - + _loopNow() def seek(value): """override template one, which does not have a loop""" @@ -262,6 +275,8 @@ def set_whatTypeOfUnit(ticks): if session.data.whatTypeOfUnit == ticks: return session.data.whatTypeOfUnit = ticks session.data.buildAllTracks() + if session.inLoopMode: + _loopNow() updatePlayback() callbacks._timeSignatureChanged() @@ -270,6 +285,8 @@ def set_howManyUnits(value): if session.data.howManyUnits == value: return session.data.howManyUnits = value session.data.buildAllTracks() + if session.inLoopMode: + _loopNow() updatePlayback() callbacks._timeSignatureChanged() @@ -278,6 +295,8 @@ def set_subdivisions(value): if session.data.subdivisions == value: return session.data.subdivisions = value session.data.buildAllTracks() + if session.inLoopMode: + _loopNow() updatePlayback() callbacks._subdivisionsChanged() @@ -293,6 +312,8 @@ def convert_subdivisions(value, errorHandling): callbacks._patternChanged(tr) else: callbacks._subdivisionsChanged() #to reset the GUI value back to the working one. + if session.inLoopMode: + _loopNow() return result def set_numberOfMeasures(value): diff --git a/engine/main.py b/engine/main.py index e494c56..f9c1f83 100644 --- a/engine/main.py +++ b/engine/main.py @@ -149,15 +149,22 @@ class Data(template.engine.sequencer.Score): return True - def buildAllTracks(self): - """Includes all patterns. - This still needs to be followed by buildSongDuration. Explicit is better than implicit.""" + def buildAllTracks(self, buildSongDuration=False): + """Includes all patterns. + + buildSongDuration is True at least once in the programs life time, on startup. + If True it will reset the loop. The api calls buildSongDuration directly when it sets + the loop. + """ for track in self.tracks: track.pattern.buildExportCache() track.buildTrack() - self.buildSongDuration() + if buildSongDuration: + self.buildSongDuration() def buildSongDuration(self, loopMeasureAroundPpqn=None): + """Loop does not reset automatically. We keep it until explicitely changed. + If we do not have a loop the song duration is already maxTrackDuration, no update needed.""" oneMeasureInTicks = (self.howManyUnits * self.whatTypeOfUnit) / self.subdivisions oneMeasureInTicks = int(oneMeasureInTicks) maxTrackDuration = self.numberOfMeasures * oneMeasureInTicks