From cc53ef3d89367f065714647cc03dc643ebb9f8a3 Mon Sep 17 00:00:00 2001 From: Brad Barnett <127794626+bdbarnett@users.noreply.github.com> Date: Tue, 27 Oct 2026 22:03:08 -0500 Subject: [PATCH 1/2] examples: add simpletests for audioinstruments and audioeffects --- docs/get-started/first-program.md | 7 +++ examples/audioeffects_simpletest.py | 73 +++++++++++++++++++++++++ examples/audioinstruments_simpletest.py | 67 +++++++++++++++++++++++ lib/audioeffects/README.md | 2 + lib/audioinstruments/README.md | 2 + 5 files changed, 151 insertions(+) create mode 100644 examples/audioeffects_simpletest.py create mode 100644 examples/audioinstruments_simpletest.py diff --git a/docs/get-started/first-program.md b/docs/get-started/first-program.md index 03ff6204..af0e76fd 100644 --- a/docs/get-started/first-program.md +++ b/docs/get-started/first-program.md @@ -58,3 +58,10 @@ frames of 16-bit stereo, so 100 of them make 25,600 frames. Put more effects in the chain with [Chain effects](../guides/chain-effects.md), or play a part in time with [Sequence a part](../guides/sequence-a-part.md). + +To hear something right away, run one of the two complete examples. Each +writes a WAV file you can open in any audio player: +[audioinstruments_simpletest.py](https://github.com/PyDevices/audiocomponents/blob/main/examples/audioinstruments_simpletest.py) +plays a tune on a Juno-106, and +[audioeffects_simpletest.py](https://github.com/PyDevices/audiocomponents/blob/main/examples/audioeffects_simpletest.py) +runs plucked notes through a tape echo and a hall. diff --git a/examples/audioeffects_simpletest.py b/examples/audioeffects_simpletest.py new file mode 100644 index 00000000..2f869b6d --- /dev/null +++ b/examples/audioeffects_simpletest.py @@ -0,0 +1,73 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT +"""Run plucked notes through a tape echo and a hall, and save a WAV file. + +A synthio Synthesizer plays short notes, a TapeDelay repeats them and a +Reverb puts them in a hall. Each effect takes the one before it as its +input, and the program writes the end of the chain to a WAV file you can +open in any audio player. Change the names to hear any of the forty-five. + +Needs: audioeffects and audiodsp. Both are built into the PyDevices +MicroPython firmware; on CPython, pip install pydevices-audioeffects. + +Run it: + micropython audioeffects_simpletest.py + +Tested on: the unix port of MicroPython and CPython 3.12 on Linux. +""" + +import struct + +import audiocore +import audioeffects +import synthio + +# Change these to match your setup. +FILENAME = "echoes.wav" +NOTES = (60, 67, 64, 72) # MIDI note numbers +NOTE_SECONDS = 0.6 +SAMPLE_RATE = 22050 +ECHO_MS = 300 # time between the repeats + +# A synthesizer whose notes die away quickly, so the echoes stand out. +envelope = synthio.Envelope(attack_time=0.005, decay_time=0.2, sustain_level=0) +synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE, envelope=envelope) + +# A tape echo fed by the synthesizer, then a hall fed by the echo. +echo = audioeffects.create("TapeDelay", synth, SAMPLE_RATE, + time_ms=ECHO_MS, feedback=0.4, mix=0.35) +hall = audioeffects.create("Reverb", echo.output, SAMPLE_RATE, + character="hall", mix=0.3) + +# Write the WAV header now; the data size is filled in at the end. +out = open(FILENAME, "wb") +out.write(b"RIFF\0\0\0\0WAVEfmt ") +out.write(struct.pack(" Date: Tue, 27 Oct 2026 22:22:04 -0500 Subject: [PATCH 2/2] audioinstruments simpletest: play the tune on the Rhodes --- docs/get-started/first-program.md | 2 +- examples/audioinstruments_simpletest.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/get-started/first-program.md b/docs/get-started/first-program.md index af0e76fd..0f8b8cfb 100644 --- a/docs/get-started/first-program.md +++ b/docs/get-started/first-program.md @@ -62,6 +62,6 @@ or play a part in time with To hear something right away, run one of the two complete examples. Each writes a WAV file you can open in any audio player: [audioinstruments_simpletest.py](https://github.com/PyDevices/audiocomponents/blob/main/examples/audioinstruments_simpletest.py) -plays a tune on a Juno-106, and +plays a tune on a Rhodes electric piano, and [audioeffects_simpletest.py](https://github.com/PyDevices/audiocomponents/blob/main/examples/audioeffects_simpletest.py) runs plucked notes through a tape echo and a hall. diff --git a/examples/audioinstruments_simpletest.py b/examples/audioinstruments_simpletest.py index ab57b8e7..46154624 100644 --- a/examples/audioinstruments_simpletest.py +++ b/examples/audioinstruments_simpletest.py @@ -1,11 +1,12 @@ # SPDX-FileCopyrightText: 2026 Brad Barnett # # SPDX-License-Identifier: MIT -"""Play a short tune on a classic synthesizer and save it as a WAV file. +"""Play a short tune on a classic electric piano and save it as a WAV file. -The program builds one instrument by name, turns its filter cutoff knob, -plays four notes and writes what comes out to a WAV file you can open in -any audio player. Change INSTRUMENT to hear another of the fifty-five. +The program builds one instrument by name, plays four notes and writes +what comes out to a WAV file you can open in any audio player. Then it +lists the instrument's knobs, which inst.set_macro() turns. Change +INSTRUMENT to hear another of the fifty-five. Needs: audioinstruments and audiodsp. Both are built into the PyDevices MicroPython firmware; on CPython, pip install pydevices-audioinstruments. @@ -23,16 +24,13 @@ # Change these to match your setup. FILENAME = "tune.wav" -INSTRUMENT = "juno106" # try "minimoog", "dx7", "rhodes" or "tr808" +INSTRUMENT = "rhodes" # try "juno106", "minimoog", "dx7" or "tr808" NOTES = (60, 64, 67, 72) # MIDI note numbers: C, E, G and the C above NOTE_SECONDS = 0.4 SAMPLE_RATE = 22050 -CUTOFF = 70 # 0-127; lower it for a darker sound -# Build the instrument, mono, and set its filter cutoff by the knob's name. +# Build the instrument, in mono, on its default patch. inst = audioinstruments.create(INSTRUMENT, SAMPLE_RATE, channel_count=1) -if "Cutoff" in inst.macro_labels: - inst.set_macro(inst.macro_labels.index("Cutoff"), CUTOFF) # Write the WAV header now; the data size is filled in at the end. out = open(FILENAME, "wb") @@ -65,3 +63,7 @@ def record(seconds): out.write(struct.pack("