diff --git a/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c b/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c
index a977a158cbe9fe168cf8c9295731c21fe5827bf2..2aa14d33da34adf82081f0598e5e27539f318c08 100644
--- a/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c
+++ b/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c
@@ -1,7 +1,7 @@
 #include "bl00mbox_line_in.h"
 
 radspa_descriptor_t bl00mbox_line_in_desc = {
-    .name = "line_in",
+    .name = "bl00mbox_line_in",
     .id = 4001,
     .description = "connects to the line input of bl00mbox",
     .create_plugin_instance = bl00mbox_line_in_create,
diff --git a/components/bl00mbox/plugins/sampler.c b/components/bl00mbox/plugins/sampler.c
index e4ff33b72db5348e3c81d4f64036590ab2ba1f97..46b0a04a453b71b60f2bc9e7ce40e7c9324e1ec4 100644
--- a/components/bl00mbox/plugins/sampler.c
+++ b/components/bl00mbox/plugins/sampler.c
@@ -4,7 +4,9 @@ radspa_t * sampler_create(uint32_t init_var);
 radspa_descriptor_t sampler_desc = {
     .name = "_sampler_ram",
     .id = 696969,
-    .description = "simple sampler that stores a copy of the sample in ram and has basic recording functionality",
+    .description = "simple sampler that stores a copy of the sample in ram and has basic recording functionality."
+                   "\ninit_var: length of pcm sample memory\ntable layout: [0:2] read head position (uint32_t), [2:4] sample start (uint32_t), "
+                   "[4:6] sample length (uint32_t), [6] new record event (bool), [7:init_var+7] pcm sample data (int16_t)",
     .create_plugin_instance = sampler_create,
     .destroy_plugin_instance = radspa_standard_plugin_destroy
 };
@@ -14,6 +16,29 @@ radspa_descriptor_t sampler_desc = {
 #define SAMPLER_TRIGGER 1
 #define SAMPLER_REC_IN 2
 #define SAMPLER_REC_TRIGGER 3
+#define READ_HEAD_POS 0
+#define SAMPLE_START 2
+#define SAMPLE_LEN 4
+#define BUFFER_OFFSET 7
+
+static inline int16_t define_behavior(uint32_t in){
+    int32_t ret = in & 0xFFFF;
+    if(ret > 32767) return ret - 65535;
+    return ret;
+}
+
+static inline void write_uint32_to_buffer_pos(int16_t * buf, uint32_t pos, uint32_t input){
+    buf[pos] = define_behavior(input);
+    buf[pos+1] = define_behavior(input>>16);
+}
+
+static inline uint32_t read_uint32_from_buffer_pos(int16_t * buf, uint32_t pos){
+    int32_t lsb = buf[pos];
+    if(lsb < 0) lsb += 65535;
+    int32_t msb = buf[pos+1];
+    if(msb < 0) msb += 65535;
+    return (((uint32_t) msb) << 16) + ((uint32_t) lsb);
+}
 
 void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_id){
     radspa_signal_t * output_sig = radspa_signal_get_by_index(sampler, SAMPLER_OUTPUT);
@@ -26,7 +51,11 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_
 
     static int32_t ret = 0;
     
-    uint32_t buffer_size = sampler->plugin_table_len;
+    uint32_t read_head_pos = read_uint32_from_buffer_pos(buf, READ_HEAD_POS);
+    uint32_t sample_start = read_uint32_from_buffer_pos(buf, SAMPLE_START);
+    uint32_t sample_len = read_uint32_from_buffer_pos(buf, SAMPLE_LEN);
+    
+    uint32_t buffer_size = sampler->plugin_table_len - 6;
     
     for(uint16_t i = 0; i < num_samples; i++){
         int16_t rec_trigger = radspa_trigger_get(rec_trigger_sig->get_value(rec_trigger_sig, i, num_samples, render_pass_id), &(data->rec_trigger_prev));
@@ -34,41 +63,52 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_
 
         if(rec_trigger > 0){
             if(!(data->rec_active)){
-                data->read_head_position = data->sample_len; // reset sample player into off
+                read_head_pos = sample_len;
+                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
                 data->write_head_position = 0;
-                data->sample_len = 0;
+                sample_len = 0;
+                write_uint32_to_buffer_pos(buf, SAMPLE_LEN, sample_len);
                 data->rec_active = true;
             }
         } else if(rec_trigger < 0){
             if(data->rec_active){
-                if(data->sample_len == buffer_size){
-                    data->sample_start = data->write_head_position;
+                if(sample_len == buffer_size){
+                    sample_start = data->write_head_position;
+                    write_uint32_to_buffer_pos(buf, SAMPLE_START, sample_start);
                 } else {
-                    data->sample_start = 0;
+                    sample_start = 0;
+                    write_uint32_to_buffer_pos(buf, SAMPLE_START, sample_start);
                 }
+                buf[6] = 1;
                 data->rec_active = false;
             }
         }
 
         if(data->rec_active){
             int16_t rec_in = rec_in_sig->get_value(rec_in_sig, i, num_samples, render_pass_id);
-            buf[data->write_head_position] = rec_in;
+            buf[data->write_head_position + BUFFER_OFFSET] = rec_in;
             data->write_head_position++;
             if(data->write_head_position >= buffer_size) data->write_head_position = 0;
-            if(data->sample_len < buffer_size) data->sample_len++;
+            if(sample_len < buffer_size){
+                sample_len++;
+                write_uint32_to_buffer_pos(buf, SAMPLE_LEN, sample_len);
+            }
         } else {
             if(trigger > 0){
-                data->read_head_position = 0;
+                read_head_pos = 0;
+                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
                 data->volume = trigger;
             } else if(trigger < 0){
-                data->read_head_position = data->sample_len;
+                read_head_pos = sample_len;
+                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
             }
 
-            if(data->read_head_position < data->sample_len){
-                uint32_t sample_offset_pos = data->read_head_position + data->sample_start;
-                if(sample_offset_pos >= data->sample_len) sample_offset_pos -= data->sample_len;
-                ret = radspa_mult_shift(buf[sample_offset_pos], data->volume);
-                data->read_head_position++;
+            if(read_head_pos < sample_len){
+                uint32_t sample_offset_pos = read_head_pos + sample_start;
+                if(sample_offset_pos >= sample_len) sample_offset_pos -= sample_len;
+                ret = radspa_mult_shift(buf[sample_offset_pos + BUFFER_OFFSET], data->volume);
+                read_head_pos++;
+                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
             } else {
                 //ret = (ret * 255)>>8; // avoid dc clicks with bad samples
                 ret = 0;
@@ -81,7 +121,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_
 radspa_t * sampler_create(uint32_t init_var){
     if(init_var == 0) return NULL; //doesn't make sense
     uint32_t buffer_size = init_var;
-    radspa_t * sampler = radspa_standard_plugin_create(&sampler_desc, SAMPLER_NUM_SIGNALS, sizeof(sampler_data_t), buffer_size);
+    radspa_t * sampler = radspa_standard_plugin_create(&sampler_desc, SAMPLER_NUM_SIGNALS, sizeof(sampler_data_t), buffer_size + BUFFER_OFFSET);
     if(sampler == NULL) return NULL;
     sampler->render = sampler_run;
     radspa_signal_set(sampler, SAMPLER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
@@ -92,7 +132,8 @@ radspa_t * sampler_create(uint32_t init_var){
     data->trigger_prev = 0;
     data->rec_trigger_prev = 0;
     data->rec_active = false;
-    data->sample_start = 0;
-    data->sample_len = sampler->plugin_table_len;
+    //int16_t * buf = sampler->plugin_table;
+    //write_uint32_to_buffer_pos(buf, SAMPLE_START, 0);
+    //write_uint32_to_buffer_pos(buf, SAMPLE_LEN, sampler->plugin_table_len);
     return sampler;
 }
diff --git a/components/bl00mbox/plugins/sampler.h b/components/bl00mbox/plugins/sampler.h
index 9958d9b9f2a440afdaa4101b710ca032fd34d44d..8483f31cb53b19b5ec53d6e6c3517f99e2044789 100644
--- a/components/bl00mbox/plugins/sampler.h
+++ b/components/bl00mbox/plugins/sampler.h
@@ -3,10 +3,7 @@
 #include <radspa_helpers.h>
 
 typedef struct {
-    uint32_t read_head_position;
     uint32_t write_head_position;
-    uint32_t sample_start;
-    uint32_t sample_len;
     int16_t trigger_prev;
     int16_t rec_trigger_prev;
     int16_t volume;
diff --git a/python_payload/apps/tiny_sampler/__init__.py b/python_payload/apps/tiny_sampler/__init__.py
index 7b2f38c3375a6ceb5824e5298b75f7d47326bb71..6f139be92b028454896018ce8089aeef69960e84 100644
--- a/python_payload/apps/tiny_sampler/__init__.py
+++ b/python_payload/apps/tiny_sampler/__init__.py
@@ -16,13 +16,13 @@ class TinySampler(Application):
         self.blm = bl00mbox.Channel("tiny sampler")
 
         self.samplers: List[bl00mbox.patches._Patch | Any] = [None] * 5
-        self.line_in = self.blm.new(bl00mbox.plugins.line_in)
+        self.line_in = self.blm.new(bl00mbox.plugins.bl00mbox_line_in)
         self.blm.volume = (
             30000  # TODO: increase onboard mic line in gain and remove this
         )
         self.line_in.signals.gain = 30000
         for i in range(5):
-            self.samplers[i] = self.blm.new(bl00mbox.patches.sampler, 5000)
+            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
diff --git a/python_payload/bl00mbox/_patches.py b/python_payload/bl00mbox/_patches.py
index 3942399fe1d2eca9d2f7aecae40fd6778007e111..9a4f9fbbc69967c9b8350e501469ea0f132e4185 100644
--- a/python_payload/bl00mbox/_patches.py
+++ b/python_payload/bl00mbox/_patches.py
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: CC0-1.0
 import math
+import os
 import bl00mbox
 import cpython.wave as wave
 
@@ -100,61 +101,152 @@ class tinysynth_fm(tinysynth):
 
 class sampler(_Patch):
     """
-    requires a wave file. default path: /sys/samples/
+    requires a wave file (str) or max sample length in milliseconds (int). default path: /sys/samples/
     """
 
     def __init__(self, chan, init_var):
         # init can be filename to load into ram
         super().__init__(chan)
+        self._filename = ""
         if type(init_var) == str:
             filename = init_var
-            if filename.startswith("/flash/") or filename.startswith("/sd/"):
-                f = wave.open(filename, "r")
-            elif filename.startswith("/"):
-                f = wave.open("/flash/" + filename, "r")
-            else:
-                f = wave.open("/flash/sys/samples/" + filename, "r")
+            f = wave.open(self._convert_filename(filename), "r")
 
-            self.len_frames = f.getnframes()
+            self._len_frames = f.getnframes()
             self.plugins.sampler = chan.new(
-                bl00mbox.plugins._sampler_ram, self.len_frames
+                bl00mbox.plugins._sampler_ram, self._len_frames
             )
 
-            assert f.getsampwidth() == 2
-            assert f.getnchannels() in (1, 2)
-            assert f.getcomptype() == "NONE"
-
-            if f.getnchannels() == 1:
-                # fast path for mono
-                table = self.plugins.sampler.table_bytearray
-                for i in range(0, self.len_frames * 2, 100):
-                    table[i : i + 100] = f.readframes(50)
-            else:
-                # somewhat fast path for stereo
-                table = self.plugins.sampler.table_int16_array
-                for i in range(self.len_frames):
-                    frame = f.readframes(1)
-                    value = int.from_bytes(frame[0:2], "little")
-                    table[i] = value
-
             f.close()
-            self._filename = filename
+            self.load(filename)
         else:
-            self.len_frames = int(48 * init_var)
+            self._len_frames = int(48 * init_var)
             self.plugins.sampler = chan.new(
-                bl00mbox.plugins._sampler_ram, self.len_frames
+                bl00mbox.plugins._sampler_ram, self._len_frames
             )
-            self._filename = ""
 
         self.signals.trigger = self.plugins.sampler.signals.trigger
         self.signals.output = self.plugins.sampler.signals.output
         self.signals.rec_in = self.plugins.sampler.signals.rec_in
         self.signals.rec_trigger = self.plugins.sampler.signals.rec_trigger
 
+    def _convert_filename(self, filename):
+        # TODO: waht if filename doesn't exist?
+        if filename.startswith("/flash/") or filename.startswith("/sd/"):
+            return filename
+        elif filename.startswith("/"):
+            return "/flash/" + filename
+        else:
+            return "/flash/sys/samples/" + filename
+
+    def load(self, filename):
+        f = wave.open(self._convert_filename(filename), "r")
+
+        assert f.getsampwidth() == 2
+        assert f.getnchannels() in (1, 2)
+        assert f.getcomptype() == "NONE"
+        self.sample_start = 0
+        frames = f.getnframes()
+        if frames > self.memory_len:
+            frames = self.memory_len
+        self.sample_len = frames
+
+        if f.getnchannels() == 1:
+            # fast path for mono
+            table = self.plugins.sampler.table_bytearray
+            for i in range(0, self.memory_len * 2, 100):
+                table[i : i + 100] = f.readframes(50)
+        else:
+            # somewhat fast path for stereo
+            table = self.plugins.sampler.table_int16_array
+            for i in range(self._len_frames):
+                frame = f.readframes(1)
+                value = int.from_bytes(frame[0:2], "little")
+                table[i] = value
+        f.close()
+
+    def save(self, filename, overwrite=True):
+        # remove when we actually write
+        return False
+        if os.path.exists(filename):
+            if overwrite:
+                os.remove(filename)
+            else:
+                return False
+        f = wave.open(self._convert_filename(filename), "w")
+        for i in range(self.sample_len):
+            data = self.plugins.sampler.table[_offset_index(i)]
+            # TODO: figure out python bytes
+            # note: index wraps around, ringbuffer!
+            # f.writeframesraw???
+        f.close()
+        return True
+
+    def _offset_index(self, index):
+        index += self.sample_start
+        if index >= self.memory_len:
+            index -= self.memory_len
+        index += 6
+        return index
+
+    @property
+    def memory_len(self):
+        return self._len_frames
+
+    def _decode_uint32(self, pos):
+        lsb = self.plugins.sampler.table[pos]
+        msb = self.plugins.sampler.table[pos + 1]
+        if lsb < 0:
+            lsb += 65535
+        if msb < 0:
+            msb += 65535
+        return lsb + (msb * (1 << 16))
+
+    def _encode_uint32(self, pos, num):
+        msb = num // (1 << 16)
+        lsb = num
+        if lsb > 32767:
+            lsb -= 65535
+        if msb > 32767:
+            msb -= 65535
+        self.plugins.sampler.table[pos] = lsb
+        self.plugins.sampler.table[pos + 1] = msb
+
+    @property
+    def read_head_position(self):
+        return self._decode_uint32(0)
+
+    @read_head_position.setter
+    def read_head_position(self, val):
+        self._encode_uint32(0, val)
+
+    @property
+    def sample_start(self):
+        return self._decode_uint32(2)
+
+    @sample_start.setter
+    def sample_start(self, val):
+        self._encode_uint32(2, val)
+
+    @property
+    def sample_len(self):
+        return self._decode_uint32(4)
+
+    @sample_len.setter
+    def sample_len(self, val):
+        self._encode_uint32(4, val)
+
     @property
     def filename(self):
         return self._filename
 
+    @property
+    def rec_event_autoclear(self):
+        if self.plugins.sampler_table[6]:
+            self.plugins.sampler_table[6] = 0
+            return True
+        return False
+
 
 class sequencer(_Patch):
     def __init__(self, chan, num_tracks, num_steps):
@@ -190,6 +282,7 @@ class sequencer(_Patch):
             + str(self.signals.step_len.value)
         )
         ret += "\n  [tracks]"
+        """
         for x, seq in enumerate(self.seqs):
             ret += (
                 "\n    "
@@ -198,6 +291,7 @@ class sequencer(_Patch):
                 + "".join(["X  " if x > 0 else ".  " for x in seq.table[1:]])
                 + "]"
             )
+        """
         ret += "\n" + "\n".join(super().__repr__().split("\n")[1:])
         return ret