diff --git a/pico-cp/app.py b/pico-cp/app.py index 54b305a..0650c33 100644 --- a/pico-cp/app.py +++ b/pico-cp/app.py @@ -18,7 +18,7 @@ import board, busio, digitalio, analogio, pwmio, displayio, vectorio, time, json, gc, os, supervisor supervisor.runtime.autoreload = False # we write our own files (log + pushed programs); never self-restart -APP_VERSION = "0.0.16" # firmware version (the A/B updater pushes/compares this) +APP_VERSION = "0.0.17" # firmware version (the A/B updater pushes/compares this) try: import rtc # set from the editor's clock SysEx so the log has real timestamps except ImportError: @@ -618,6 +618,7 @@ class App: self.load(self.idx) # reload from source -> discard edits # ---------- modal overlay (save / revert / message) ---------- def _show_saverevert(self): + gc.collect() self._overlay = 'saverevert'; g = self.g_overlay while len(g): g.pop() px, py, pw, ph = 24, 178, WIDTH - 48, 116 @@ -665,6 +666,7 @@ class App: self._tap_log(tx, ty) # else the practice log # ---------- lane editor (tap the instrument name): sound / beats / sub / swing / mute + add / remove ---------- def _show_laneedit(self, li): + gc.collect() self._overlay = 'lane'; self._edit_li = li; self._draw_laneedit() def _draw_laneedit(self): li = self._edit_li; L = self.lanes[li]; g = self.g_overlay @@ -736,6 +738,7 @@ class App: self._close_overlay() # ---------- hamburger menu (main) + sub-modals (Settings / Help / About) ---------- def _show_menu(self): + gc.collect() # defragment before allocating modal bitmaps self._overlay = 'menu'; self._draw_menu() def _draw_menu(self): g = self.g_overlay @@ -768,6 +771,7 @@ class App: # ---------- Settings sub-modal (LED / Speaker / MIDI Out / Channel / Clock Out / Clock In) ---------- def _show_settings(self): + gc.collect() self._overlay = 'settings'; self._draw_settings() def _draw_settings(self): g = self.g_overlay @@ -836,6 +840,7 @@ class App: # ---------- Help sub-modal (paginated) ---------- def _show_help(self): + gc.collect() self._overlay = 'help'; self._help_page = 0; self._draw_help() def _draw_help(self): g = self.g_overlay @@ -872,6 +877,7 @@ class App: # ---------- About sub-modal ---------- def _show_about(self): + gc.collect() self._overlay = 'about'; self._draw_about() def _draw_about(self): import sys @@ -1017,7 +1023,7 @@ class App: L['step'] = (L['step'] + 1) % L['steps'] if li == 0: self._m_steps += 1 # count master-lane steps -> bars - nb = self._m_steps // L['steps'] + nb = (self._m_steps - 1) // L['steps'] # bar of THIS step (off-by-one fix vs 0.0.16) if nb != self._lastbar: self._lastbar = nb; self._on_new_bar(nb) if self._advance: break # seam armed - suppress this step's firing if self.ramp and L['steps'] > 0 and not self._slaved: # CONTINUOUS ramp (off when slaved) @@ -1073,7 +1079,11 @@ class App: nxt = (self.idx + 1) % len(items) if nxt == self.idx: return # 1-item playlist -> just loop, no swap name, prog = items[nxt] - bpm, lanes, bars, ramp, trainer = parse_program(prog) + gc.collect() # defragment before parse_program allocates new lanes + try: + bpm, lanes, bars, ramp, trainer = parse_program(prog) + except MemoryError: + gc.collect(); return # leave _next_pending None -> the segment just loops self._next_pending = {'lanes': lanes, 'bpm': bpm, 'bars': bars, 'ramp': ramp, 'trainer': trainer, 'name': name, 'idx': nxt} def _do_advance(self): # gapless seam: swap the prepared track in at seam_t @@ -1180,7 +1190,7 @@ class App: mlen = self.lanes[0]['steps'] if self.lanes else 1 bpb = (self.lanes[0]['steps'] // max(1, self.lanes[0]['sub'])) if self.lanes else 4 el = (time.monotonic() - self._seg_start) if run else 0 # time within the current segment (resets with the bar) - mbars = self._m_steps // max(1, mlen) # whole master bars elapsed + mbars = max(0, self._m_steps - 1) // max(1, mlen) # bar containing THIS step (off-by-one fix vs 0.0.16) cur = ("%d" % ((mbars % self.bars + 1) if self.bars else (mbars + 1))) if run else "-" # cycle 1..N if self.bars: # track has a length (b): show "X of TOTAL" ts = "%s of %s" % (self._fmt_t(el), self._fmt_t(self.bars * bpb * 60.0 / self.bpm))