Skip to content

Commit a6ec310

Browse files
add synthio.Envelope plot option
1 parent 2a8c959 commit a6ec310

File tree

2 files changed

+81
-22
lines changed

2 files changed

+81
-22
lines changed

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Introduction
1919
:alt: Code Style: Black
2020

2121
A CircuitPython class to create a positionable ``displayio.TileGrid`` object
22-
from a ``synthio.ReadableBuffer`` wave table. The class inherits all
23-
properties of a ``TileGrid`` object including ``bitmap``, ``pixel_shader``, ``x``, ``y``
24-
and provides the bitmap properties of ``width``, ``height``.
22+
from a ``synthio.ReadableBuffer`` wave table or ``synthio.Envelope object.
23+
The class inherits the properties of a ``TileGrid`` object including ``bitmap``,
24+
``pixel_shader``, ``width``, ``height``, ``x``, ``y``.
2525

2626

2727
Dependencies

cedargrove_waveviz.py

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
`cedargrove_waveviz`
66
===============================================================================
77
A CircuitPython class to create a positionable ``displayio.TileGrid`` object
8-
from a ``synthio.ReadableBuffer`` wave table. The class inherits all
9-
properties of a ``TileGrid`` object including bitmap, pixel_shader, width,
10-
height, x, y.
8+
from a ``synthio.ReadableBuffer`` wave table or ``synthio.Envelope object.
9+
The class inherits the properties of a ``TileGrid`` object including bitmap,
10+
pixel_shader, width, height, x, y.
1111
1212
https://github.com/CedarGroveStudios/CircuitPython_WaveViz
1313
https://docs.circuitpython.org/en/latest/shared-bindings/displayio/#displayio.TileGrid
@@ -27,15 +27,16 @@
2727

2828

2929
# pylint: disable=too-few-public-methods
30+
# pylint: disable=too-many-instance-attributes
3031
class WaveViz(displayio.TileGrid):
3132
"""
3233
The WaveViz class creates a positionable ``displayio.TileGrid`` object
33-
from a ``synthio.ReadableBuffer`` wave table. The class inherits the
34-
properties of a ``TileGrid`` object of bitmap, pixel_shader, width,
35-
height, x, y.
34+
from a ``synthio.ReadableBuffer`` wave table or ``synthio.Envelope object.
35+
The class inherits the properties of a ``TileGrid`` object of bitmap,
36+
pixel_shader, width, height, x, y.
3637
37-
:param synthio.ReadableBuffer wave_table: The synthio waveform object of type 'h'
38-
(signed 16-bit). No default.
38+
:param synthio.ReadableBuffer wave_table: The synthio waveform or envelope
39+
object of type 'h' (signed 16-bit). No default.
3940
:param int x: The tile grid's x-axis coordinate value. No default.
4041
:param int y: The tile grid's y-axis coordinate value. No default.
4142
:param int width: The tile grid's width in pixels. No default.
@@ -45,6 +46,8 @@ class WaveViz(displayio.TileGrid):
4546
:param integer back_color: The grid background color. Defaults to None (transparent).
4647
:param bool auto_scale: Automatically adjust resultant plot to the wave table's
4748
full-scale value. Defaults to True (auto scale enabled).
49+
:param bool envelope_plot: Plot an envelope object. Defaults to False (plot
50+
a wave object).
4851
"""
4952

5053
# pylint: disable=too-many-arguments
@@ -59,6 +62,7 @@ def __init__(
5962
grid_color=0x808080,
6063
back_color=None,
6164
auto_scale=True,
65+
envelope_plot=False,
6266
):
6367
"""Instantiate the tile generator class."""
6468
self._wave_table = wave_table
@@ -70,6 +74,7 @@ def __init__(
7074
self._auto_scale = auto_scale
7175
self._max_sample_value = 32767 # Maximum signed 16-bit value
7276
self._scale_y = 0 # Define for later use
77+
self._envelope_plot = envelope_plot
7378

7479
self._palette = displayio.Palette(3)
7580
self._palette[1] = plot_color
@@ -126,13 +131,66 @@ def max_result(self):
126131
return self._max_sample_value
127132

128133
def _update_plot(self):
129-
"""Clears the bitmap and plots the grid and waveform."""
134+
"""Clears the bitmap and plots the grid and waveform or envelope."""
130135
# Clear the target bitmap
131136
self._bmp.fill(0)
132137

133138
# Plot grid and wave table
134139
self._plot_grid() # Plot the grid
135-
self._plot_wave() # Plot the wave table
140+
if self._envelope_plot:
141+
self._plot_envelope()
142+
else:
143+
self._plot_wave() # Plot the wave table
144+
145+
def _plot_envelope(self):
146+
"""Plot the wave_table as a bitmap representing an ADSR envelope
147+
object. Y-axis is set at 0.0 to 1.0 and will not automatically
148+
scale. Sustain duration is plotted as an arbitrary value based
149+
on the attack and release time values."""
150+
# Get the five envelope values from the wave table
151+
a_time = self._wave_table[0] # Attack time
152+
a_level = self._wave_table[1] # Attack level
153+
d_time = self._wave_table[2] # Decay time
154+
s_level = self._wave_table[3] # Sustain level
155+
r_time = self._wave_table[4] # Release time
156+
157+
x_points = array("h", [])
158+
y_points = array("h", [])
159+
160+
# Plot envelope polygon
161+
if s_level != 0:
162+
# Full ADSR envelope
163+
s_time = 0.3 * (a_time + r_time) # relative/arbitrary, not actual
164+
time_points = [
165+
0,
166+
a_time,
167+
a_time + d_time,
168+
a_time + d_time + s_time,
169+
a_time + d_time + s_time + r_time,
170+
]
171+
level_points = [0, a_level, s_level, s_level, 0]
172+
env_duration = a_time + d_time + s_time + r_time + 0.0001
173+
else:
174+
# AR phases only (plucked or struck instrument)
175+
time_points = [0, a_time, a_time + r_time]
176+
level_points = [0, a_level, 0]
177+
env_duration = a_time + r_time + 0.0001
178+
179+
# Scale the lists to fit the plot window size and location in pixels
180+
for time in time_points:
181+
x_points.append(int((self._width / env_duration) * time))
182+
183+
for level in level_points:
184+
y_points.append(-int(self._height * level) + self._height)
185+
186+
# Draw the envelope polygon
187+
bitmaptools.draw_polygon(
188+
self._bmp,
189+
x_points,
190+
y_points,
191+
1,
192+
False,
193+
)
136194

137195
def _plot_wave(self):
138196
"""Plot the wave_table as a bitmap. Extract samples from the wave
@@ -182,12 +240,13 @@ def _plot_grid(self):
182240
2,
183241
)
184242

185-
# Draw x-axis line
186-
bitmaptools.draw_line(
187-
self._bmp,
188-
0,
189-
self._y_offset,
190-
self._width,
191-
self._y_offset,
192-
2,
193-
)
243+
if not self._envelope_plot:
244+
# Draw x-axis line for wave plot
245+
bitmaptools.draw_line(
246+
self._bmp,
247+
0,
248+
self._y_offset,
249+
self._width,
250+
self._y_offset,
251+
2,
252+
)

0 commit comments

Comments
 (0)