@@ -209,6 +209,11 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
209209 uint32_t dds_rate ;
210210 const int16_t * waveform = synth -> waveform ;
211211 uint32_t waveform_length = synth -> waveform_length ;
212+
213+ uint32_t ring_dds_rate = 0 ;
214+ const int16_t * ring_waveform = NULL ;
215+ uint32_t ring_waveform_length = 0 ;
216+
212217 if (mp_obj_is_small_int (note_obj )) {
213218 uint8_t note = mp_obj_get_int (note_obj );
214219 uint8_t octave = note / 12 ;
@@ -227,35 +232,97 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t
227232 waveform_length = note -> waveform_buf .len / 2 ;
228233 }
229234 dds_rate = synthio_frequency_convert_scaled_to_dds ((uint64_t )frequency_scaled * waveform_length , sample_rate );
235+ if (note -> ring_frequency_scaled != 0 && note -> ring_waveform_buf .buf ) {
236+ ring_waveform = note -> ring_waveform_buf .buf ;
237+ ring_waveform_length = note -> ring_waveform_buf .len / 2 ;
238+ ring_dds_rate = synthio_frequency_convert_scaled_to_dds ((uint64_t )note -> ring_frequency_scaled * ring_waveform_length , sample_rate );
239+ uint32_t lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT ;
240+ if (ring_dds_rate > lim / 2 ) {
241+ ring_dds_rate = 0 ; // can't ring at that frequency
242+ }
243+ }
230244 }
231245
232- uint32_t accum = synth -> accum [chan ];
233- uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT ;
234- if (dds_rate > lim / 2 ) {
235- // beyond nyquist, can't play note
236- continue ;
237- }
246+ int synth_chan = synth -> channel_count ;
247+ if (ring_dds_rate ) {
248+ uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT ;
249+ uint32_t accum = synth -> accum [chan ];
238250
239- // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
240- if ( accum > lim ) {
241- accum %= lim ;
242- }
251+ if ( dds_rate > lim / 2 ) {
252+ // beyond nyquist, can't play note
253+ continue ;
254+ }
243255
244- int synth_chan = synth -> channel_count ;
245- for (uint16_t i = 0 , j = 0 ; i < dur ; i ++ ) {
246- accum += dds_rate ;
247- // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
256+ // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
257+ if (accum > lim ) {
258+ accum %= lim ;
259+ }
260+
261+ int32_t ring_buffer [dur ];
262+ // first, fill with waveform
263+ for (uint16_t i = 0 ; i < dur ; i ++ ) {
264+ accum += dds_rate ;
265+ // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
266+ if (accum > lim ) {
267+ accum -= lim ;
268+ }
269+ int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT ;
270+ ring_buffer [i ] = waveform [idx ];
271+ }
272+ synth -> accum [chan ] = accum ;
273+
274+ // now modulate by ring and accumulate
275+ accum = synth -> ring_accum [chan ];
276+ lim = ring_waveform_length << SYNTHIO_FREQUENCY_SHIFT ;
277+
278+ // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
248279 if (accum > lim ) {
249- accum -= lim ;
280+ accum %= lim ;
281+ }
282+
283+ for (uint16_t i = 0 , j = 0 ; i < dur ; i ++ ) {
284+ accum += ring_dds_rate ;
285+ // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
286+ if (accum > lim ) {
287+ accum -= lim ;
288+ }
289+ int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT ;
290+ int16_t wi = (ring_waveform [idx ] * ring_buffer [i ]) / 32768 ;
291+ for (int c = 0 ; c < synth_chan ; c ++ ) {
292+ out_buffer32 [j ] += (wi * loudness [c ]) / 32768 ;
293+ j ++ ;
294+ }
250295 }
251- int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT ;
252- int16_t wi = waveform [idx ];
253- for (int c = 0 ; c < synth_chan ; c ++ ) {
254- out_buffer32 [j ] += (wi * loudness [c ]) / 65536 ;
255- j ++ ;
296+ synth -> ring_accum [chan ] = accum ;
297+ } else {
298+ uint32_t lim = waveform_length << SYNTHIO_FREQUENCY_SHIFT ;
299+ uint32_t accum = synth -> accum [chan ];
300+
301+ if (dds_rate > lim / 2 ) {
302+ // beyond nyquist, can't play note
303+ continue ;
304+ }
305+
306+ // can happen if note waveform gets set mid-note, but the expensive modulo is usually avoided
307+ if (accum > lim ) {
308+ accum %= lim ;
309+ }
310+
311+ for (uint16_t i = 0 , j = 0 ; i < dur ; i ++ ) {
312+ accum += dds_rate ;
313+ // because dds_rate is low enough, the subtraction is guaranteed to go back into range, no expensive modulo needed
314+ if (accum > lim ) {
315+ accum -= lim ;
316+ }
317+ int16_t idx = accum >> SYNTHIO_FREQUENCY_SHIFT ;
318+ int16_t wi = waveform [idx ];
319+ for (int c = 0 ; c < synth_chan ; c ++ ) {
320+ out_buffer32 [j ] += (wi * loudness [c ]) / 65536 ;
321+ j ++ ;
322+ }
256323 }
324+ synth -> accum [chan ] = accum ;
257325 }
258- synth -> accum [chan ] = accum ;
259326 }
260327
261328 int16_t * out_buffer16 = (int16_t * )(void * )synth -> buffers [synth -> buffer_index ];
0 commit comments