Created
April 2, 2024 20:05
-
-
Save kevinjwalters/ff004b1b1acab9f70b9d237765acb3b3 to your computer and use it in GitHub Desktop.
SimpleLFO v0.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SimpleLFO: | |
LIBRARY = {"triangle": {"waveform": (0, 32767, 0, -32767), | |
"interpolate": True, "nowrap": False, "once": False}, | |
"square": {"waveform": (32767, -32767), | |
"interpolate": False, "nowrap": False, "once": False}, | |
"sine": {"waveform": tuple([round(32767.0 * math.sin(2 * math.pi * idx / 100)) for idx in range(100)]), | |
"interpolate": True, "nowrap": False, "once": False}, | |
"sawtooth": {"waveform": tuple([round(32767 - 2 * 32767 * idx / (20 - 1)) for idx in range(20)]), | |
"interpolate": True, "nowrap": False, "once": False}, | |
### Oneshots | |
"uniramp": {"waveform": (32767, 0), | |
"interpolate": True, "nowrap": True, "once": True}, | |
"reverseramp": {"waveform": (-32767, 32767), | |
"interpolate": True, "nowrap": True, "once": True} | |
} | |
def __init__(self, | |
waveform="triangle", | |
rate=1.0, | |
scale=1, | |
offset=0, | |
once=None, | |
interpolate=True, | |
nowrap=None): | |
self.rate = rate | |
self.scale = scale | |
self.offset = offset | |
if isinstance(waveform, str): | |
self._waveform = self.LIBRARY[waveform]["waveform"] | |
self._interpolate = self.LIBRARY[waveform]["interpolate"] | |
self._nowrap = self.LIBRARY[waveform]["nowrap"] if nowrap is None else nowrap | |
self._once = self.LIBRARY[waveform]["once"] if once is None else once | |
else: | |
self._waveform = waveform | |
self._interpolate = interpolate | |
self._nowrap = True if (once and nowrap is None) else bool(nowrap) | |
self._once = bool(once) | |
self._mean = sum(self._waveform) / len(self._waveform) | |
self._waveform_len = len(self._waveform) | |
self._period_ns = 1e9 / rate | |
### TODO work out the real condition for this!! | |
self._idx_ghz = rate * (self._waveform_len - 1 if self._nowrap else self._waveform_len) * 1e-9 | |
self._rescale = scale / 32768.0 | |
self._starttime_ns = time.monotonic_ns() | |
self._endfirst_ns = self._starttime_ns + self._period_ns | |
self._update_tick = 1 | |
def retrigger(self): | |
self._starttime_ns = time.monotonic_ns() | |
@property | |
def value(self): | |
now_ns = time.monotonic_ns() | |
frac_idx, int_idx = math.modf((now_ns - self._starttime_ns) * self._idx_ghz) | |
idx = int(int_idx) % self._waveform_len ### int() required here for index use | |
interpolate = self._interpolate | |
w_value = None | |
if self._once: | |
if self._nowrap: | |
last_cycle_idx = self._waveform_len - 1 | |
new_idx = last_cycle_idx | |
else: | |
last_cycle_idx = self._waveform_len | |
new_idx = 0 | |
### Check to see if once waveform has finished | |
if int_idx >= last_cycle_idx: | |
if self._nowrap: | |
idx = new_idx | |
interpolate = False | |
else: | |
w_value = self._mean | |
if w_value is None: | |
if interpolate: | |
next_idx = idx + 1 | |
if next_idx >= self._waveform_len: | |
next_idx = 0 | |
w_value = (1.0 - frac_idx) * self._waveform[idx] + frac_idx * self._waveform[next_idx] | |
else: | |
w_value = self._waveform[idx] | |
return w_value * self._rescale + self.offset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment