diff --git a/docs/badge/bl00mbox.rst b/docs/badge/bl00mbox.rst index 20a820d5d6f53393f7ded102f03ad70cd29e2bb6..10366dad5ba8ce508d22c710e6b16da8ada69368 100644 --- a/docs/badge/bl00mbox.rst +++ b/docs/badge/bl00mbox.rst @@ -278,6 +278,28 @@ Some other misc channel operations for live coding mostly: plugins: 0 [channel mixer] (0 connections) +Radspa signal types +------------------------ + +Radspa is a C plugin format that all bl00mbox plugins are written in. Its main feature is that all signals +are expressed in the same manner so that every input->output connection is valid. This means that for real +world value interpretation some decoding is sometimes necessary. While the REPL informs you of these +quanta and helper functions such as .start() or .dB() help with first contact, for interfacing with these +signals with another signal some understanding is helpful. The data is represented as an int16_t stream. + +[pitch] provides a logarithmic frequency input. A value of 18367 represents A440, going up by 1 represents +0.5 cent or 1/2400 octaves or a factor of 2^(1/2400). Special methods: .tone can be set to (float) semitones +distance from A440 or a note name such as "F#4", .freq can be set to a value in Hz + +[gain] provides a linear volume input. A value of 4096 represents unity gain. Special methods: .mult is linear +and represents unity gain as 1, .dB is 20*log_10(x) and represents unity gain as 0. + +[trigger] provides an input for note start/stop events. A start event with a given velocity (midi term, think +loudness, 1..32767) from a stopped state is encoded by a permanent signal change to the velocity value. A +restart from this "running" state is encoded as permanently flipping the signal sign, i.e to [-1..-32676] and +back to [1..32767] on the next restart. A change from nonzero to zero encodes a signal stop. Note: This API is +still subject to change. + Example 1: Auto bassline ------------------------ diff --git a/python_payload/bl00mbox/_user.py b/python_payload/bl00mbox/_user.py index a882af9acb989425a6cf33d8d516501421645834..b9c9bf9aaa441b6addae046ea222d1f59b348f19 100644 --- a/python_payload/bl00mbox/_user.py +++ b/python_payload/bl00mbox/_user.py @@ -87,6 +87,12 @@ class Signal: self._hints = "" def __repr__(self): + ret = self._no_desc() + if len(self._description): + ret += "\n " + "\n ".join(self._description.split("\n")) + return ret + + def _no_desc(self): self._plugin._check_existence() ret = self.name @@ -126,6 +132,9 @@ class Signal: if isinstance(self, SignalPitchMixin): ret += " / " + str(self.tone) + " semitones / " + str(self.freq) + "Hz" + if isinstance(self, SignalVolumeMixin): + ret += " / " + str(self.dB) + "dB / x" + str(self.mult) + return ret @property @@ -271,6 +280,24 @@ class SignalPitchMixin: self.value = (32767 - 2400 * 6) + 200 * tone +class SignalVolumeMixin: + @property + def dB(self): + return 20 * math.log((self.value / 4096), 10) + + @dB.setter + def dB(self, val): + self.value = int(4096 * (10 ** (val / 20))) + + @property + def mult(self): + return self.value / 4096 + + @mult.setter + def mult(self, val): + self.value = int(4096 * val) + + class SignalInputTrigger(SignalInput, SignalTriggerMixin): pass @@ -279,6 +306,10 @@ class SignalInputPitch(SignalInput, SignalPitchMixin): pass +class SignalInputVolume(SignalInput, SignalVolumeMixin): + pass + + class SignalList: def __init__(self, plugin): self._list = [] @@ -298,6 +329,9 @@ class SignalList: elif hints & 32: signal = SignalInputPitch(plugin, signal_num) signal._hints = "input/pitch" + elif hints & 8: + signal = SignalInputVolume(plugin, signal_num) + signal._hints = "input/volume" else: signal = SignalInput(plugin, signal_num) signal._hints = "input" @@ -335,7 +369,7 @@ class Plugin: self._check_existence() ret = "[plugin " + str(self.bud_num) + "] " + self.name for sig in self.signals._list: - ret += "\n " + "\n ".join(repr(sig).split("\n")) + ret += "\n " + "\n ".join(sig._no_desc().split("\n")) return ret def __del__(self): @@ -502,6 +536,10 @@ class Channel: else: print("no active channels") + def print_plugins(self): + for plugin in self.plugins: + print(repr(plugin)) + def new(self, thing, init_var=None): self.free = False if type(thing) == type: