Skip to content

Commit e0f745c

Browse files
authored
Merge pull request #9247 from jepler/improve-lfo-initial-value
synthio: Calculate LFO.value at construction
2 parents 6c4bfd6 + 9e878f7 commit e0f745c

File tree

3 files changed

+16
-6
lines changed

3 files changed

+16
-6
lines changed

shared-bindings/synthio/LFO.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@ STATIC const uint16_t triangle[] = {0, 32767, 0, -32767};
4040
//| should be considered an implementation detail, though it affects how LFOs
4141
//| behave for instance when used to implement an integrator (``l.offset = l``).
4242
//|
43-
//| An LFO's output, which is reflected in its `value` property, is not
44-
//| updated in any other way than when its associated synthesizer updates it.
45-
//| For instance, if an LFO is created with ``offset=1``, its `value` will still
46-
//| be ``0`` until it is updated by its associated synthesizer. Similarly, merely
47-
//| updating its properties does not update its value property.
43+
//| An LFO's ``value`` property is computed once when it is constructed, and then
44+
//| when its associated synthesizer updates it.
45+
//|
46+
//| This means that for instance an LFO **created** with ``offset=1`` has ```value==1``
47+
//| immediately, but **updating** the ``offset`` property alone does not
48+
//| change ``value``; it only updates through an association with an active synthesizer.
4849
//|
4950
//| The interpolation of the waveform is necessarily different depending on the
5051
//| ``once`` property. Consider a LFO with ``waveform=np.array([0, 100],
@@ -100,11 +101,17 @@ STATIC mp_obj_t synthio_lfo_make_new(const mp_obj_type_t *type_in, size_t n_args
100101
synthio_synth_parse_waveform(&self->waveform_bufinfo, args[ARG_waveform].u_obj);
101102
}
102103
self->waveform_obj = args[ARG_waveform].u_obj;
103-
self->base.last_tick = synthio_global_tick;
104104

105105
mp_obj_t result = MP_OBJ_FROM_PTR(self);
106106
properties_construct_helper(result, lfo_properties + 1, args + 1, MP_ARRAY_SIZE(lfo_properties) - 1);
107107

108+
// Force computation of the LFO's initial output
109+
synthio_global_rate_scale = 0;
110+
self->base.last_tick = synthio_global_tick - 1;
111+
synthio_block_slot_t slot;
112+
synthio_block_assign_slot(MP_OBJ_FROM_PTR(result), &slot, MP_QSTR_self);
113+
(void)synthio_block_slot_get(&slot);
114+
108115
return result;
109116
};
110117

tests/circuitpython/synthlfo.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@
1717
lfos[2].rate = lfos[1]
1818
lfos[2].offset = lfos[0]
1919

20+
print("Initial values", *(l.value for l in lfos))
21+
2022
for i in range(100):
2123
print(i * 256 / 48000, *list(lfo_tick(*lfos)) + [l.phase for l in lfos])

tests/circuitpython/synthlfo.py.exp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
Initial values 0.0 1.99993896484375 0.0 0.999969482421875 0.999969482421875
12
0.0 0.02133268229166667 1.973273111979167 0.06342789066420661 0.999969482421875 0.9466377766927083 0.02133333333333333 0.01333333333333333 0.01052412326388889 0.02666666666666667 0.02666666666666667
23
0.005333333333333333 0.04266536458333333 1.946607259114583 0.1262869271612167 0.999969482421875 0.8933060709635416 0.04266666666666667 0.02666666666666667 0.02090602864583333 0.05333333333333333 0.05333333333333333
34
0.01066666666666667 0.06399804687500001 1.91994140625 0.1885771094910304 0.999969482421875 0.8399743652343751 0.064 0.03999999999999999 0.03114571614583333 0.07999999999999998 0.07999999999999998

0 commit comments

Comments
 (0)