Skip to content

Commit b141729

Browse files
committed
feat(ui): refine radio metadata, modal flow, and live playback updates
1 parent 6a34e5c commit b141729

3 files changed

Lines changed: 432 additions & 72 deletions

File tree

src/audio_player.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
1919
const 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> {
7373
struct 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,

src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ pub struct RadioStation {
123123
pub name: String,
124124
pub url: String,
125125
#[serde(default)]
126+
pub last_station_name: Option<String>,
127+
#[serde(default)]
126128
pub last_stream_title: Option<String>,
127129
#[serde(default)]
128130
pub favorite: bool,
@@ -133,6 +135,7 @@ impl RadioStation {
133135
Self {
134136
name: name.into(),
135137
url: url.into(),
138+
last_station_name: None,
136139
last_stream_title: None,
137140
favorite: false,
138141
}

0 commit comments

Comments
 (0)