@@ -14,8 +14,8 @@ use std::{
1414 time:: { Duration , Instant } ,
1515} ;
1616
17- const RADIO_VISUALIZER_HISTORY_SECONDS : usize = 60 ;
18- const RADIO_VISUALIZER_BUCKETS_PER_SECOND : usize = 2 ;
17+ const RADIO_VISUALIZER_HISTORY_SECONDS : usize = 15 ;
18+ const RADIO_VISUALIZER_BUCKETS_PER_SECOND : usize = 8 ;
1919const RADIO_VISUALIZER_MAX_BUCKETS : usize = RADIO_VISUALIZER_HISTORY_SECONDS * RADIO_VISUALIZER_BUCKETS_PER_SECOND ;
2020
2121#[ derive( Clone , Debug ) ]
@@ -73,6 +73,7 @@ impl<R> Seek for RadioStream<R> {
7373struct RadioVisualizerState {
7474 peaks : VecDeque < f32 > ,
7575 current_peak : f32 ,
76+ smoothed_peak : f32 ,
7677 sample_counter : usize ,
7778}
7879
@@ -211,17 +212,25 @@ fn record_radio_peak(visualizer: &RadioVisualizerHandle, sample_rate: u32, peak:
211212 let Ok ( mut state) = visualizer. lock ( ) else {
212213 return ;
213214 } ;
214- state. current_peak = state. current_peak . max ( peak. min ( 1.0 ) ) ;
215+
216+ let peak = peak. abs ( ) . min ( 1.0 ) ;
217+ let envelope = peak. powf ( 0.72 ) ;
218+ state. smoothed_peak = if envelope > state. smoothed_peak {
219+ state. smoothed_peak * 0.62 + envelope * 0.38
220+ } else {
221+ state. smoothed_peak * 0.90 + envelope * 0.10
222+ } ;
223+ state. current_peak = state. current_peak . max ( state. smoothed_peak ) ;
215224 state. sample_counter += 1 ;
216225
217226 let samples_per_bucket = ( sample_rate. max ( 1 ) as usize / RADIO_VISUALIZER_BUCKETS_PER_SECOND ) . max ( 1 ) ;
218227 if state. sample_counter >= samples_per_bucket {
219- let peak = state. current_peak ;
228+ let peak = ( state. current_peak * 1.18 ) . clamp ( 0.015 , 1.0 ) ;
220229 state. peaks . push_back ( peak) ;
221230 while state. peaks . len ( ) > RADIO_VISUALIZER_MAX_BUCKETS {
222231 state. peaks . pop_front ( ) ;
223232 }
224- state. current_peak = 0.0 ;
233+ state. current_peak = state . smoothed_peak * 0.72 ;
225234 state. sample_counter = 0 ;
226235 }
227236}
@@ -392,6 +401,33 @@ impl AudioPlayer {
392401 Ok ( playback_info ( path, render_info) )
393402 }
394403
404+ pub fn play_file_with_orbit_from_live_position (
405+ & mut self ,
406+ path : & Path ,
407+ settings : DspSettings ,
408+ start_seconds : f32 ,
409+ ) -> Result < PlaybackInfo > {
410+ let render_started_at = Instant :: now ( ) ;
411+ let ( mut processed_samples, mut render_info, sample_rate) = self . render_file ( path, settings, start_seconds) ?;
412+ let render_elapsed_seconds = render_started_at. elapsed ( ) . as_secs_f32 ( ) ;
413+ let compensated_start_seconds = start_seconds + render_elapsed_seconds;
414+
415+ if render_elapsed_seconds > 0.025 {
416+ let trim_frames = ( render_elapsed_seconds * sample_rate as f32 ) . round ( ) . max ( 0.0 ) as usize ;
417+ let trim_samples = ( trim_frames * 2 ) . min ( processed_samples. len ( ) ) ;
418+ if trim_samples > 0 && trim_samples < processed_samples. len ( ) {
419+ processed_samples. drain ( 0 ..trim_samples) ;
420+ render_info. rendered_duration_seconds = ( render_info. rendered_duration_seconds - render_elapsed_seconds) . max ( 0.0 ) ;
421+ }
422+ }
423+
424+ self . stop ( ) ;
425+ let rendered_duration = Duration :: from_secs_f32 ( render_info. rendered_duration_seconds . max ( 0.0 ) ) ;
426+ self . play_processed_samples ( processed_samples, sample_rate, rendered_duration, path, settings, compensated_start_seconds) ?;
427+
428+ Ok ( playback_info ( path, render_info) )
429+ }
430+
395431 pub fn crossfade_to_file_with_orbit_from (
396432 & mut self ,
397433 path : & Path ,
0 commit comments