Skip to content

Commit 3f7e7bd

Browse files
authored
Add smooth & stepped random wave shapes to Lutra (#383)
1 parent c2f61b4 commit 3f7e7bd

File tree

4 files changed

+28
-1
lines changed

4 files changed

+28
-1
lines changed
Loading
6.41 KB
Loading

software/contrib/lutra.md

+8
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@ the module and will be re-loaded every time `Lutra` starts. Available wave shape
1414
- ![Triangle Wave](./lutra-docs/wave_triangle.png) Triangle
1515
- ![Saw Wave](./lutra-docs/wave_saw.png) Saw
1616
- ![Ramp Wave](./lutra-docs/wave_ramp.png) Ramp
17+
- ![Stepped Random Wave](./lutra-docs/wave_step_random.png) Stepped Random
18+
- ![Smooth Random Wave](./lutra-docs/wave_smooth_random.png) Smooth Random (Linear)
1719

1820
When pressing `b2` to select the wave shape, the selected shape will briefly appear in the upper left corner of the
1921
screen.
2022

23+
The stepped random wave will hold a randomly-chosen voltage for the duration of the cycle period, choosing a new
24+
voltage every period.
25+
26+
The smooth random wave moves linearly from the current voltage toward a randomly-chosen goal over the cycle period,
27+
choosing a new random goal voltage every period.
28+
2129
## CV Input Configuration
2230

2331
By default CV signals applied to `ain` will adjust the spread of the output waves. If preferred, this can be changed

software/contrib/lutra.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import configuration
2121
import math
22+
from random import random
2223
import time
2324

2425
import _thread
@@ -39,14 +40,18 @@ class WaveGenerator:
3940
WAVE_SHAPE_TRIANGLE = 2
4041
WAVE_SHAPE_SAW = 3
4142
WAVE_SHAPE_RAMP = 4
42-
NUM_WAVE_SHAPES = 5
43+
WAVE_SHAPE_STEP_RANDOM = 5
44+
WAVE_SHAPE_SMOOTH_RANDOM = 6
45+
NUM_WAVE_SHAPES = 7
4346

4447
WAVE_SHAPES_NAMES = [
4548
"Sine",
4649
"Square",
4750
"Triangle",
4851
"Saw",
4952
"Ramp",
53+
"Step_Random",
54+
"Smooth_Random",
5055
]
5156

5257
WAVE_SHAPES_NAMES_TO_SHAPES = {
@@ -55,6 +60,8 @@ class WaveGenerator:
5560
"triangle": WAVE_SHAPE_TRIANGLE,
5661
"saw": WAVE_SHAPE_SAW,
5762
"ramp": WAVE_SHAPE_RAMP,
63+
"step_random": WAVE_SHAPE_STEP_RANDOM,
64+
"smooth_random": WAVE_SHAPE_SMOOTH_RANDOM,
5865
}
5966

6067
## 12x12 pixel images of the wave shapes
@@ -64,6 +71,8 @@ class WaveGenerator:
6471
FrameBuffer(bytearray(b'\x06\x00\x06\x00\t\x00\t\x00\x10\x80\x10\x80 @ @@ @ \x80\x10\x80\x10'), 12, 12, MONO_HLSB), # TRIANGLE
6572
FrameBuffer(bytearray(b'\x80\x00\xc0\x00\xa0\x00\x90\x00\x88\x00\x84\x00\x82\x00\x81\x00\x80\x80\x80@\x80 \x80\x10'), 12, 12, MONO_HLSB), # SAW
6673
FrameBuffer(bytearray(b'\x00\x10\x000\x00P\x00\x90\x01\x10\x02\x10\x04\x10\x08\x10\x10\x10 \x10@\x10\x80\x10'), 12, 12, MONO_HLSB), # RAMP
74+
FrameBuffer(bytearray(b'\x00\xe0\x00\xa0\x00\xa0\x00\xa0<\xa0$\xa0$\xa0\xe4\xb0\x04\x80\x04\x80\x04\x80\x07\x80'), 12, 12, MONO_HLSB), # STEP_RANDOM
75+
FrameBuffer(bytearray(b'\x00`\x00P\x00P\x08P\x14P$PD\x90\x82\x80\x02\x80\x02\x80\x02\x80\x01\x80'), 12, 12, MONO_HLSB), # SMOOTH_RANDOM
6776
]
6877

6978
IMAGE_SIZE = (12, 12)
@@ -79,6 +88,9 @@ def __init__(self, cv_output):
7988
self.cycle_ticks = 1000
8089
self.current_tick = 0
8190

91+
self.prev_random_goal = random() * MAX_OUTPUT_VOLTAGE
92+
self.random_goal = random() * MAX_OUTPUT_VOLTAGE
93+
8294
def reset(self):
8395
"""Reset the wave to the beginning
8496
"""
@@ -118,12 +130,19 @@ def tick(self):
118130
volts = MAX_OUTPUT_VOLTAGE - self.current_tick / self.cycle_ticks * MAX_OUTPUT_VOLTAGE
119131
elif self.shape == self.WAVE_SHAPE_RAMP:
120132
volts = self.current_tick / self.cycle_ticks * MAX_OUTPUT_VOLTAGE
133+
elif self.shape == self.WAVE_SHAPE_STEP_RANDOM:
134+
volts = self.random_goal
135+
elif self.shape == self.WAVE_SHAPE_SMOOTH_RANDOM:
136+
slope = (self.random_goal - self.prev_random_goal) / self.cycle_ticks
137+
volts = slope * self.current_tick + self.prev_random_goal
121138
else:
122139
volts = 0
123140

124141
self.current_tick = self.current_tick + 1
125142
if self.current_tick >= self.cycle_ticks:
126143
self.current_tick = 0
144+
self.prev_random_goal = self.random_goal
145+
self.random_goal = random() * MAX_OUTPUT_VOLTAGE
127146

128147
self.cv_output.voltage(volts)
129148
return volts

0 commit comments

Comments
 (0)