From 476899efb17bf440f70a122a9c4deed5e1ede081 Mon Sep 17 00:00:00 2001
From: moon2 <moon2protonmail@protonmail>
Date: Fri, 18 Aug 2023 18:35:09 +0200
Subject: [PATCH] Revert "bl00mbox: not quite sampler patch file save/load but
 almost"

This reverts commit 96686b95fb471e77327917eb919ee5b91084c2f3.

broke sampler file loading, fix approach in sampler_fix branch, not there yet
---
 .../plugins/bl00mbox/bl00mbox_line_in.c       |   2 +-
 components/bl00mbox/plugins/sampler.c         |  79 +++------
 components/bl00mbox/plugins/sampler.h         |   3 +
 python_payload/apps/tiny_sampler/__init__.py  |   4 +-
 python_payload/bl00mbox/_patches.py           | 154 ++++--------------
 5 files changed, 55 insertions(+), 187 deletions(-)

diff --git a/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c b/components/bl00mbox/plugins/bl00mbox/bl00mbox_line_in.c
index 2aa14d33da..a977a158cb 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 = "bl00mbox_line_in",
+    .name = "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 46b0a04a45..e4ff33b72d 100644
--- a/components/bl00mbox/plugins/sampler.c
+++ b/components/bl00mbox/plugins/sampler.c
@@ -4,9 +4,7 @@ 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."
-                   "\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)",
+    .description = "simple sampler that stores a copy of the sample in ram and has basic recording functionality",
     .create_plugin_instance = sampler_create,
     .destroy_plugin_instance = radspa_standard_plugin_destroy
 };
@@ -16,29 +14,6 @@ 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);
@@ -51,11 +26,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_
 
     static int32_t ret = 0;
     
-    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;
+    uint32_t buffer_size = sampler->plugin_table_len;
     
     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));
@@ -63,52 +34,41 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_
 
         if(rec_trigger > 0){
             if(!(data->rec_active)){
-                read_head_pos = sample_len;
-                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
+                data->read_head_position = data->sample_len; // reset sample player into off
                 data->write_head_position = 0;
-                sample_len = 0;
-                write_uint32_to_buffer_pos(buf, SAMPLE_LEN, sample_len);
+                data->sample_len = 0;
                 data->rec_active = true;
             }
         } else if(rec_trigger < 0){
             if(data->rec_active){
-                if(sample_len == buffer_size){
-                    sample_start = data->write_head_position;
-                    write_uint32_to_buffer_pos(buf, SAMPLE_START, sample_start);
+                if(data->sample_len == buffer_size){
+                    data->sample_start = data->write_head_position;
                 } else {
-                    sample_start = 0;
-                    write_uint32_to_buffer_pos(buf, SAMPLE_START, sample_start);
+                    data->sample_start = 0;
                 }
-                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 + BUFFER_OFFSET] = rec_in;
+            buf[data->write_head_position] = rec_in;
             data->write_head_position++;
             if(data->write_head_position >= buffer_size) data->write_head_position = 0;
-            if(sample_len < buffer_size){
-                sample_len++;
-                write_uint32_to_buffer_pos(buf, SAMPLE_LEN, sample_len);
-            }
+            if(data->sample_len < buffer_size) data->sample_len++;
         } else {
             if(trigger > 0){
-                read_head_pos = 0;
-                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
+                data->read_head_position = 0;
                 data->volume = trigger;
             } else if(trigger < 0){
-                read_head_pos = sample_len;
-                write_uint32_to_buffer_pos(buf, READ_HEAD_POS, read_head_pos);
+                data->read_head_position = data->sample_len;
             }
 
-            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);
+            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++;
             } else {
                 //ret = (ret * 255)>>8; // avoid dc clicks with bad samples
                 ret = 0;
@@ -121,7 +81,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 + BUFFER_OFFSET);
+    radspa_t * sampler = radspa_standard_plugin_create(&sampler_desc, SAMPLER_NUM_SIGNALS, sizeof(sampler_data_t), buffer_size);
     if(sampler == NULL) return NULL;
     sampler->render = sampler_run;
     radspa_signal_set(sampler, SAMPLER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
@@ -132,8 +92,7 @@ radspa_t * sampler_create(uint32_t init_var){
     data->trigger_prev = 0;
     data->rec_trigger_prev = 0;
     data->rec_active = false;
-    //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);
+    data->sample_start = 0;
+    data->sample_len = sampler->plugin_table_len;
     return sampler;
 }
diff --git a/components/bl00mbox/plugins/sampler.h b/components/bl00mbox/plugins/sampler.h
index 8483f31cb5..9958d9b9f2 100644
--- a/components/bl00mbox/plugins/sampler.h
+++ b/components/bl00mbox/plugins/sampler.h
@@ -3,7 +3,10 @@
 #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 6f139be92b..7b2f38c337 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.bl00mbox_line_in)
+        self.line_in = self.blm.new(bl00mbox.plugins.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, 1000)
+            self.samplers[i] = self.blm.new(bl00mbox.patches.sampler, 5000)
             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 9a4f9fbbc6..3942399fe1 100644
--- a/python_payload/bl00mbox/_patches.py
+++ b/python_payload/bl00mbox/_patches.py
@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: CC0-1.0
 import math
-import os
 import bl00mbox
 import cpython.wave as wave
 
@@ -101,152 +100,61 @@ class tinysynth_fm(tinysynth):
 
 class sampler(_Patch):
     """
-    requires a wave file (str) or max sample length in milliseconds (int). default path: /sys/samples/
+    requires a wave file. 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
-            f = wave.open(self._convert_filename(filename), "r")
+            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")
 
-            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.load(filename)
+            self._filename = 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):
@@ -282,7 +190,6 @@ class sequencer(_Patch):
             + str(self.signals.step_len.value)
         )
         ret += "\n  [tracks]"
-        """
         for x, seq in enumerate(self.seqs):
             ret += (
                 "\n    "
@@ -291,7 +198,6 @@ 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
 
-- 
GitLab