-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add synthio.BlockInput
support to synthio.Note
waveform loop parameters
#9788
Add synthio.BlockInput
support to synthio.Note
waveform loop parameters
#9788
Conversation
…tart`, `synthio.Note.waveform_loop_end`, `synthio.Note.ring_waveform_loop_start`, and `synthio.Note.ring_waveform_loop_end`.
In the example I shared originally, the duty cycle does not change linearly and produces an output that is not the best demonstration of controlling a square wave duty cycle through synthio. I've modified the example to demonstrate controlling duty cycle with LFO in a linear fashion. This uses a "window" technique by controlling both import audiobusio
import board
import synthio
import ulab.numpy as np
SIZE = 256
VOLUME = 32000
SAMPLE_RATE = 48000
RATE = 0.1
audio = audiobusio.I2SOut(bit_clock=board.GP0, word_select=board.GP1, data=board.GP2)
synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE)
audio.play(synth)
waveform = np.concatenate((
np.full(SIZE // 2, VOLUME, dtype=np.int16),
np.full(SIZE // 2, -VOLUME, dtype=np.int16)
))
note = synthio.Note(
frequency=110,
waveform=waveform,
waveform_loop_start=synthio.LFO(
scale=SIZE // 4,
offset=SIZE // 4,
rate=RATE,
),
waveform_loop_end=synthio.LFO(
scale=SIZE // 4,
offset=SIZE * 3 // 4,
rate=RATE,
),
)
synth.press(note) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks nice and simple, appreciate you picking up the work and unlocking some new capabilities!
It's especially nice that with properly configured blocks you can make sure the "window" remains always the same size for square wave modulation!
I think the docstrings need to be updated to reflect that out of range values for start/end are always clipped to 0/len-1, and none are ever rejected with ValueError anymore.
@kevinjwalters please test if you can
shared-bindings/synthio/Note.c
Outdated
//| waveform_loop_start: int | ||
|
||
|
||
//| waveform_loop_start: BlockInput | ||
//| """The sample index of where to begin looping waveform data. | ||
//| | ||
//| Values outside the range ``0`` to ``waveform_max_length-1`` (inclusive) are rejected with a `ValueError`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do these docstrings need to be updated? I haven't read below to see how you deal with out of range values from a varying BlockInput
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept the conditions mostly the same, but it's now handled within the calls to synthio_block_slot_get_limited
. I've updated the docstrings to remove references to ValueError
since that is no longer applicable. The major difference is that the code no longer checks the loop_start/loop_end values to see if they are outside the range and instead just clamps them to the valid range. I've removed portions of the docstrings which mentioned this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll keep this conversation open until you've reviewed the changes. Let me know if you have any other suggestions.
The test failure occurs because the repr of a note has changed slightly:
notice how e.g., the Do you know how or want to learn how to run the tests locally and update the expected output files? Otherwise, it looks like I could push that change to this branch, let me know if you'd like |
I haven't figured out how to build unix build-standard with synthio support just yet, but I'll dive into that soon. I'm assuming your solution is to update the tests to use floats instead rather than attempt to get integers working with And I'd rather fix the tests first before merging. |
yes, failed tests stop everything else from building, so it'll need to be fixed. In ports/unix You can The third target to know about is |
Thank you very much for the instruction, @jepler ! I'll tackle that this afternoon and get the PR ready for merging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great now!
The following
int
properties ofsynthio.Note
have been updated to supportsynthio.BlockInput
:synthio.Note.waveform_loop_start
synthio.Note.waveform_loop_end
synthio.Note.ring_waveform_loop_start
synthio.Note.ring_waveform_loop_end
The most common use-case for this feature is controlling PWM/duty-cycle on a square waveform with a
synthio.LFO
object (see example below), but it could be utilized for other wave-shaping scenarios.This PR addresses the following issue: #9780.
In this PR, I've also included two small bug fixes that I discovered along the way:
ring_waveform_loop_start
during note frequency calculation.synthio.Note.amplitude
changed from0.0
to1.0
in documentation to better reflect actual implementation.