Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kevinjwalters/ff004b1b1acab9f70b9d237765acb3b3 to your computer and use it in GitHub Desktop.
Save kevinjwalters/ff004b1b1acab9f70b9d237765acb3b3 to your computer and use it in GitHub Desktop.
SimpleLFO v0.1
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