Skip to content

Commit 610ef76

Browse files
committed
feat(player): refine repeat state, sticky folders, and silence skipping
1 parent 861fb91 commit 610ef76

7 files changed

Lines changed: 190 additions & 97 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: Release
2+
run-name: Release v${{ inputs.version }}
23

34
on:
45
workflow_dispatch:

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "audio-orbit"
3-
version = "0.8.11"
3+
version = "0.8.9"
44
edition = "2021"
55
build = "build.rs"
66

src/audio-orbit.exe.manifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<assemblyIdentity
44
type="win32"
55
name="AudioOrbit"
6-
version="0.8.11.0"
6+
version="0.8.9.0"
77
processorArchitecture="*"
88
/>
99
<dependency>

src/audio_player.rs

Lines changed: 30 additions & 2 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 = 180;
18-
const RADIO_VISUALIZER_BUCKETS_PER_SECOND: usize = 5;
17+
const RADIO_VISUALIZER_HISTORY_SECONDS: usize = 60;
18+
const RADIO_VISUALIZER_BUCKETS_PER_SECOND: usize = 2;
1919
const RADIO_VISUALIZER_MAX_BUCKETS: usize = RADIO_VISUALIZER_HISTORY_SECONDS * RADIO_VISUALIZER_BUCKETS_PER_SECOND;
2020

2121
#[derive(Clone, Debug)]
@@ -330,6 +330,9 @@ impl AudioPlayer {
330330

331331
let peaks: Vec<f32> = state.peaks.iter().copied().collect();
332332
if peaks.len() <= requested_points {
333+
if peaks.len() == RADIO_VISUALIZER_MAX_BUCKETS && peaks.len() > 1 {
334+
return Self::resample_radio_peaks(&peaks, requested_points);
335+
}
333336
return peaks;
334337
}
335338

@@ -349,6 +352,31 @@ impl AudioPlayer {
349352
rendered
350353
}
351354

355+
fn resample_radio_peaks(peaks: &[f32], requested_points: usize) -> Vec<f32> {
356+
if requested_points == 0 || peaks.is_empty() {
357+
return Vec::new();
358+
}
359+
if requested_points == peaks.len() {
360+
return peaks.to_vec();
361+
}
362+
363+
let mut rendered = Vec::with_capacity(requested_points);
364+
let last_index = peaks.len().saturating_sub(1) as f32;
365+
let output_last_index = requested_points.saturating_sub(1).max(1) as f32;
366+
367+
for index in 0..requested_points {
368+
let source_position = index as f32 / output_last_index * last_index;
369+
let left_index = source_position.floor() as usize;
370+
let right_index = source_position.ceil() as usize;
371+
let mix = source_position - left_index as f32;
372+
let left = peaks.get(left_index).copied().unwrap_or(0.0);
373+
let right = peaks.get(right_index).copied().unwrap_or(left);
374+
rendered.push(left + (right - left) * mix);
375+
}
376+
377+
rendered
378+
}
379+
352380
pub fn play_file_with_orbit_from(
353381
&mut self,
354382
path: &Path,

src/dsp.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,11 @@ pub fn render_orbit_to_stereo(
142142
let smoothing_time_seconds = 0.08 + smoothness * 0.70;
143143
let smoothing_coeff = (-1.0 / (sample_rate.max(1) as f32 * smoothing_time_seconds)).exp();
144144

145-
let silence_limit = settings.silence_threshold_seconds.max(1) as usize * sample_rate.max(1) as usize;
145+
let sample_rate_usize = sample_rate.max(1) as usize;
146+
let silence_limit = settings.silence_threshold_seconds.max(1) as usize * sample_rate_usize;
147+
let silence_bridge_limit = (sample_rate_usize / 20).max(1);
146148
let mut consecutive_silent_frames = 0usize;
149+
let mut non_silent_bridge_frames = 0usize;
147150
let mut silence_ranges = Vec::new();
148151
let mut skipped_silence_start: Option<usize> = None;
149152

@@ -156,11 +159,17 @@ pub fn render_orbit_to_stereo(
156159

157160
for frame_index in start_frame..frame_count {
158161
let source_sample = mono[frame_index];
159-
let is_silent = source_sample.abs() <= silence_floor;
160-
if is_silent {
162+
let is_below_silence_floor = source_sample.abs() <= silence_floor;
163+
if is_below_silence_floor {
164+
consecutive_silent_frames += 1;
165+
non_silent_bridge_frames = 0;
166+
} else if consecutive_silent_frames > 0 && non_silent_bridge_frames < silence_bridge_limit {
167+
// AIMP-style silence skipping should not be broken by tiny decoder clicks or noise-floor spikes.
168+
non_silent_bridge_frames += 1;
161169
consecutive_silent_frames += 1;
162170
} else {
163171
consecutive_silent_frames = 0;
172+
non_silent_bridge_frames = 0;
164173
}
165174

166175
if settings.skip_silence_enabled && consecutive_silent_frames > silence_limit {
@@ -256,7 +265,11 @@ pub fn render_orbit_to_stereo(
256265
}
257266

258267
fn silence_floor_from_percent(percent: u8) -> f32 {
259-
percent.clamp(1, 20) as f32 / 100.0
268+
if percent == 0 {
269+
0.001
270+
} else {
271+
percent.clamp(1, 20) as f32 / 100.0
272+
}
260273
}
261274

262275
fn render_plain_stereo(
@@ -271,19 +284,27 @@ fn render_plain_stereo(
271284
silence_floor: f32,
272285
) -> (Vec<f32>, f32, Vec<(f32, f32)>) {
273286
let frame_count = mono.len();
274-
let silence_limit = silence_threshold_seconds.max(1) as usize * sample_rate.max(1) as usize;
287+
let sample_rate_usize = sample_rate.max(1) as usize;
288+
let silence_limit = silence_threshold_seconds.max(1) as usize * sample_rate_usize;
289+
let silence_bridge_limit = (sample_rate_usize / 20).max(1);
275290
let mut consecutive_silent_frames = 0usize;
291+
let mut non_silent_bridge_frames = 0usize;
276292
let mut silence_ranges = Vec::new();
277293
let mut skipped_silence_start: Option<usize> = None;
278294
let mut output = Vec::with_capacity((frame_count.saturating_sub(start_frame)) * 2);
279295

280296
for frame_index in start_frame..frame_count {
281297
let source_sample = mono[frame_index];
282-
let is_silent = source_sample.abs() <= silence_floor;
283-
if is_silent {
298+
let is_below_silence_floor = source_sample.abs() <= silence_floor;
299+
if is_below_silence_floor {
300+
consecutive_silent_frames += 1;
301+
non_silent_bridge_frames = 0;
302+
} else if consecutive_silent_frames > 0 && non_silent_bridge_frames < silence_bridge_limit {
303+
non_silent_bridge_frames += 1;
284304
consecutive_silent_frames += 1;
285305
} else {
286306
consecutive_silent_frames = 0;
307+
non_silent_bridge_frames = 0;
287308
}
288309

289310
if skip_silence_enabled && consecutive_silent_frames > silence_limit {

0 commit comments

Comments
 (0)