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

bl00mbox: api refactor (mypy help from dx)

parent 1846391d
Branches
Tags
1 merge request!97bl00mbox: api refactor
Pipeline #6418 passed
...@@ -11,13 +11,9 @@ Upcoming features ...@@ -11,13 +11,9 @@ Upcoming features
(in no specific order) (in no specific order)
1) Expose hardware such as captouch and IMU as pseudo-signals that buds can subscribe to. This frees the repl for parameter manipulation while the backend takes care of the playing surface, neat for live coding. 1) Expose hardware such as captouch and IMU as pseudo-signals that plugins can subscribe to. This frees the repl for parameter manipulation while the backend takes care of the playing surface, neat for live coding.
2) Cross-channel connections 2) Stepped value naming
3) Stepped value naming
4) Better signal/bud representation in patches
Patches Patches
------------- -------------
...@@ -35,8 +31,7 @@ with a channel instance, but you can also spawn one directly: ...@@ -35,8 +31,7 @@ with a channel instance, but you can also spawn one directly:
>>> blm.volume = 5000 >>> blm.volume = 5000
The easiest way to get sound is to use patches. These are "macroscopic" units The easiest way to get sound is to use patches. These are "macroscopic" units
that directly connect to the output and provide a compact UI. Here's how to and can often be used without much thinking:
create one:
.. code-block:: pycon .. code-block:: pycon
...@@ -44,15 +39,17 @@ create one: ...@@ -44,15 +39,17 @@ create one:
>>> bl00mbox.patches. >>> bl00mbox.patches.
# create a patch instance # create a patch instance
>>> tiny = blm.new(bl00mbox.patches.tinysynth_fm) >>> tiny = blm.new(bl00mbox.patches.tinysynth_fm)
# connect sound output to mixer of the channel
>>> tiny.signals.output = blm.mixer
# play it! # play it!
>>> tiny.start() >>> tiny.signals.trigger.start()
# try autocomplete here too! # try autocomplete here too!
>>> tiny. >>> tiny.
# patches come with very individual parameters! # patches come with very individual parameters!
>>> tiny.fm_waveform(tiny.SAW) >>> tiny.signals.waveform = 0
>>> tiny.start() >>> tiny.signals.trigger.start()
Buds Plugins
---------- ----------
We can inspect the patch we created earlier: We can inspect the patch we created earlier:
...@@ -61,13 +58,13 @@ We can inspect the patch we created earlier: ...@@ -61,13 +58,13 @@ We can inspect the patch we created earlier:
>>> tiny >>> tiny
[patch] tinysynth_fm [patch] tinysynth_fm
[bud 32] osc_fm [plugin 32] osc_fm
output [output]: 0 => input in [bud 34] ampliverter output [output]: 0 => input in [plugin 34] ampliverter
pitch [input/pitch]: 18367 / 0.0 semitones / 440.0Hz pitch [input/pitch]: 18367 / 0.0 semitones / 440.0Hz
waveform [input]: -1 waveform [input]: -1
lin_fm [input]: 0 <= output in [bud 35] osc_fm lin_fm [input]: 0 <= output in [plugin 35] osc_fm
[bud 33] env_adsr [plugin 33] env_adsr
output [output]: 0 => gain in [bud 34] ampliverter output [output]: 0 => gain in [plugin 34] ampliverter
phase [output]: 0 phase [output]: 0
input [input]: 32767 input [input]: 32767
trigger [input/trigger]: 0 trigger [input/trigger]: 0
...@@ -76,20 +73,20 @@ We can inspect the patch we created earlier: ...@@ -76,20 +73,20 @@ We can inspect the patch we created earlier:
sustain [ms] [input]: 0 sustain [ms] [input]: 0
release [input]: 100 release [input]: 100
gate [input]: 0 gate [input]: 0
[bud 34] ampliverter [plugin 34] ampliverter
output [output]: 0 ==> [channel mixer] output [output]: 0 ==> [channel mixer]
input [input]: 0 <= output in [bud 32] osc_fm input [input]: 0 <= output in [plugin 32] osc_fm
gain [input]: 0 <= output in [bud 33] env_adsr gain [input]: 0 <= output in [plugin 33] env_adsr
bias [input]: 0 bias [input]: 0
[bud 35] osc_fm [plugin 35] osc_fm
output [output]: 0 => lin_fm in [bud 32] osc_fm output [output]: 0 => lin_fm in [plugin 32] osc_fm
pitch [input/pitch]: 21539 / 15.86 semitones / 1099.801Hz pitch [input/pitch]: 21539 / 15.86 semitones / 1099.801Hz
waveform [input]: 1 waveform [input]: 1
lin_fm [input]: 0 lin_fm [input]: 0
The patch is actually composed of buds! Buds are wrappers that contain atomic plugins. Each The patch is actually composed of plugins and connections! Plugins are atomic signal processing
plugin is composed of signals that can be connected to other signals. Signals can have different units. Each plugin has signals that can be connected to other signals. Signals can have different
properties that are listed behind their name in square brackets. For starters, each signal is properties that are listed behind their name in square brackets. For starters, each signal is
either an input or output. Connections always happen between an input and an output. Outputs either an input or output. Connections always happen between an input and an output. Outputs
can fan out to multiple inputs, but inputs can only receive data from a single output. If no can fan out to multiple inputs, but inputs can only receive data from a single output. If no
...@@ -99,7 +96,7 @@ output is connected to an input, it has a static value. ...@@ -99,7 +96,7 @@ output is connected to an input, it has a static value.
A special case is the channel mixer (an [input] signal) which only fakes A special case is the channel mixer (an [input] signal) which only fakes
being a bl00mbox signal and can accept multiple outputs. being a bl00mbox signal and can accept multiple outputs.
Let's play around with that a bit more and create some fresh unbothered buds: Let's play around with that a bit more and create some fresh unbothered plugins:
.. code-block:: pycon .. code-block:: pycon
...@@ -107,29 +104,29 @@ Let's play around with that a bit more and create some fresh unbothered buds: ...@@ -107,29 +104,29 @@ Let's play around with that a bit more and create some fresh unbothered buds:
>>> bl00mbox.plugins. >>> bl00mbox.plugins.
# print details about specific plugin # print details about specific plugin
>>> bl00mbox.plugins.ampliverter >>> bl00mbox.plugins.ampliverter
# create a new bud # create a new plugin
>>> osc = blm.new(bl00mbox.plugins.osc_fm) >>> osc = blm.new(bl00mbox.plugins.osc_fm)
>>> env = blm.new(bl00mbox.plugins.env_adsr) >>> env = blm.new(bl00mbox.plugins.env_adsr)
You can inspect properties of the new buds just as with a patch - in fact, many patches simply print You can inspect properties of the new plugins just as with a patch - in fact, many patches simply print
all their contained buds and maybe some extra info (but that doesn't have to be the case and is up all their contained plugins and maybe some extra info (but that doesn't have to be the case and is up
to the patch designer). to the patch designer).
.. note:: .. note::
As of now patch designers can hide buds within the internal structure however they like and As of now patch designers can hide plugins within the internal structure however they like and
you kind of have to know where to find stuff. We'll come up with a better solution soon! you kind of have to know where to find stuff. We'll come up with a better solution soon!
.. code-block:: pycon .. code-block:: pycon
# print general info about bud # print general info about plugin
>>> osc >>> osc
[bud 36] osc_fm [plugin 36] osc_fm
output [output]: 0 output [output]: 0
pitch [input/pitch]: 18367 / 0.0 semitones / 440.0Hz pitch [input/pitch]: 18367 / 0.0 semitones / 440.0Hz
waveform [input]: -16000 waveform [input]: -16000
lin_fm [input]: 0 lin_fm [input]: 0
# print info about a specific bud signal # print info about a specific plugin signal
>>> env.signals.trigger >>> env.signals.trigger
trigger [input/trigger]: 0 trigger [input/trigger]: 0
...@@ -186,9 +183,9 @@ and we can get them individually: ...@@ -186,9 +183,9 @@ and we can get them individually:
>>> chan_one >>> chan_one
[channel 1: shoegaze] (foreground) [channel 1: shoegaze] (foreground)
volume: 3000 volume: 3000
buds: 18 plugins: 18
[channel mixer] (1 connections) [channel mixer] (1 connections)
output in [bud 1] lowpass output in [plugin 1] lowpass
We have accidentially grabbed the channel used by the shoegaze application! Each application We have accidentially grabbed the channel used by the shoegaze application! Each application
should have its own channel(s), so in order to get a free one we'll request a free one from the should have its own channel(s), so in order to get a free one we'll request a free one from the
...@@ -209,7 +206,7 @@ backend by skipping the number. We can also provide a name for a new channel ins ...@@ -209,7 +206,7 @@ backend by skipping the number. We can also provide a name for a new channel ins
>>> chan_free >>> chan_free
[channel 3: hewwo] (foreground) [channel 3: hewwo] (foreground)
volume: 3000 volume: 3000
buds: 0 plugins: 0
[channel mixer] (0 connections) [channel mixer] (0 connections)
In case there's no free channel yet you get channel 31, the garbage channel. It behaves like In case there's no free channel yet you get channel 31, the garbage channel. It behaves like
...@@ -258,12 +255,12 @@ doing so: ...@@ -258,12 +255,12 @@ doing so:
What constitutes a channel interaction for auto channel foregrounding is a bit in motion at this point What constitutes a channel interaction for auto channel foregrounding is a bit in motion at this point
and generally unreliable. For applications it is ideal to mark the channel manually when using it. When and generally unreliable. For applications it is ideal to mark the channel manually when using it. When
exiting, an application should free the channel with automatically clears all buds. A channel should exiting, an application should free the channel with automatically clears all plugins. A channel should
be no longer used after freeing: be no longer used after freeing:
.. code-block:: pycon .. code-block:: pycon
# this clears all buds and sets the internal "free" marker to zero # this clears all plugins and sets the internal "free" marker to zero
>>> chan_one.free = True >>> chan_one.free = True
# good practice to not accidentially use a free channel # good practice to not accidentially use a free channel
>>> chan_one = None >>> chan_one = None
...@@ -278,7 +275,7 @@ Some other misc channel operations for live coding mostly: ...@@ -278,7 +275,7 @@ Some other misc channel operations for live coding mostly:
>>> bl00mbox.Channels.print_overview() >>> bl00mbox.Channels.print_overview()
[channel 3: hewwo] (foreground) [channel 3: hewwo] (foreground)
volume: 3000 volume: 3000
buds: 0 plugins: 0
[channel mixer] (0 connections) [channel mixer] (0 connections)
Example 1: Auto bassline Example 1: Auto bassline
......
...@@ -31,14 +31,15 @@ class HarmonicApp(Application): ...@@ -31,14 +31,15 @@ class HarmonicApp(Application):
self.cp_prev = captouch.read() self.cp_prev = captouch.read()
for i, synth in enumerate(self.synths): for i, synth in enumerate(self.synths):
synth.decay(500) synth.signals.decay = 500
synth.waveform(-32767) synth.signals.waveform = -32767
synth.attack(50) synth.signals.attack = 50
synth.volume(0.3) synth.signals.volume = 0.3 * 32767
synth.sustain(0.9) synth.signals.sustain = 0.9 * 32767
synth.release(800) synth.signals.release = 800
synth.fm_waveform(-32767) synth.signals.fm_waveform = -32767
synth.fm(1.5) synth.signals.output = blm.mixer
# synth.fm = 1.5
self._set_chord(3) self._set_chord(3)
self.prev_captouch = [0] * 10 self.prev_captouch = [0] * 10
...@@ -71,11 +72,11 @@ class HarmonicApp(Application): ...@@ -71,11 +72,11 @@ class HarmonicApp(Application):
self._set_chord(k) self._set_chord(k)
else: else:
k = int(i / 2) k = int(i / 2)
self.synths[k].tone(self.chord[k]) self.synths[k].signals.pitch.tone = self.chord[k]
self.synths[k].start() self.synths[k].signals.trigger.start()
self.color_intensity = 1.0 self.color_intensity = 1.0
elif (not cts.petals[i].pressed) and self.cp_prev.petals[i].pressed: elif (not cts.petals[i].pressed) and self.cp_prev.petals[i].pressed:
if (1 + i) % 2: if (1 + i) % 2:
k = int(i / 2) k = int(i / 2)
self.synths[k].stop() self.synths[k].signals.trigger.stop()
self.cp_prev = cts self.cp_prev = cts
...@@ -67,16 +67,18 @@ def run(ins: InputState) -> None: ...@@ -67,16 +67,18 @@ def run(ins: InputState) -> None:
k -= 10 k -= 10
k = 3 - k k = 3 - k
note = scale[k] + 12 * octave note = scale[k] + 12 * octave
synths[0].tone(note) synths[0].signals.pitch.tone = note
synths[0].start() synths[0].signals.trigger.start()
def init() -> None: def init() -> None:
global synths global synths
for i in range(1): for i in range(1):
synths += [blm.new(bl00mbox.patches.tinysynth_fm)] synth = blm.new(bl00mbox.patches.tinysynth_fm)
synth.signals.output = blm.mixer
synths += [synth]
for synth in synths: for synth in synths:
synth.decay(100) synth.signals.decay = 100
def foreground() -> None: def foreground() -> None:
......
...@@ -84,7 +84,8 @@ class Otamatone(Application): ...@@ -84,7 +84,8 @@ class Otamatone(Application):
self._blm = bl00mbox.Channel("Otamatone") self._blm = bl00mbox.Channel("Otamatone")
self._osc = self._blm.new(bl00mbox.patches.tinysynth) self._osc = self._blm.new(bl00mbox.patches.tinysynth)
self._osc.waveform(2) self._osc.signals.output = self._blm.mixer
self._osc.signals.waveform = 2
self._intensity = 0.0 self._intensity = 0.0
self.input.captouch.petals[self.PETAL_NO].whole.repeat_disable() self.input.captouch.petals[self.PETAL_NO].whole.repeat_disable()
...@@ -123,12 +124,12 @@ class Otamatone(Application): ...@@ -123,12 +124,12 @@ class Otamatone(Application):
if petal.whole.down: if petal.whole.down:
if self._intensity < 1.0: if self._intensity < 1.0:
self._intensity += 0.1 * (delta_ms / 20) self._intensity += 0.1 * (delta_ms / 20)
self._osc.tone(ctrl * 12) self._osc.signals.pitch.tone = ctrl * 12
self._osc.start() self._osc.signals.trigger.start()
if petal.whole.up: if petal.whole.up:
self._intensity = 0 self._intensity = 0
self._osc.stop() self._osc.signals.trigger.stop()
self._blob._yell = self._intensity * 0.8 + (ctrl + 1) * 0.1 self._blob._yell = self._intensity * 0.8 + (ctrl + 1) * 0.1
......
...@@ -65,13 +65,13 @@ class ShoegazeApp(Application): ...@@ -65,13 +65,13 @@ class ShoegazeApp(Application):
self.git_mixer.signals.input2 = self.git_strings[2].signals.output self.git_mixer.signals.input2 = self.git_strings[2].signals.output
self.git_mixer.signals.input3 = self.git_strings[3].signals.output self.git_mixer.signals.input3 = self.git_strings[3].signals.output
self.git_mixer.signals.output = self.git_lp.signals.input self.git_mixer.signals.output = self.git_lp.signals.input
self.git_fuzz.buds.dist.signals.input = self.git_lp.signals.output self.git_fuzz.signals.input = self.git_lp.signals.output
self.bass_lp.signals.input = self.bass_string.signals.output self.bass_lp.signals.input = self.bass_string.signals.output
self.main_mixer.signals.input1 = self.bass_lp.signals.output self.main_mixer.signals.input1 = self.bass_lp.signals.output
self.main_fuzz.buds.dist.signals.input = self.main_mixer.signals.output self.main_fuzz.signals.input = self.main_mixer.signals.output
self.main_fuzz.buds.dist.signals.output = self.main_lp.signals.input self.main_fuzz.signals.output = self.main_lp.signals.input
self.main_lp.signals.output = self.blm.mixer self.main_lp.signals.output = self.blm.mixer
self.git_delay.signals.time = 200 self.git_delay.signals.time = 200
...@@ -104,12 +104,12 @@ class ShoegazeApp(Application): ...@@ -104,12 +104,12 @@ class ShoegazeApp(Application):
self.main_lp.signals.freq = 2500 self.main_lp.signals.freq = 2500
self.main_lp.signals.gain = 2000 self.main_lp.signals.gain = 2000
self.git_mixer.signals.gain = 4000 self.git_mixer.signals.gain = 4000
self.main_lp.signals.input = self.main_fuzz.buds.dist.signals.output self.main_lp.signals.input = self.main_fuzz.signals.output
if self.delay_on: if self.delay_on:
self.git_delay.signals.input = self.git_fuzz.buds.dist.signals.output self.git_delay.signals.input = self.git_fuzz.signals.output
self.main_mixer.signals.input0 = self.git_delay.signals.output self.main_mixer.signals.input0 = self.git_delay.signals.output
else: else:
self.main_mixer.signals.input0 = self.git_fuzz.buds.dist.signals.output self.main_mixer.signals.input0 = self.git_fuzz.signals.output
else: else:
self.bass_lp.signals.gain = 2000 self.bass_lp.signals.gain = 2000
self.git_lp.signals.gain = 2000 self.git_lp.signals.gain = 2000
......
...@@ -48,17 +48,21 @@ class SimpleDrums(Application): ...@@ -48,17 +48,21 @@ class SimpleDrums(Application):
# Dot(20, 20, 0, 40, self._track_col(1)).draw(0,ctx) # Dot(20, 20, 0, 40, self._track_col(1)).draw(0,ctx)
self.snare = self.blm.new(bl00mbox.patches.sampler, "snare.wav") self.snare = self.blm.new(bl00mbox.patches.sampler, "snare.wav")
# Dot(30, 30, 2, -20, self._track_col(2)).draw(0,ctx) # Dot(30, 30, 2, -20, self._track_col(2)).draw(0,ctx)
self.kick.sampler.signals.trigger = self.seq.seqs[0].signals.output self.kick.signals.output = self.blm.mixer
self.hat.sampler.signals.trigger = self.seq.seqs[1].signals.output self.snare.signals.output = self.blm.mixer
self.snare.sampler.signals.trigger = self.seq.seqs[2].signals.output self.hat.signals.output = self.blm.mixer
self.kick.signals.trigger = self.seq.plugins.sequencer0.signals.output
self.hat.signals.trigger = self.seq.plugins.sequencer1.signals.output
self.snare.signals.trigger = self.seq.plugins.sequencer2.signals.output
self.seq.signals.bpm.value = 80
self.track_names = ["kick", "hihat", "snare"] self.track_names = ["kick", "hihat", "snare"]
self.track = 0 self.track = 0
self.seq.bpm = 80
self.blm.background_mute_override = True self.blm.background_mute_override = True
self.tap_tempo_press_counter = 0 self.tap_tempo_press_counter = 0
self.delta_acc = 0 self.delta_acc = 0
self.stopped = False self.stopped = False
self.bpm = self.seq.bpm self.bpm = self.seq.signals.bpm.value
# True if a given group should be highlighted, when a corresponding # True if a given group should be highlighted, when a corresponding
# petal is pressed. # petal is pressed.
...@@ -96,7 +100,7 @@ class SimpleDrums(Application): ...@@ -96,7 +100,7 @@ class SimpleDrums(Application):
(0.15, 0.15, 0.15), (0.15, 0.15, 0.15),
) )
) )
st = self.seq.seqs[0].signals.step.value st = self.seq.signals.step.value
for track in range(3): for track in range(3):
rgb = self._track_col(track) rgb = self._track_col(track)
...@@ -143,7 +147,7 @@ class SimpleDrums(Application): ...@@ -143,7 +147,7 @@ class SimpleDrums(Application):
ctx.move_to(0, -65) ctx.move_to(0, -65)
ctx.rgb(255, 255, 255) ctx.rgb(255, 255, 255)
ctx.text(str(self.seq.bpm) + " bpm") ctx.text(str(self.seq.signals.bpm) + " bpm")
ctx.font_size = 15 ctx.font_size = 15
...@@ -160,7 +164,7 @@ class SimpleDrums(Application): ...@@ -160,7 +164,7 @@ class SimpleDrums(Application):
def think(self, ins: InputState, delta_ms: int) -> None: def think(self, ins: InputState, delta_ms: int) -> None:
super().think(ins, delta_ms) super().think(ins, delta_ms)
st = self.seq.seqs[0].signals.step.value st = self.seq.signals.step.value
rgb = self._track_col(self.track) rgb = self._track_col(self.track)
if st == 0: if st == 0:
leds.set_all_rgb(*[int(x / 4) for x in rgb]) leds.set_all_rgb(*[int(x / 4) for x in rgb])
...@@ -183,19 +187,19 @@ class SimpleDrums(Application): ...@@ -183,19 +187,19 @@ class SimpleDrums(Application):
self.track = (self.track - 1) % 3 self.track = (self.track - 1) % 3
if petals[0].whole.pressed: if petals[0].whole.pressed:
if self.stopped: if self.stopped:
self.seq.bpm = self.bpm self.seq.signals.bpm = self.bpm
self.blm.background_mute_override = True self.blm.background_mute_override = True
self.stopped = False self.stopped = False
elif self.delta_acc < 3000 and self.delta_acc > 10: elif self.delta_acc < 3000 and self.delta_acc > 10:
bpm = int(60000 / self.delta_acc) bpm = int(60000 / self.delta_acc)
if bpm > 40 and bpm < 500: if bpm > 40 and bpm < 500:
self.seq.bpm = bpm self.seq.signals.bpm = bpm
self.bpm = bpm self.bpm = bpm
self.delta_acc = 0 self.delta_acc = 0
if petals[0].whole.down: if petals[0].whole.down:
if self.tap_tempo_press_counter > 500: if self.tap_tempo_press_counter > 500:
self.seq.bpm = 0 self.seq.signals.bpm = 0
self.stopped = True self.stopped = True
self.blm.background_mute_override = False self.blm.background_mute_override = False
else: else:
......
...@@ -10,124 +10,106 @@ except ImportError: ...@@ -10,124 +10,106 @@ except ImportError:
class _Patch: class _Patch:
def bl00mbox_patch_marker(self): def __init__(self, chan):
return True self.plugins = _PatchPluginList()
self.signals = _PatchSignalList()
self._channel = chan
def __repr__(self):
ret = "[patch] " + type(self).__name__
ret += "\n [signals:]\n " + "\n ".join(repr(self.signals).split("\n"))
ret += "\n [plugins:]\n " + "\n ".join(repr(self.plugins).split("\n"))
return ret
class _PatchSignalList:
pass
class _PatchItemList:
def __init__(self):
self._items = []
class _PatchBudList: def __iter__(self):
pass return iter(self._items)
def __repr__(self):
return "\n".join([x + ": " + repr(getattr(self, x)) for x in self._items])
class tinysynth(_Patch): def __setattr__(self, key, value):
def __init__(self, chan): current_value = getattr(self, key, None)
self.channel = chan
self.SINE = -32767
self.TRI = -1
self.SQUARE = 1
self.SAW = 32767
self.osc = chan._new_bud(420)
self.env = chan._new_bud(42)
self.amp = chan._new_bud(69)
self.amp.signals.output.value = chan.mixer
self.amp.signals.gain.value = self.env.signals.output
self.amp.signals.input.value = self.osc.signals.output
self.env.signals.sustain.value = 0
self.env.signals.decay.value = 500
self.release(100)
def __repr__(self): if current_value is None and not key.startswith("_"):
ret = "[patch] tinysynth" self._items.append(key)
ret += "\n " + "\n ".join(repr(self.osc).split("\n"))
ret += "\n " + "\n ".join(repr(self.env).split("\n"))
ret += "\n " + "\n ".join(repr(self.amp).split("\n"))
return ret
def tone(self, val): super().__setattr__(key, value)
self.osc.signals.pitch.tone = val
def freq(self, val):
self.osc.signals.pitch.freq = val
def volume(self, val): class _PatchSignalList(_PatchItemList):
self.env.signals.input.value = 32767 * val def __setattr__(self, key, value):
current_value = getattr(self, key, None)
if isinstance(current_value, bl00mbox.Signal):
current_value.value = value
return
super().__setattr__(key, value)
def start(self):
self.env.signals.trigger.start()
def stop(self): class _PatchPluginList(_PatchItemList):
self.env.signals.trigger.stop() pass
def waveform(self, val):
self.osc.signals.waveform.value = val
def attack(self, val): class tinysynth(_Patch):
self.env.signals.attack.value = val def __init__(self, chan):
super().__init__(chan)
self.plugins.osc = self._channel.new(bl00mbox.plugins.osc_fm)
self.plugins.env = self._channel.new(bl00mbox.plugins.env_adsr)
self.plugins.amp = self._channel.new(bl00mbox.plugins.ampliverter)
def decay(self, val): self.plugins.amp.signals.gain = self.plugins.env.signals.output
self.env.signals.decay.value = val self.plugins.amp.signals.input = self.plugins.osc.signals.output
self.plugins.env.signals.decay = 500
def sustain(self, val): self.signals.output = self.plugins.amp.signals.output
self.env.signals.sustain.value = val * 32767 self.signals.pitch = self.plugins.osc.signals.pitch
self.signals.waveform = self.plugins.osc.signals.waveform
def release(self, val): self.signals.trigger = self.plugins.env.signals.trigger
self.env.signals.release.value = val self.signals.attack = self.plugins.env.signals.attack
self.signals.sustain = self.plugins.env.signals.sustain
self.signals.decay = self.plugins.env.signals.decay
self.signals.release = self.plugins.env.signals.release
self.signals.volume = self.plugins.env.signals.input.value
self.signals.release = 100
class tinysynth_fm(tinysynth): class tinysynth_fm(tinysynth):
def __init__(self, chan): def __init__(self, chan):
tinysynth.__init__(self, chan) super().__init__(chan)
self.mod_osc = chan._new_bud(420) self.plugins.mod_osc = self._channel.new(bl00mbox.plugins.osc_fm)
self.fm_mult = 2.5 self.plugins.mod_osc.signals.output = self.plugins.osc.signals.lin_fm
self.mod_osc.signals.output.value = self.osc.signals.lin_fm self.signals.fm_waveform = self.plugins.mod_osc.signals.waveform
self.decay(1000) self.signals.fm_pitch = self.plugins.mod_osc.signals.pitch
self.attack(20) self.signals.decay = 1000
self._update_mod_osc() self.signals.attack = 20
self.fm_waveform(self.SQUARE) self.signals.waveform = -1
self.waveform(self.TRI) self.signals.fm_waveform = 0
def fm_waveform(self, val):
self.mod_osc.signals.waveform.value = val
def __repr__(self): self.sync_mod_osc(2.5)
ret = tinysynth.__repr__(self)
ret = ret.split("\n")
ret[0] += "_fm"
ret = "\n".join(ret)
ret += "\n " + "\n ".join(repr(self.mod_osc).split("\n"))
return ret
def fm(self, val):
self.fm_mult = val
self._update_mod_osc()
def tone(self, val):
self.osc.signals.pitch.tone = val
self._update_mod_osc()
def freq(self, val):
self.osc.signals.pitch.freq = val
self._update_mod_osc()
def _update_mod_osc(self): def sync_mod_osc(self, val):
self.mod_osc.signals.pitch.freq = self.fm_mult * self.osc.signals.pitch.freq self.signals.fm_pitch.freq = int(val) * self.signals.pitch.freq
class sampler(_Patch): class sampler(_Patch):
"""needs a wave file with path relative to samples/""" """
needs a wave file with path relative to /flash/sys/samples/
"""
def __init__(self, chan, filename): def __init__(self, chan, filename):
super().__init__(chan)
if wave is None: if wave is None:
pass pass
# raise Bl00mboxError("wave library not found") # raise Bl00mboxError("wave library not found")
f = wave.open("/flash/sys/samples/" + filename, "r") f = wave.open("/flash/sys/samples/" + filename, "r")
self.len_frames = f.getnframes() self.len_frames = f.getnframes()
self.sampler = chan._new_bud(696969, self.len_frames) self.plugins.sampler = chan._new_plugin(696969, self.len_frames)
assert f.getsampwidth() == 2 assert f.getsampwidth() == 2
assert f.getnchannels() in (1, 2) assert f.getnchannels() in (1, 2)
...@@ -135,12 +117,12 @@ class sampler(_Patch): ...@@ -135,12 +117,12 @@ class sampler(_Patch):
if f.getnchannels() == 1: if f.getnchannels() == 1:
# fast path for mono # fast path for mono
table = self.sampler.table_bytearray table = self.plugins.sampler.table_bytearray
for i in range(0, self.len_frames * 2, 100): for i in range(0, self.len_frames * 2, 100):
table[i : i + 100] = f.readframes(50) table[i : i + 100] = f.readframes(50)
else: else:
# somewhat fast path for stereo # somewhat fast path for stereo
table = self.sampler.table_int16_array 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) frame = f.readframes(1)
value = int.from_bytes(frame[0:2], "little") value = int.from_bytes(frame[0:2], "little")
...@@ -148,13 +130,8 @@ class sampler(_Patch): ...@@ -148,13 +130,8 @@ class sampler(_Patch):
f.close() f.close()
self._filename = filename self._filename = filename
self.sampler.signals.output = chan.mixer self.signals.trigger = self.plugins.sampler.signals.trigger
self.signals.output = self.plugins.sampler.signals.output
def start(self):
self.sampler.signals.trigger.start()
def stop(self):
self.sampler.signals.trigger.stop()
@property @property
def filename(self): def filename(self):
...@@ -162,30 +139,42 @@ class sampler(_Patch): ...@@ -162,30 +139,42 @@ class sampler(_Patch):
class step_sequencer(_Patch): class step_sequencer(_Patch):
def __init__(self, chan): def __init__(self, chan, num=4):
super().__init__(chan)
if num > 32:
num = 32
if num < 0:
num = 0
self.seqs = [] self.seqs = []
for i in range(4): prev_seq = None
seq = chan._new_bud(56709) for i in range(num):
seq = chan._new_plugin(56709)
seq.table = [-32767] + ([0] * 16) seq.table = [-32767] + ([0] * 16)
if len(self.seqs): if prev_seq is None:
self.seqs[-1].signals.sync_out = seq.signals.sync_in self.signals.bpm = seq.signals.bpm
self.signals.beat_div = seq.signals.beat_div
self.signals.step = seq.signals.step
self.signals.step_len = seq.signals.step_len
else:
prev_seq.signals.sync_out = seq.signals.sync_in
prev_seq = seq
self.seqs += [seq] self.seqs += [seq]
self._bpm = 120 setattr(self.plugins, "sequencer" + str(i), seq)
def __repr__(self): def __repr__(self):
ret = "[patch] step sequencer" ret = "[patch] step sequencer"
# ret += "\n " + "\n ".join(repr(self.seqs[0]).split("\n")) # ret += "\n " + "\n ".join(repr(self.seqs[0]).split("\n"))
ret += ( ret += (
"\n bpm: " "\n bpm: "
+ str(self.seqs[0].signals.bpm.value) + str(self.signals.bpm.value)
+ " @ 1/" + " @ 1/"
+ str(self.seqs[0].signals.beat_div.value) + str(self.signals.beat_div.value)
) )
ret += ( ret += (
"\n step: " " step: "
+ str(self.seqs[0].signals.step.value) + str(self.signals.step.value)
+ "/" + "/"
+ str(self.seqs[0].signals.step_len.value) + str(self.signals.step_len.value)
) )
ret += "\n [tracks]" ret += "\n [tracks]"
for x, seq in enumerate(self.seqs): for x, seq in enumerate(self.seqs):
...@@ -196,18 +185,9 @@ class step_sequencer(_Patch): ...@@ -196,18 +185,9 @@ class step_sequencer(_Patch):
+ "".join(["X " if x > 0 else ". " for x in seq.table[1:]]) + "".join(["X " if x > 0 else ". " for x in seq.table[1:]])
+ "]" + "]"
) )
ret += "\n" + "\n".join(super().__repr__().split("\n")[1:])
return ret return ret
@property
def bpm(self):
return self._bpm
@bpm.setter
def bpm(self, bpm):
for seq in self.seqs:
seq.signals.bpm.value = bpm
self._bpm = bpm
def trigger_start(self, track, step): def trigger_start(self, track, step):
a = self.seqs[track].table a = self.seqs[track].table
a[step + 1] = 32767 a[step + 1] = 32767
...@@ -228,18 +208,13 @@ class step_sequencer(_Patch): ...@@ -228,18 +208,13 @@ class step_sequencer(_Patch):
else: else:
self.trigger_stop(track, step) self.trigger_stop(track, step)
@property
def step(self):
return self.seqs[0].signals.step
class fuzz(_Patch): class fuzz(_Patch):
def __init__(self, chan): def __init__(self, chan):
self.buds = _PatchBudList() super().__init__(chan)
self.signals = _PatchSignalList() self.plugins.dist = chan.new(bl00mbox.plugins.distortion)
self.buds.dist = chan.new(bl00mbox.plugins.distortion) self.signals.input = self.plugins.dist.signals.input
self.signals.input = self.buds.dist.signals.input self.signals.output = self.plugins.dist.signals.output
self.signals.output = self.buds.dist.signals.output
self._intensity = 2 self._intensity = 2
self._volume = 32767 self._volume = 32767
self._gate = 0 self._gate = 0
...@@ -287,29 +262,27 @@ class fuzz(_Patch): ...@@ -287,29 +262,27 @@ class fuzz(_Patch):
gate = self.gate >> 9 gate = self.gate >> 9
for i in range(64 - gate, 64 + gate): for i in range(64 - gate, 64 + gate):
table[i] = 0 table[i] = 0
self.buds.dist.table = table self.plugins.dist.table = table
class karplus_strong(_Patch): class karplus_strong(_Patch):
def __init__(self, chan): def __init__(self, chan):
self.buds = _PatchBudList() super().__init__(chan)
self.signals = _PatchSignalList() self.plugins.noise = chan._new_plugin(bl00mbox.plugins.noise_burst)
self.plugins.noise.signals.length = 25
self.buds.noise = chan._new_bud(bl00mbox.plugins.noise_burst)
self.buds.noise.signals.length = 25
self.buds.flanger = chan._new_bud(bl00mbox.plugins.flanger) self.plugins.flanger = chan._new_plugin(bl00mbox.plugins.flanger)
self.buds.flanger.signals.resonance = 32500 self.plugins.flanger.signals.resonance = 32500
self.buds.flanger.signals.manual.tone = "A2" self.plugins.flanger.signals.manual.tone = "A2"
self.buds.flanger.signals.input = self.buds.noise.signals.output self.plugins.flanger.signals.input = self.plugins.noise.signals.output
self.signals.trigger = self.buds.noise.signals.trigger self.signals.trigger = self.plugins.noise.signals.trigger
self.signals.pitch = self.buds.flanger.signals.manual self.signals.pitch = self.plugins.flanger.signals.manual
self.signals.output = self.buds.flanger.signals.output self.signals.output = self.plugins.flanger.signals.output
self.signals.level = self.buds.flanger.signals.level self.signals.level = self.plugins.flanger.signals.level
self.decay = 1000 self.decay = 1000
@property @property
...@@ -318,9 +291,9 @@ class karplus_strong(_Patch): ...@@ -318,9 +291,9 @@ class karplus_strong(_Patch):
@decay.setter @decay.setter
def decay(self, val): def decay(self, val):
tone = self.buds.flanger.signals.manual.tone tone = self.plugins.flanger.signals.manual.tone
loss = (50 * (2 ** (-tone / 12))) // (val / 1000) loss = (50 * (2 ** (-tone / 12))) // (val / 1000)
if loss < 2: if loss < 2:
loss = 2 loss = 2
self.buds.flanger.signals.resonance = 32767 - loss self.plugins.flanger.signals.resonance = 32767 - loss
self._decay = val self._decay = val
...@@ -14,22 +14,22 @@ class Bl00mboxError(Exception): ...@@ -14,22 +14,22 @@ class Bl00mboxError(Exception):
pass pass
def _makeSignal(bud, signal_num): def _makeSignal(plugin, signal_num):
hints = sys_bl00mbox.channel_bud_get_signal_hints( hints = sys_bl00mbox.channel_bud_get_signal_hints(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
if hints & 2: if hints & 2:
signal = SignalOutput(bud, signal_num) signal = SignalOutput(plugin, signal_num)
signal._hints = "output" signal._hints = "output"
elif hints & 1: elif hints & 1:
if hints & 4: if hints & 4:
signal = SignalInputTrigger(bud, signal_num) signal = SignalInputTrigger(plugin, signal_num)
signal._hints = "input/trigger" signal._hints = "input/trigger"
elif hints & 32: elif hints & 32:
signal = SignalInputPitch(bud, signal_num) signal = SignalInputPitch(plugin, signal_num)
signal._hints = "input/pitch" signal._hints = "input/pitch"
else: else:
signal = SignalInput(bud, signal_num) signal = SignalInput(plugin, signal_num)
signal._hints = "input" signal._hints = "input"
return signal return signal
...@@ -44,7 +44,7 @@ class ChannelMixer: ...@@ -44,7 +44,7 @@ class ChannelMixer:
ret += " (" + str(len(self.connections)) + " connections)" ret += " (" + str(len(self.connections)) + " connections)"
for con in self.connections: for con in self.connections:
ret += "\n " + con.name ret += "\n " + con.name
ret += " in [bud " + str(con._bud.bud_num) + "] " + con._bud.name ret += " in [plugin " + str(con._plugin.bud_num) + "] " + con._plugin.name
return ret return ret
def _unplug_all(self): def _unplug_all(self):
...@@ -61,33 +61,33 @@ class ChannelMixer: ...@@ -61,33 +61,33 @@ class ChannelMixer:
s = sys_bl00mbox.channel_get_signal_by_mixer_list_pos( s = sys_bl00mbox.channel_get_signal_by_mixer_list_pos(
self._channel.channel_num, i self._channel.channel_num, i
) )
sig = Signal(Bud(self._channel, 0, bud_num=b), s) sig = Signal(Plugin(self._channel, 0, bud_num=b), s)
ret += [sig] ret += [sig]
return ret return ret
class Signal: class Signal:
def __init__(self, bud, signal_num): def __init__(self, plugin, signal_num):
self._bud = bud self._plugin = plugin
self._signal_num = signal_num self._signal_num = signal_num
self._name = sys_bl00mbox.channel_bud_get_signal_name( self._name = sys_bl00mbox.channel_bud_get_signal_name(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
mpx = sys_bl00mbox.channel_bud_get_signal_name_multiplex( mpx = sys_bl00mbox.channel_bud_get_signal_name_multiplex(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
if mpx != (-1): if mpx != (-1):
self._name += str(mpx) self._name += str(mpx)
self._description = sys_bl00mbox.channel_bud_get_signal_description( self._description = sys_bl00mbox.channel_bud_get_signal_description(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
self._unit = sys_bl00mbox.channel_bud_get_signal_unit( self._unit = sys_bl00mbox.channel_bud_get_signal_unit(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
self._hints = "" self._hints = ""
def __repr__(self): def __repr__(self):
self._bud._check_existence() self._plugin._check_existence()
ret = self.name ret = self.name
if len(self.unit): if len(self.unit):
...@@ -110,10 +110,10 @@ class Signal: ...@@ -110,10 +110,10 @@ class Signal:
conret += [ conret += [
direction direction
+ con.name + con.name
+ " in [bud " + " in [plugin "
+ str(con._bud.bud_num) + str(con._plugin.bud_num)
+ "] " + "] "
+ con._bud.name + con._plugin.name
] ]
if isinstance(con, ChannelMixer): if isinstance(con, ChannelMixer):
conret += [" ==> [channel mixer]"] conret += [" ==> [channel mixer]"]
...@@ -146,9 +146,9 @@ class Signal: ...@@ -146,9 +146,9 @@ class Signal:
@property @property
def value(self): def value(self):
self._bud._check_existence() self._plugin._check_existence()
return sys_bl00mbox.channel_bud_get_signal_value( return sys_bl00mbox.channel_bud_get_signal_value(
self._bud.channel_num, self._bud.bud_num, self._signal_num self._plugin.channel_num, self._plugin.bud_num, self._signal_num
) )
...@@ -157,29 +157,31 @@ class SignalOutput(Signal): ...@@ -157,29 +157,31 @@ class SignalOutput(Signal):
def value(self, val): def value(self, val):
if val == None: if val == None:
sys_bl00mbox.channel_disconnect_signal_tx( sys_bl00mbox.channel_disconnect_signal_tx(
self._bud.channel_num, self._bud.bud_num, self._signal_num self._plugin.channel_num, self._plugin.bud_num, self._signal_num
) )
elif isinstance(val, SignalInput): elif isinstance(val, SignalInput):
val.value = self val.value = self
elif isinstance(val, ChannelMixer): elif isinstance(val, ChannelMixer):
if val._channel.channel_num == self._bud.channel_num: if val._channel.channel_num == self._plugin.channel_num:
sys_bl00mbox.channel_connect_signal_to_output_mixer( sys_bl00mbox.channel_connect_signal_to_output_mixer(
self._bud.channel_num, self._bud.bud_num, self._signal_num self._plugin.channel_num, self._plugin.bud_num, self._signal_num
) )
@property @property
def connections(self): def connections(self):
cons = [] cons = []
chan = self._bud.channel_num chan = self._plugin.channel_num
bud = self._bud.bud_num bud_num = self._plugin.bud_num
sig = self._signal_num sig = self._signal_num
for i in range(sys_bl00mbox.channel_subscriber_num(chan, bud, sig)): for i in range(sys_bl00mbox.channel_subscriber_num(chan, bud_num, sig)):
b = sys_bl00mbox.channel_get_bud_by_subscriber_list_pos(chan, bud, sig, i) b = sys_bl00mbox.channel_get_bud_by_subscriber_list_pos(
chan, bud_num, sig, i
)
s = sys_bl00mbox.channel_get_signal_by_subscriber_list_pos( s = sys_bl00mbox.channel_get_signal_by_subscriber_list_pos(
chan, bud, sig, i chan, bud_num, sig, i
) )
if (s >= 0) and (b > 0): if (s >= 0) and (b > 0):
cons += [_makeSignal(Bud(Channel(chan), 0, bud_num=b), s)] cons += [_makeSignal(Plugin(Channel(chan), 0, bud_num=b), s)]
elif s == -1: elif s == -1:
cons += [ChannelMixer(Channel(chan))] cons += [ChannelMixer(Channel(chan))]
return cons return cons
...@@ -188,18 +190,18 @@ class SignalOutput(Signal): ...@@ -188,18 +190,18 @@ class SignalOutput(Signal):
class SignalInput(Signal): class SignalInput(Signal):
@Signal.value.setter @Signal.value.setter
def value(self, val): def value(self, val):
self._bud._check_existence() self._plugin._check_existence()
if isinstance(val, SignalOutput): if isinstance(val, SignalOutput):
if len(self.connections): if len(self.connections):
if not sys_bl00mbox.channel_disconnect_signal_rx( if not sys_bl00mbox.channel_disconnect_signal_rx(
self._bud.channel_num, self._bud.bud_num, self._signal_num self._plugin.channel_num, self._plugin.bud_num, self._signal_num
): ):
return return
sys_bl00mbox.channel_connect_signal( sys_bl00mbox.channel_connect_signal(
self._bud.channel_num, self._plugin.channel_num,
self._bud.bud_num, self._plugin.bud_num,
self._signal_num, self._signal_num,
val._bud.bud_num, val._plugin.bud_num,
val._signal_num, val._signal_num,
) )
elif isinstance(val, SignalInput): elif isinstance(val, SignalInput):
...@@ -208,23 +210,26 @@ class SignalInput(Signal): ...@@ -208,23 +210,26 @@ class SignalInput(Signal):
elif (type(val) == int) or (type(val) == float): elif (type(val) == int) or (type(val) == float):
if len(self.connections): if len(self.connections):
if not sys_bl00mbox.channel_disconnect_signal_rx( if not sys_bl00mbox.channel_disconnect_signal_rx(
self._bud.channel_num, self._bud.bud_num, self._signal_num self._plugin.channel_num, self._plugin.bud_num, self._signal_num
): ):
return return
sys_bl00mbox.channel_bud_set_signal_value( sys_bl00mbox.channel_bud_set_signal_value(
self._bud.channel_num, self._bud.bud_num, self._signal_num, int(val) self._plugin.channel_num,
self._plugin.bud_num,
self._signal_num,
int(val),
) )
@property @property
def connections(self): def connections(self):
cons = [] cons = []
chan = self._bud.channel_num chan = self._plugin.channel_num
bud = self._bud.bud_num bud = self._plugin.bud_num
sig = self._signal_num sig = self._signal_num
b = sys_bl00mbox.channel_get_source_bud(chan, bud, sig) b = sys_bl00mbox.channel_get_source_bud(chan, bud, sig)
s = sys_bl00mbox.channel_get_source_signal(chan, bud, sig) s = sys_bl00mbox.channel_get_source_signal(chan, bud, sig)
if (s >= 0) and (b > 0): if (s >= 0) and (b > 0):
cons += [_makeSignal(Bud(Channel(chan), 0, bud_num=b), s)] cons += [_makeSignal(Plugin(Channel(chan), 0, bud_num=b), s)]
return cons return cons
...@@ -240,8 +245,8 @@ class SignalInputTrigger(SignalInput): ...@@ -240,8 +245,8 @@ class SignalInputTrigger(SignalInput):
class SignalInputPitch(SignalInput): class SignalInputPitch(SignalInput):
def __init__(self, bud, signal_num): def __init__(self, plugin, signal_num):
SignalInput.__init__(self, bud, signal_num) SignalInput.__init__(self, plugin, signal_num)
@property @property
def tone(self): def tone(self):
...@@ -271,26 +276,26 @@ class SignalInputPitch(SignalInput): ...@@ -271,26 +276,26 @@ class SignalInputPitch(SignalInput):
class SignalList: class SignalList:
def __init__(self, bud): def __init__(self, plugin):
self._list = [] self._list = []
for signal_num in range( for signal_num in range(
sys_bl00mbox.channel_bud_get_num_signals(bud.channel_num, bud.bud_num) sys_bl00mbox.channel_bud_get_num_signals(plugin.channel_num, plugin.bud_num)
): ):
hints = sys_bl00mbox.channel_bud_get_signal_hints( hints = sys_bl00mbox.channel_bud_get_signal_hints(
bud.channel_num, bud.bud_num, signal_num plugin.channel_num, plugin.bud_num, signal_num
) )
if hints & 2: if hints & 2:
signal = SignalOutput(bud, signal_num) signal = SignalOutput(plugin, signal_num)
signal._hints = "output" signal._hints = "output"
elif hints & 1: elif hints & 1:
if hints & 4: if hints & 4:
signal = SignalInputTrigger(bud, signal_num) signal = SignalInputTrigger(plugin, signal_num)
signal._hints = "input/trigger" signal._hints = "input/trigger"
elif hints & 32: elif hints & 32:
signal = SignalInputPitch(bud, signal_num) signal = SignalInputPitch(plugin, signal_num)
signal._hints = "input/pitch" signal._hints = "input/pitch"
else: else:
signal = SignalInput(bud, signal_num) signal = SignalInput(plugin, signal_num)
signal._hints = "input" signal._hints = "input"
self._list += [signal] self._list += [signal]
setattr(self, signal.name.split(" ")[0], signal) setattr(self, signal.name.split(" ")[0], signal)
...@@ -303,7 +308,7 @@ class SignalList: ...@@ -303,7 +308,7 @@ class SignalList:
super().__setattr__(key, value) super().__setattr__(key, value)
class Bud: class Plugin:
def __init__(self, channel, plugin_id, init_var=0, bud_num=None): def __init__(self, channel, plugin_id, init_var=0, bud_num=None):
self._channel_num = channel.channel_num self._channel_num = channel.channel_num
if bud_num == None: if bud_num == None:
...@@ -312,7 +317,7 @@ class Bud: ...@@ -312,7 +317,7 @@ class Bud:
self.channel_num, self.plugin_id, init_var self.channel_num, self.plugin_id, init_var
) )
if self._bud_num == None: if self._bud_num == None:
raise Bl00mboxError("bud init failed") raise Bl00mboxError("plugin init failed")
else: else:
self._bud_num = bud_num self._bud_num = bud_num
self._check_existence() self._check_existence()
...@@ -324,7 +329,7 @@ class Bud: ...@@ -324,7 +329,7 @@ class Bud:
def __repr__(self): def __repr__(self):
self._check_existence() self._check_existence()
ret = "[bud " + str(self.bud_num) + "] " + self.name ret = "[plugin " + str(self.bud_num) + "] " + self.name
for sig in self.signals._list: for sig in self.signals._list:
ret += "\n " + "\n ".join(repr(sig).split("\n")) ret += "\n " + "\n ".join(repr(sig).split("\n"))
return ret return ret
...@@ -335,7 +340,7 @@ class Bud: ...@@ -335,7 +340,7 @@ class Bud:
def _check_existence(self): def _check_existence(self):
if not sys_bl00mbox.channel_bud_exists(self.channel_num, self.bud_num): if not sys_bl00mbox.channel_bud_exists(self.channel_num, self.bud_num):
raise Bl00mboxError("bud has been deleted") raise Bl00mboxError("plugin has been deleted")
@property @property
def channel_num(self): def channel_num(self):
...@@ -429,9 +434,9 @@ class Channel: ...@@ -429,9 +434,9 @@ class Channel:
ret += " (background mute override)" ret += " (background mute override)"
ret += "\n volume: " + str(self.volume) ret += "\n volume: " + str(self.volume)
b = sys_bl00mbox.channel_buds_num(self.channel_num) b = sys_bl00mbox.channel_buds_num(self.channel_num)
ret += "\n buds: " + str(b) ret += "\n plugins: " + str(b)
if len(self.buds) != b: if len(self.plugins) != b:
ret += " (desync" + str(len(self.buds)) + ")" ret += " (desync" + str(len(self.plugins)) + ")"
ret += "\n " + "\n ".join(repr(self.mixer).split("\n")) ret += "\n " + "\n ".join(repr(self.mixer).split("\n"))
return ret return ret
...@@ -463,16 +468,16 @@ class Channel: ...@@ -463,16 +468,16 @@ class Channel:
self.clear() self.clear()
sys_bl00mbox.channel_set_free(self.channel_num, val) sys_bl00mbox.channel_set_free(self.channel_num, val)
def _new_bud(self, thing, init_var=None): def _new_plugin(self, thing, init_var=None):
bud_init_var = 0 plugin_init_var = 0
if (type(init_var) == int) or (type(init_var) == float): if (type(init_var) == int) or (type(init_var) == float):
bud_init_var = int(init_var) plugin_init_var = int(init_var)
bud = None plugin = None
if isinstance(thing, bl00mbox._plugins._Plugin): if isinstance(thing, bl00mbox._plugins._Plugin):
bud = Bud(self, thing.plugin_id, bud_init_var) plugin = Plugin(self, thing.plugin_id, plugin_init_var)
if type(thing) == int: if type(thing) == int:
bud = Bud(self, thing, bud_init_var) plugin = Plugin(self, thing, plugin_init_var)
return bud return plugin
def _new_patch(self, patch, init_var=None): def _new_patch(self, patch, init_var=None):
if init_var == None: if init_var == None:
...@@ -499,17 +504,17 @@ class Channel: ...@@ -499,17 +504,17 @@ class Channel:
if issubclass(thing, bl00mbox.patches._Patch): if issubclass(thing, bl00mbox.patches._Patch):
return self._new_patch(thing, init_var) return self._new_patch(thing, init_var)
if isinstance(thing, bl00mbox._plugins._Plugin) or (type(thing) == int): if isinstance(thing, bl00mbox._plugins._Plugin) or (type(thing) == int):
return self._new_bud(thing, init_var) return self._new_plugin(thing, init_var)
@property @property
def buds(self): def plugins(self):
buds = [] plugins = []
for i in range(sys_bl00mbox.channel_buds_num(self.channel_num)): for i in range(sys_bl00mbox.channel_buds_num(self.channel_num)):
b = sys_bl00mbox.channel_get_bud_by_list_pos(self.channel_num, i) b = sys_bl00mbox.channel_get_bud_by_list_pos(self.channel_num, i)
bud = Bud(self, 0, bud_num=b) plugin = Plugin(self, 0, bud_num=b)
buds += [bud] plugins += [plugin]
return buds return plugins
@property @property
def channel_num(self): def channel_num(self):
......
...@@ -2,47 +2,42 @@ import bl00mbox ...@@ -2,47 +2,42 @@ import bl00mbox
from typing import List from typing import List
class _Patch: ... class _Patch:
plugins: _PatchPluginList
signals: _PatchSignalList
class _PatchSignalList: class _PatchSignalList:
def __getattr__(self, name: str) -> bl00mbox.Signal: ... def __getattr__(self, name: str) -> bl00mbox.Signal: ...
def __setattr__(
class _PatchBudList: self,
def __getattr__(self, name: str) -> bl00mbox.Bud: ... name: str,
value: int | float | bl00mbox.Signal | bl00mbox.ChannelMixer,
class tinysynth(_Patch): ) -> None: ...
def decay(self, v: float) -> None: ...
def waveform(self, v: int) -> None: ... class _PatchPluginList:
def attack(self, v: float) -> None: ... def __getattr__(self, name: str) -> bl00mbox.Plugin: ...
def volume(self, v: float) -> None: ... def __setattr__(
def sustain(self, v: float) -> None: ... self,
def release(self, v: float) -> None: ... name: str,
def tone(self, v: float) -> None: ... value: bl00mbox.Plugin,
def start(self) -> None: ... ) -> None: ...
def stop(self) -> None: ...
class tinysynth(_Patch): ...
class tinysynth_fm(tinysynth): class tinysynth_fm(tinysynth): ...
def fm_waveform(self, v: int) -> None: ...
def fm(self, v: float) -> None: ...
class step_sequencer(_Patch): class step_sequencer(_Patch):
seqs: List[bl00mbox.Bud] seqs: List[bl00mbox.Plugin]
bpm: int bpm: int
def trigger_state(self, track: int, i: int) -> bool: ... def trigger_state(self, track: int, i: int) -> bool: ...
def trigger_toggle(self, track: int, i: int) -> None: ... def trigger_toggle(self, track: int, i: int) -> None: ...
class sampler(_Patch): class sampler(_Patch): ...
sampler: bl00mbox.Bud
class fuzz(_Patch): class fuzz(_Patch):
buds: _PatchBudList
signals: _PatchSignalList
volume: int volume: int
intensity: float intensity: float
gate: int gate: int
class karplus_strong(_Patch): class karplus_strong(_Patch):
buds: _PatchBudList
signals: _PatchSignalList
decay: int decay: int
...@@ -13,7 +13,7 @@ class Signal: ...@@ -13,7 +13,7 @@ class Signal:
value: Any value: Any
# value: None | int | float | "Signal" | "ChannelMixer" # value: None | int | float | "Signal" | "ChannelMixer"
def __init__(self, bud: "Bud", signal_num: int): ... def __init__(self, plugin: "Plugin", signal_num: int): ...
# SignalInputTrigger functions # SignalInputTrigger functions
def start(self, velocity: int = 32767) -> None: ... def start(self, velocity: int = 32767) -> None: ...
...@@ -28,7 +28,7 @@ class SignalList: ...@@ -28,7 +28,7 @@ class SignalList:
def __setattr__(self, name: str, value: Signal | int | "ChannelMixer") -> None: ... def __setattr__(self, name: str, value: Signal | int | "ChannelMixer") -> None: ...
def __getattr__(self, name: str) -> Signal: ... def __getattr__(self, name: str) -> Signal: ...
class Bud: class Plugin:
signals: SignalList signals: SignalList
def __init__( def __init__(
...@@ -51,11 +51,11 @@ class Channel: ...@@ -51,11 +51,11 @@ class Channel:
def __init__(self, name: str): ... def __init__(self, name: str): ...
def clear(self) -> None: ... def clear(self) -> None: ...
def _new_patch(self, patch: Type[T], init_var: Optional[Any] = None) -> T: ... def _new_patch(self, patch: Type[T], init_var: Optional[Any] = None) -> T: ...
def _new_bud( def _new_plugin(
self, self,
thing: bl00mbox._plugins._Plugin | int, thing: bl00mbox._plugins._Plugin | int,
init_var: Optional[int | float] = None, init_var: Optional[int | float] = None,
) -> Bud: ... ) -> Plugin: ...
@overload @overload
def new(self, thing: Type[P], init_var: Optional[Any] = None) -> P: ... def new(self, thing: Type[P], init_var: Optional[Any] = None) -> P: ...
@overload @overload
...@@ -63,7 +63,7 @@ class Channel: ...@@ -63,7 +63,7 @@ class Channel:
self, self,
thing: bl00mbox._plugins._Plugin | int, thing: bl00mbox._plugins._Plugin | int,
init_var: Optional[int | float] = None, init_var: Optional[int | float] = None,
) -> Bud: ... ) -> Plugin: ...
class ChannelMixer: class ChannelMixer:
_channel: Channel _channel: Channel
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment