@@ -14,6 +14,12 @@ use super::{
1414 ChannelConfigOptions , TABLE_LENGTH_USIZE ,
1515} ;
1616
17+ fn get_fase_incr ( freq : f32 , detune : f32 , sample_rate : f64 ) -> f64 {
18+ let computed_freq = freq as f64 * ( detune as f64 / 1200. ) . exp2 ( ) ;
19+ let clamped = computed_freq. clamp ( -sample_rate / 2. , sample_rate / 2. ) ;
20+ clamped / sample_rate
21+ }
22+
1723/// Options for constructing an [`OscillatorNode`]
1824// dictionary OscillatorOptions : AudioNodeOptions {
1925// OscillatorType type = "sine";
@@ -404,55 +410,21 @@ impl AudioProcessor for OscillatorRenderer {
404410 self . start_time = current_time;
405411 }
406412
407- let nyquist = scope. sample_rate / 2. ;
408-
409- channel_data
410- . iter_mut ( )
411- . zip ( frequency_values. iter ( ) . cycle ( ) )
412- . zip ( detune_values. iter ( ) . cycle ( ) )
413- . for_each ( |( ( o, & frequency) , & detune) | {
414- if current_time < self . start_time || current_time >= self . stop_time {
415- * o = 0. ;
416- current_time += dt;
417-
418- return ;
419- }
420-
421- // @todo: we could avoid recompute that if both param lengths are 1
422- let computed_frequency = frequency * ( detune / 1200. ) . exp2 ( ) ;
423- let computed_frequency = computed_frequency. clamp ( -nyquist, nyquist) ;
424-
425- // first sample to render
426- if !self . started {
427- // if start time was between last frame and current frame
428- // we need to adjust the phase first
429- if current_time > self . start_time {
430- let phase_incr = computed_frequency as f64 / sample_rate;
431- let ratio = ( current_time - self . start_time ) / dt;
432- self . phase = Self :: unroll_phase ( phase_incr * ratio) ;
433- }
434-
435- self . started = true ;
436- }
437-
438- let phase_incr = computed_frequency as f64 / sample_rate;
439-
440- // @note: per spec all default oscillators should be rendered from a
441- // wavetable, define if it worth the assle...
442- // e.g. for now `generate_sine` and `generate_custom` are almost the sames
443- // cf. https://webaudio.github.io/web-audio-api/#oscillator-coefficients
444- * o = match self . type_ {
445- OscillatorType :: Sine => self . generate_sine ( ) ,
446- OscillatorType :: Sawtooth => self . generate_sawtooth ( phase_incr) ,
447- OscillatorType :: Square => self . generate_square ( phase_incr) ,
448- OscillatorType :: Triangle => self . generate_triangle ( ) ,
449- OscillatorType :: Custom => self . generate_custom ( ) ,
450- } ;
451-
452- current_time += dt;
453-
454- self . phase = Self :: unroll_phase ( self . phase + phase_incr) ;
455- } ) ;
413+ if frequency_values. len ( ) == 1 && detune_values. len ( ) == 1 {
414+ let phase_incr = get_fase_incr ( frequency_values[ 0 ] , detune_values[ 0 ] , sample_rate) ;
415+ channel_data
416+ . iter_mut ( )
417+ . for_each ( |output| self . generate_sample ( output, phase_incr, & mut current_time, dt) ) ;
418+ } else {
419+ channel_data
420+ . iter_mut ( )
421+ . zip ( frequency_values. iter ( ) . cycle ( ) )
422+ . zip ( detune_values. iter ( ) . cycle ( ) )
423+ . for_each ( |( ( output, & f) , & d) | {
424+ let phase_incr = get_fase_incr ( f, d, sample_rate) ;
425+ self . generate_sample ( output, phase_incr, & mut current_time, dt)
426+ } ) ;
427+ }
456428
457429 true
458430 }
@@ -488,6 +460,50 @@ impl AudioProcessor for OscillatorRenderer {
488460}
489461
490462impl OscillatorRenderer {
463+ #[ inline]
464+ fn generate_sample (
465+ & mut self ,
466+ output : & mut f32 ,
467+ phase_incr : f64 ,
468+ current_time : & mut f64 ,
469+ dt : f64 ,
470+ ) {
471+ if * current_time < self . start_time || * current_time >= self . stop_time {
472+ * output = 0. ;
473+ * current_time += dt;
474+
475+ return ;
476+ }
477+
478+ // first sample to render
479+ if !self . started {
480+ // if start time was between last frame and current frame
481+ // we need to adjust the phase first
482+ if * current_time > self . start_time {
483+ let ratio = ( * current_time - self . start_time ) / dt;
484+ self . phase = Self :: unroll_phase ( phase_incr * ratio) ;
485+ }
486+
487+ self . started = true ;
488+ }
489+
490+ // @note: per spec all default oscillators should be rendered from a
491+ // wavetable, define if it worth the assle...
492+ // e.g. for now `generate_sine` and `generate_custom` are almost the sames
493+ // cf. https://webaudio.github.io/web-audio-api/#oscillator-coefficients
494+ * output = match self . type_ {
495+ OscillatorType :: Sine => self . generate_sine ( ) ,
496+ OscillatorType :: Sawtooth => self . generate_sawtooth ( phase_incr) ,
497+ OscillatorType :: Square => self . generate_square ( phase_incr) ,
498+ OscillatorType :: Triangle => self . generate_triangle ( ) ,
499+ OscillatorType :: Custom => self . generate_custom ( ) ,
500+ } ;
501+
502+ * current_time += dt;
503+
504+ self . phase = Self :: unroll_phase ( self . phase + phase_incr) ;
505+ }
506+
491507 #[ inline]
492508 fn generate_sine ( & mut self ) -> f32 {
493509 let position = self . phase * TABLE_LENGTH_USIZE as f64 ;
0 commit comments