Skip to content
Snippets Groups Projects
Commit ac52e91d authored by moon2's avatar moon2 :speech_balloon:
Browse files

tiny sampler: pitch shift + save samples

parent 13294127
Branches
Tags
No related merge requests found
......@@ -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()
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 ct.petals[i * 2].pressed and not self.ct_prev.petals[i * 2].pressed:
if self.press_event[i * 2]:
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 (
ct.petals[(i * 2) + 1].pressed
and not self.ct_prev.petals[(i * 2) + 1].pressed
):
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 (
not ct.petals[(i * 2) + 1].pressed
and self.ct_prev.petals[(i * 2) + 1].pressed
):
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 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
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`:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment