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..1785815aa905fcb41016391f9c6a366ddaa61393 100644 --- a/components/bl00mbox/plugins/sampler.c +++ b/components/bl00mbox/plugins/sampler.c @@ -15,6 +15,12 @@ radspa_descriptor_t sampler_desc = { #define SAMPLER_REC_IN 2 #define SAMPLER_REC_TRIGGER 3 +static int16_t define_behavior(uint32_t in){ + int32_t ret = in & 0xFFFF; + if(ret > 32767) return ret - 65535; + return ret; +} + 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); if(output_sig->buffer == NULL) return; @@ -26,7 +32,14 @@ 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; + buf[0] = define_behavior(data->read_head_position); + buf[1] = define_behavior(data->read_head_position>>16); + buf[2] = define_behavior(data->sample_start); + buf[3] = define_behavior(data->sample_start>>16); + buf[2] = define_behavior(data->sample_len); + buf[3] = define_behavior(data->sample_len>>16); + + 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)); @@ -52,7 +65,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ 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 + 6] = 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++; @@ -67,7 +80,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ 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); + ret = radspa_mult_shift(buf[sample_offset_pos + 6], data->volume); data->read_head_position++; } else { //ret = (ret * 255)>>8; // avoid dc clicks with bad samples @@ -81,7 +94,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 + 6*sizeof(int16_t); if(sampler == NULL) return NULL; sampler->render = sampler_run; radspa_signal_set(sampler, SAMPLER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); diff --git a/python_payload/apps/tiny_sampler/__init__.py b/python_payload/apps/tiny_sampler/__init__.py index c424b67b104c87d80e156b5df81004c724cb0475..2f5d88ee191da24535ef47816a382c15cc03cc45 100644 --- a/python_payload/apps/tiny_sampler/__init__.py +++ b/python_payload/apps/tiny_sampler/__init__.py @@ -16,10 +16,10 @@ class TinySampler(Application): self.blm = bl00mbox.Channel("tiny sampler") self.samplers = [None] * 5 - self.line_in = self.blm.new(bl00mbox.plugins.line_in) + self.line_in = self.blm.new(bl00mbox.plugins.bl00mbox_line_in) 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.mid self.is_recording = [False] * 5 @@ -82,6 +82,7 @@ class TinySampler(Application): ): if self.is_recording[i]: self.samplers[i].signals.rec_trigger.stop() + self.samplers[i].normalize() self.is_recording[i] = False self.ct_prev = ct diff --git a/python_payload/bl00mbox/_patches.py b/python_payload/bl00mbox/_patches.py index a4b5aa8634ae731330ef71b1dbce45630a42ab64..d3e32378e88fb44e62fa7d748f752b1a6bab1e38 100644 --- a/python_payload/bl00mbox/_patches.py +++ b/python_payload/bl00mbox/_patches.py @@ -100,7 +100,7 @@ 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): @@ -113,9 +113,9 @@ class sampler(_Patch): 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 @@ -125,22 +125,22 @@ class sampler(_Patch): 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) + for i in range(0, self._len_frames * 2, 100): + table[i + 6 : i + 100 + 6] = f.readframes(50) else: # somewhat fast path for stereo table = self.plugins.sampler.table_int16_array - for i in range(self.len_frames): + for i in range(self._len_frames): frame = f.readframes(1) value = int.from_bytes(frame[0:2], "little") - table[i] = value + table[i + 6] = value f.close() 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 = "" @@ -149,10 +149,51 @@ class sampler(_Patch): self.signals.rec_in = self.plugins.sampler.signals.rec_in self.signals.rec_trigger = self.plugins.sampler.signals.rec_trigger + def load(self, filename): + pass + + def save(self, filename): + pass + + def _extract_uint32_t(self, lsb, msb): + if lsb < 0: + lsb += 65535 + if msb < 0: + msb += 65535 + return lsb + (msb * (1<<16)) + + @property + def read_head_position(self): + return self._extract_uint32_t(self.plugins.sampler.table[0], self.plugins.sampler.table[1]) + + @property + def sample_start(self): + return self._extract_uint32_t(self.plugins.sampler.table[2], self.plugins.sampler.table[3]) + + @property + def sample_len(self): + return self._extract_uint32_t(self.plugins.sampler.table[4], self.plugins.sampler.table[5]) + @property def filename(self): return self._filename + def normalize(self): + maximum = 0 + table = self.plugins.sampler.table_int16_array + for i in range(self.sample_len): + i = (i + self.sample_start) % self._len_frames + a = table[i+6] + if a < 0: + a = -a + if a > maximum: + maximum = a + if maximum != 0: + gain = 32767/maximum + for i in range(self.sample_len): + i = (i + self.sample_start) % self._len_frames + table[i+6] = gain * table[i+6] + class sequencer(_Patch): def __init__(self, chan, num_tracks, num_steps): @@ -188,6 +229,7 @@ class sequencer(_Patch): + str(self.signals.step_len.value) ) ret += "\n [tracks]" + """ for x, seq in enumerate(self.seqs): ret += ( "\n " @@ -196,6 +238,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