/
magnusroot
/
nm
Обзор
Документация
Войти
/
magnusroot
/
nm
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
crates/player/src/types.rs
178 строк
7 KB
Magnus Root
First version
13 июл 2026, 09:24
13 июл 2026, 09:24
50f8b8c
Код
Авторство
О чём код?
use std::path::PathBuf; use std::time::Duration; /// Режим повтора очереди. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum RepeatMode { #[default] Off, Track, All, } impl RepeatMode { pub fn cycle(self) -> Self { match self { RepeatMode::Off => RepeatMode::All, RepeatMode::All => RepeatMode::Track, RepeatMode::Track => RepeatMode::Off, } } } /// Допустимые скорости воспроизведения (тайпраст-стайл: питч меняется вместе со скоростью). pub const SPEED_STEPS: [f32; 7] = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75]; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Speed(pub f32); impl Default for Speed { fn default() -> Self { Speed(1.0) } } impl Speed { pub fn clamp_to_steps(value: f32) -> f32 { SPEED_STEPS .iter() .copied() .min_by(|a, b| { (a - value) .abs() .partial_cmp(&(b - value).abs()) .unwrap() }) .unwrap_or(1.0) } pub fn next_up(self) -> Self { let idx = SPEED_STEPS .iter() .position(|s| (*s - self.0).abs() < f32::EPSILON) .unwrap_or(3); Speed(SPEED_STEPS[(idx + 1).min(SPEED_STEPS.len() - 1)]) } pub fn next_down(self) -> Self { let idx = SPEED_STEPS .iter() .position(|s| (*s - self.0).abs() < f32::EPSILON) .unwrap_or(3); Speed(SPEED_STEPS[idx.saturating_sub(1)]) } } /// Количество полос эквалайзера. pub const EQ_BANDS: usize = 8; /// Центральные частоты полос (Гц), классическая графическая раскладка. pub const EQ_FREQS: [f32; EQ_BANDS] = [60.0, 150.0, 400.0, 1000.0, 2400.0, 6000.0, 12000.0, 16000.0]; #[derive(Debug, Clone, Copy, PartialEq)] pub enum PlaybackStatus { Stopped, Playing, Paused, } /// Элемент очереди воспроизведения. Обычно это просто "весь файл", но для cue-листов /// (несколько логических треков внутри одного физического файла) start/end задают диапазон, /// а title/artist_override — то, что показывать вместо тегов самого файла. #[derive(Debug, Clone, PartialEq)] pub struct QueueItem { pub path: PathBuf, pub start: Duration, pub end: Option<Duration>, pub title_override: Option<String>, pub artist_override: Option<String>, /// Значение тега ReplayGain (дБ), если есть в файле — приоритет над AGC-левеллером. pub replay_gain_db: Option<f32>, } impl QueueItem { pub fn whole_file(path: PathBuf) -> Self { QueueItem { path, start: Duration::ZERO, end: None, title_override: None, artist_override: None, replay_gain_db: None, } } } /// Что именно поставить в очередь при открытии трека напрямую. #[derive(Debug, Clone)] pub enum OpenMode { /// Только этот трек. SingleTrack, /// Весь альбом (все треки из той же папки/альбома), отсортированный по номеру трека. WholeAlbum, } #[derive(Debug, Clone)] pub enum PlayerCommand { /// Открыть файл напрямую: либо один трек, либо весь альбом вокруг него. OpenPath(PathBuf, OpenMode), /// Заменить очередь целиком (например, при выборе плейлиста) и начать играть с индекса. SetQueue(Vec<QueueItem>, usize), /// Добавить трек в конец текущей очереди. Enqueue(PathBuf), PlayPause, Stop, Next, Previous, /// Позиция отсчитывается от начала ТЕКУЩЕГО трека (а не файла) — так, как её видит /// пользователь на прогресс-баре. Для cue-треков это не то же самое, что абсолютная /// позиция в физическом файле — движок сам делает пересчёт. Seek(Duration), SetSpeed(f32), ToggleShuffle, CycleRepeat, SetEqBand(usize, f32), ResetEq, /// Играть интернет-радио по URL. Название нужно только для отображения в UI/тегах. PlayRadio { name: String, url: String }, ToggleMute, /// Плавное затухание громкости в последние несколько секунд трека. ToggleFadeOut, /// Выравнивание громкости между треками: тег ReplayGain в приоритете, /// адаптивный левеллер (AGC) как fallback для файлов без тега. ToggleLoudnessNorm, } #[derive(Debug, Clone)] pub struct TrackInfo { pub path: PathBuf, pub title: String, pub artist: String, pub album: String, pub duration: Option<Duration>, pub cover: Option<Vec<u8>>, } #[derive(Debug, Clone)] pub enum PlayerEvent { TrackChanged(TrackInfo), Position(Duration), StatusChanged(PlaybackStatus), SpeedChanged(f32), ShuffleChanged(bool), RepeatChanged(RepeatMode), EqChanged([f32; EQ_BANDS]), MuteChanged(bool), /// Текст "сейчас играет", распарсенный из ICY-метаданных потока (если станция их отдаёт). RadioMetadata(String), /// Индекс (в исходном порядке, как он был передан в SetQueue) элемента очереди, /// который сейчас играет. Шлётся вместе с TrackChanged — так UI однозначно знает, /// какой пункт своей локальной копии очереди подсвечивать, даже если несколько /// элементов указывают на один физический файл (cue-листы). QueueIndexChanged(usize), /// Текущий спектр (логарифмические полосы, 0..1), для визуализатора в UI. Spectrum(Vec<f32>), FadeOutChanged(bool), LoudnessNormChanged(bool), QueueFinished, Error(String), }