Skip to content

Commit 9a9f322

Browse files
committed
synthio: Perform vibrato in pitch, not as frequency ratio
Now the vibrato 'units' are 1.0 = one octave, 1/12 = one semitone, 1/1200 = one cent. Before, the units were somewhat arbitrary and were not perceptually "symmetrical" around the base frequency. For vibrato_depth = 1/12 and base frequency of 440, before: pitch from 403.33 to 476.67Hz, not corresponding to any notes after: pitch from 415.30 to 466.16Hz, corresponding to G# and A#
1 parent a53c0ed commit 9a9f322

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

shared-bindings/synthio/Note.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,12 @@ MP_PROPERTY_GETSET(synthio_note_amplitude_obj,
118118

119119

120120
//| tremolo_depth: float
121-
//| """The tremolo depth of the note, from 0 to 1"""
121+
//| """The tremolo depth of the note, from 0 to 1
122+
//|
123+
//| A depth of 0 disables tremolo. A nonzero value enables tremolo,
124+
//| with the maximum decrease in amplitude being equal to the tremolo
125+
//| depth. A note with a tremolo depth of 1 will fade out to nothing, while
126+
//| a tremolo depth of 0.1 will give a minimum amplitude of 0.9."""
122127
STATIC mp_obj_t synthio_note_get_tremolo_depth(mp_obj_t self_in) {
123128
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
124129
return mp_obj_new_float(common_hal_synthio_note_get_tremolo_depth(self));
@@ -154,7 +159,12 @@ MP_PROPERTY_GETSET(synthio_note_tremolo_rate_obj,
154159
(mp_obj_t)&synthio_note_set_tremolo_rate_obj);
155160

156161
//| vibrato_depth: float
157-
//| """The vibrato depth of the note, from 0 to 1"""
162+
//| """The vibrato depth of the note, from 0 to 1
163+
//|
164+
//| A depth of 0 disables vibrato. A depth of 1 corresponds to a vibrato of ±1
165+
//| octave. A depth of (1/12) = 0.833 corresponds to a vibrato of ±1 semitone,
166+
//| and a depth of .00833 corresponds to one musical cent.
167+
//| """
158168
STATIC mp_obj_t synthio_note_get_vibrato_depth(mp_obj_t self_in) {
159169
synthio_note_obj_t *self = MP_OBJ_TO_PTR(self_in);
160170
return mp_obj_new_float(common_hal_synthio_note_get_vibrato_depth(self));

shared-module/synthio/Note.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,35 @@ uint32_t synthio_note_envelope(synthio_note_obj_t *self) {
151151
return self->amplitude_scaled;
152152
}
153153

154+
// Perform a pitch bend operation
155+
//
156+
// bend_value is in the range [0, 65535]. "no change" is 32768. The bend unit is 32768/octave.
157+
//
158+
// compare to (frequency_scaled * pow(2, (bend_value-32768)/32768))
159+
// a 13-entry pitch table
160+
#define BEND_SCALE (32768)
161+
#define BEND_OFFSET (BEND_SCALE)
162+
163+
STATIC uint16_t pitch_bend_table[] = { 0, 1948, 4013, 6200, 8517, 10972, 13573, 16329, 19248, 22341, 25618, 29090, 32768 };
164+
165+
STATIC uint32_t pitch_bend(uint32_t frequency_scaled, uint16_t bend_value) {
166+
bool down = (bend_value < 32768);
167+
if (!down) {
168+
bend_value -= 32768;
169+
}
170+
uint32_t bend_value_semitone = (uint32_t)bend_value * 24; // 65536/semitone
171+
uint32_t semitone = bend_value_semitone >> 16;
172+
uint32_t fractone = bend_value_semitone & 0xffff;
173+
uint32_t f_lo = pitch_bend_table[semitone];
174+
uint32_t f_hi = pitch_bend_table[semitone + 1]; // table has 13 entries, indexing with semitone=12 is OK
175+
uint32_t f = ((f_lo * (65535 - fractone) + f_hi * fractone) >> 16) + BEND_OFFSET;
176+
return (frequency_scaled * (uint64_t)f) >> (15 + down);
177+
}
178+
154179
uint32_t synthio_note_step(synthio_note_obj_t *self, int32_t sample_rate, int16_t dur, uint16_t *loudness) {
155180
int tremolo_value = synthio_lfo_step(&self->tremolo_state, dur);
156181
int vibrato_value = synthio_lfo_step(&self->vibrato_state, dur);
157182
*loudness = (*loudness * tremolo_value) >> 15;
158-
uint32_t frequency_scaled = ((uint64_t)self->frequency_scaled * vibrato_value) >> 15;
183+
uint32_t frequency_scaled = pitch_bend(self->frequency_scaled, vibrato_value);
159184
return frequency_scaled;
160185
}

0 commit comments

Comments
 (0)