Adds a 10-band graphic equalizer to AudioSettings (enabled flag + per-band dB gains, normalised to 10 entries and clamped to range). Presets return gain curves; the settings page gains EQ UI. libmpv applies the filter on Linux (Android parity pending). Old persisted settings without EQ fields load as disabled + flat. Also includes the requirements/traceability/ux-flows doc updates for this feature and the home long-press routing (UR-058/DR-087). TRACES: UR-027 | IR-020, DR-030 | UT-079, UT-080, UT-081, UT-082
84 lines
2.7 KiB
Rust
84 lines
2.7 KiB
Rust
//! Audio and video playback settings commands.
|
|
//!
|
|
//! TRACES: UR-022, UR-027, UR-031, UR-032, UR-033 | DR-025, DR-030, DR-034, DR-035, DR-036, IR-020
|
|
|
|
use tauri::State;
|
|
|
|
use super::{PlayerStateWrapper, VideoSettingsWrapper};
|
|
use crate::player::AutoplaySettings;
|
|
use crate::settings::{AudioSettings, EqPreset, VideoSettings};
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn player_set_audio_settings(
|
|
player: State<'_, PlayerStateWrapper>,
|
|
settings: AudioSettings,
|
|
) -> Result<AudioSettings, String> {
|
|
// Validate/normalise domain values before applying: clamp crossfade to its
|
|
// range and normalise the equalizer band vector (length + gain clamps).
|
|
let validated = settings
|
|
.with_crossfade_clamped()
|
|
.with_equalizer_normalised();
|
|
let mut controller = player.0.lock().await;
|
|
controller
|
|
.set_audio_settings(&validated)
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(controller.audio_settings())
|
|
}
|
|
|
|
/// The built-in equalizer presets and their per-band gain curves (dB), for the
|
|
/// settings UI. The curve numbers are domain data defined by the band layout,
|
|
/// so the frontend reads them here rather than encoding them.
|
|
///
|
|
/// TRACES: UR-027 | DR-030
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn player_get_eq_presets() -> Result<Vec<(EqPreset, Vec<f32>)>, String> {
|
|
Ok(EqPreset::ALL
|
|
.iter()
|
|
.map(|p| (*p, p.gains().to_vec()))
|
|
.collect())
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn player_get_audio_settings(
|
|
player: State<'_, PlayerStateWrapper>,
|
|
) -> Result<AudioSettings, String> {
|
|
let controller = player.0.lock().await;
|
|
Ok(controller.audio_settings())
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn player_set_video_settings(
|
|
video_settings: State<'_, VideoSettingsWrapper>,
|
|
player: State<'_, PlayerStateWrapper>,
|
|
settings: VideoSettings,
|
|
) -> Result<VideoSettings, String> {
|
|
let validated = settings.with_countdown_clamped();
|
|
{
|
|
let mut current = video_settings.0.lock().map_err(|e| e.to_string())?;
|
|
*current = validated.clone();
|
|
} // Drop MutexGuard before await
|
|
|
|
// Sync to PlayerController's autoplay settings so on_playback_ended() uses current values
|
|
let controller = player.0.lock().await;
|
|
controller.set_autoplay_settings(AutoplaySettings {
|
|
enabled: validated.auto_play_next_episode,
|
|
countdown_seconds: validated.auto_play_countdown_seconds,
|
|
max_episodes: validated.auto_play_max_episodes,
|
|
});
|
|
|
|
Ok(validated)
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn player_get_video_settings(
|
|
video_settings: State<'_, VideoSettingsWrapper>,
|
|
) -> Result<VideoSettings, String> {
|
|
let current = video_settings.0.lock().map_err(|e| e.to_string())?;
|
|
Ok(current.clone())
|
|
}
|