diff --git a/python_payload/apps/tiny_sampler/__init__.py b/python_payload/apps/tiny_sampler/__init__.py
index 9de8e881f8de4950e6a822d543eefd5bacd1b632..121e563c6f0018a17517e6c4ad1fbec52ba6fac9 100644
--- a/python_payload/apps/tiny_sampler/__init__.py
+++ b/python_payload/apps/tiny_sampler/__init__.py
@@ -12,10 +12,46 @@ from st3m.ui.view import View, ViewManager
 import math
 
 
-class Pictograms:
-    @classmethod
-    def two_petal_group(
-        cls, ctx, start=0, stop=5, outer_rad=110, inner_rad=50, offset=10
+class TinySampler(Application):
+    def __init__(self, app_ctx: ApplicationContext) -> None:
+        super().__init__(app_ctx)
+        self.blm = None
+
+        self.is_recording = [False] * 5
+        self.is_playing = [False] * 5
+        self.has_data = [False] * 5
+        self.has_data_stored = [False] * 5
+
+        self.ct_prev = captouch.read()
+        self.mode = 0
+        self._num_modes = 3
+        self.press_event = [False] * 10
+        self.release_event = [False] * 10
+        self.pitch_shift = [0] * 5
+
+    def _build_synth(self):
+        if self.blm is None:
+            self.blm = bl00mbox.Channel("tiny sampler")
+        self.samplers: List[bl00mbox.patches._Patch | Any] = [None] * 5
+        self.line_in = self.blm.new(bl00mbox.plugins.bl00mbox_line_in)
+        self.line_in.signals.gain = 32000
+        for i in range(5):
+            self.samplers[i] = self.blm.new(bl00mbox.patches.sampler, 1000)
+            self.samplers[i].signals.output = self.blm.mixer
+            self.samplers[i].signals.rec_in = self.line_in.signals.right
+            self.has_data[i] = self.samplers[i].load("tiny_sample_" + str(i) + ".wav")
+            if self.has_data[i]:
+                self.samplers[
+                    i
+                ].plugins.sampler.signals.pitch_shift.tone = self.pitch_shift[i]
+            self.has_data_stored[i] = self.has_data[i]
+
+    def _highlight_petal(self, num: int, r: int, g: int, b: int) -> None:
+        for i in range(7):
+            leds.set_rgb((4 * num - i + 3) % 40, r, g, b)
+
+    def draw_two_petal_group(
+        self, ctx, start=0, stop=5, outer_rad=110, inner_rad=50, offset=10
     ):
         cos72 = 0.31
         sin72 = 0.95
@@ -44,44 +80,10 @@ class Pictograms:
             ctx.stroke()
         ctx.restore()
 
-
-class TinySampler(Application):
-    def __init__(self, app_ctx: ApplicationContext) -> None:
-        super().__init__(app_ctx)
-        self.blm = bl00mbox.Channel("tiny sampler")
-
-        self.samplers: List[bl00mbox.patches._Patch | Any] = [None] * 5
-        self.line_in = self.blm.new(bl00mbox.plugins.bl00mbox_line_in)
-        self.line_in.signals.gain = 32000
-        for i in range(5):
-            self.samplers[i] = self.blm.new(bl00mbox.patches.sampler, 1000)
-            self.samplers[i].signals.output = self.blm.mixer
-            self.samplers[i].signals.rec_in = self.line_in.signals.right
-        self.is_recording = [False] * 5
-        self.is_playing = [False] * 5
-        self.has_data = [False] * 5
-        if audio.input_get_source() == audio.INPUT_SOURCE_NONE:
-            audio.input_set_source(audio.INPUT_SOURCE_ONBOARD_MIC)
-
-        self.ct_prev = captouch.read()
-
-    def _highlight_petal(self, num: int, r: int, g: int, b: int) -> None:
-        for i in range(7):
-            leds.set_rgb((4 * num - i + 3) % 40, r, g, b)
-
-    def draw(self, ctx: Context) -> None:
-        dist = 90
-        ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill()
-
-        ctx.rgb(0.1, 0.5, 0.6)
-        ctx.line_width = 6
-        Pictograms.two_petal_group(ctx, stop=5)
-
+    def draw_mode_0(self, ctx):
         ctx.save()
-        ctx.line_width = 4
-        ctx.font = ctx.get_font_name(0)
-        ctx.text_align = ctx.MIDDLE
-        ctx.font_size = 24
+        dist = 90
+        ctx.line_width = 5
         for i in range(5):
             if not self.has_data[i]:
                 ctx.rgb(0.4, 0.4, 0.4)
@@ -97,19 +99,80 @@ class TinySampler(Application):
 
             ctx.fill()
             ctx.rotate(6.28 / 10)
-            ctx.rgb(1, 0, 0)
-            if self.is_recording[i]:
-                ctx.arc(0, -dist, 8, 0, math.tau, 1)
+            if not self.is_recording[i]:
+                ctx.rgb(0.7, 0, 0)
+                ctx.arc(0, -dist, 6, 0, math.tau, 1)
                 ctx.stroke()
-                ctx.arc(0, -dist, 5, 0, math.tau, 1)
-                ctx.fill()
             else:
-                ctx.arc(0, -dist, 7, 0, math.tau, 1)
+                ctx.rgb(1, 0, 0)
+                ctx.arc(0, -dist, 9, 0, math.tau, 1)
                 ctx.fill()
             ctx.move_to(0, 0)
             ctx.rotate(6.28 / 10)
         ctx.restore()
 
+    def draw_mode_1(self, ctx):
+        ctx.save()
+        dist = 80
+        text_shift = 5
+        ctx.font = "Comic Mono"
+        ctx.text_align = ctx.MIDDLE
+        ctx.font_size = 18
+        rot_over = 6.28 / 50
+        ctx.rotate(-(6.28 / 4) + rot_over)
+        for i in range(5):
+            if not self.has_data_stored[i]:
+                ctx.rgb(0.4, 0.4, 0.4)
+            else:
+                ctx.rgb(0.8, 0.8, 0.8)
+            ctx.move_to(dist, text_shift)
+            ctx.text("load")
+            ctx.rotate(6.28 / 10 - 2 * rot_over)
+
+            if not self.has_data[i]:
+                ctx.rgb(0.4, 0.4, 0.4)
+            else:
+                ctx.rgb(0.8, 0.8, 0.8)
+            ctx.move_to(dist, text_shift)
+            ctx.text("save")
+            ctx.move_to(0, 0)
+            ctx.rotate(6.28 / 10 + 2 * rot_over)
+        ctx.restore()
+
+    def draw_mode_2(self, ctx):
+        ctx.save()
+        dist = 80
+        text_shift = 5
+        ctx.font = "Comic Mono"
+        ctx.text_align = ctx.MIDDLE
+        ctx.font_size = 25
+        ctx.move_to(0, 5)
+        ctx.rgb(0.8, 0.8, 0.8)
+        ctx.text("pitch")
+        ctx.rotate(-(6.28 / 4) + (6.28 / 20))
+        if self.blm is not None:
+            for i in range(5):
+                ctx.move_to(dist, text_shift)
+                ctx.text(
+                    str(int(self.samplers[i].plugins.sampler.signals.pitch_shift.tone))
+                )
+                ctx.move_to(0, 0)
+                ctx.rotate(6.28 / 5)
+        ctx.restore()
+
+    def draw(self, ctx: Context) -> None:
+        ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill()
+
+        ctx.rgb(0.1, 0.5, 0.6)
+        ctx.line_width = 6
+        self.draw_two_petal_group(ctx, stop=5)
+        if self.mode == 0:
+            self.draw_mode_0(ctx)
+        elif self.mode == 1:
+            self.draw_mode_1(ctx)
+        elif self.mode == 2:
+            self.draw_mode_2(ctx)
+
     def think(self, ins: InputState, delta_ms: int) -> None:
         super().think(ins, delta_ms)
 
@@ -121,38 +184,95 @@ class TinySampler(Application):
                 self._highlight_petal(i * 2, 0, 255, 0)
         leds.update()
 
+        if self.blm is None:
+            return
+        if self.input.buttons.app.left.pressed:
+            self.mode = (self.mode - 1) % self._num_modes
+            release_all = True
+        elif self.input.buttons.app.right.pressed:
+            self.mode = (self.mode + 1) % self._num_modes
+            release_all = True
+        else:
+            release_all = False
+
         ct = captouch.read()
-        for i in range(5):
-            if not self.is_recording[i]:
-                if ct.petals[i * 2].pressed and not self.ct_prev.petals[i * 2].pressed:
+
+        self.press_event = [False] * 10
+        if release_all:
+            self.release_event = [True] * 10
+        else:
+            self.release_event = [False] * 10
+            for i in range(10):
+                if ct.petals[i].pressed and not self.ct_prev.petals[i].pressed:
+                    self.press_event[i] = True
+                elif not ct.petals[i].pressed and self.ct_prev.petals[i].pressed:
+                    self.release_event[i] = True
+
+        if self.mode == 0 or release_all:
+            for i in range(5):
+                if not self.is_recording[i]:
+                    if self.press_event[i * 2]:
+                        self.samplers[i].signals.trigger.start()
+                        self.is_playing[i] = True
+                    if self.release_event[i * 2]:
+                        self.samplers[i].signals.trigger.stop()
+                        self.is_playing[i] = False
+            for i in range(5):
+                if self.press_event[i * 2 + 1]:
+                    if not self.is_recording[i]:
+                        self.samplers[i].signals.rec_trigger.start()
+                        self.is_recording[i] = True
+                if self.release_event[i * 2 + 1]:
+                    if self.is_recording[i]:
+                        self.samplers[i].signals.rec_trigger.stop()
+                        self.is_recording[i] = False
+                        self.has_data[i] = True
+        elif self.mode == 1 or release_all:
+            for i in range(5):
+                if self.press_event[i * 2]:
+                    self.has_data_stored[i] = self.samplers[i].load(
+                        "tiny_sample_" + str(i) + ".wav"
+                    )
+                    self.has_data[i] = self.has_data_stored[i]
+            for i in range(5):
+                if self.press_event[i * 2 + 1]:
+                    if self.has_data[i]:
+                        if self.samplers[i].save(
+                            "tiny_sample_" + str(i) + ".wav", overwrite=True
+                        ):
+                            self.has_data_stored[i] = True
+        elif self.mode == 2 or release_all:
+            for i in range(5):
+                if self.press_event[i * 2]:
+                    self.samplers[i].plugins.sampler.signals.pitch_shift.tone += 1
+                    self.pitch_shift[i] = self.samplers[
+                        i
+                    ].plugins.sampler.signals.pitch_shift.tone
                     self.samplers[i].signals.trigger.start()
                     self.is_playing[i] = True
-                if not ct.petals[i * 2].pressed and self.ct_prev.petals[i * 2].pressed:
+                if self.release_event[i * 2]:
+                    self.samplers[i].signals.trigger.stop()
+                    self.is_playing[i] = False
+            for i in range(5):
+                if self.press_event[i * 2 + 1]:
+                    self.samplers[i].plugins.sampler.signals.pitch_shift.tone -= 1
+                    self.pitch_shift[i] = self.samplers[
+                        i
+                    ].plugins.sampler.signals.pitch_shift.tone
+                    self.samplers[i].signals.trigger.start()
+                    self.is_playing[i] = True
+                if self.release_event[i * 2 + 1]:
                     self.samplers[i].signals.trigger.stop()
                     self.is_playing[i] = False
-
-        for i in range(5):
-            if (
-                ct.petals[(i * 2) + 1].pressed
-                and not self.ct_prev.petals[(i * 2) + 1].pressed
-            ):
-                if not self.is_recording[i]:
-                    self.samplers[i].signals.rec_trigger.start()
-                    self.is_recording[i] = True
-            if (
-                not ct.petals[(i * 2) + 1].pressed
-                and self.ct_prev.petals[(i * 2) + 1].pressed
-            ):
-                if self.is_recording[i]:
-                    self.samplers[i].signals.rec_trigger.stop()
-                    self.is_recording[i] = False
-                    self.has_data[i] = True
 
         self.ct_prev = ct
 
     def on_enter(self, vm) -> None:
+        self.mode = 0
         super().on_enter(vm)
-        self.blm.foreground = True
+        audio.input_set_source(audio.INPUT_SOURCE_ONBOARD_MIC)
+        if self.blm is None:
+            self._build_synth()
 
     def on_exit(self) -> None:
         super().on_exit()
@@ -161,7 +281,10 @@ class TinySampler(Application):
                 self.samplers[i].signals.rec_trigger.stop()
                 self.is_recording[i] = False
         audio.input_set_source(audio.INPUT_SOURCE_NONE)
-        self.blm.foreground = False
+        if self.blm is not None:
+            self.blm.clear()
+            self.blm.free = True
+            self.blm = None
 
 
 # For running with `mpremote run`: