mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
feat(playback): global speed with three strategies (#852)
* feat(playback): global speed with three strategies Add Settings → Audio and player-bar controls for global playback speed (speed with auto pitch correction as default, varispeed, manual pitch shift). Time-stretch runs on a background worker; Orbit sessions force 1.0× passthrough. * fix(playback): align seekbar, seek, and progress on content timeline Unify UI timebase across varispeed and preserve strategies: full-track duration, speed-scaled progress for DSP paths, and content-timeline seeks without varispeed scaling. Reset the sample counter after seek so clicks land correctly; restart playback on strategy/enable changes instead of fragile hot-switching. * fix(ui): anchor playback speed popover like volume controls Replace the centered EQ-style modal with a player-bar popover (outside click, Escape, reposition on scroll). Show compact controls in the bar and overflow menu; keep strategy hints and labels in Settings only. * docs(release): CHANGELOG and credits for playback speed (PR #852) * docs(changelog): add playback speed entry for PR #852 * fix(clippy): simplify raw_counter_samples branch for CI Collapse duplicate if branches flagged by clippy::if-same-then-else. * fix(ui): wheel on pitch slider adjusts pitch in speed popover In compact player-bar controls, scroll over the pitch row changes pitch; elsewhere in the panel changes speed. Stop propagation so overflow menu wheel does not tweak volume. * fix(playback): address PR #852 review and drop ineffective dynamic imports Translate playback-rate strings for de/fr/es/zh/nb/nl/ro; restamp sample counter on live preserve-path speed changes; use neutral rate atomics for radio progress; static-import playerStore in playListenSession (move preview volume sync to previewPlayerVolumeSync side-effect module). * fix(i18n): translate playback-rate strategy labels in all locales Replace leftover English Varispeed/Pitch strings in ru and other non-en settings blocks so popover strategy buttons and hints read natively. * fix(i18n): refine German varispeed label to "Tonhöhe folgt dem Tempo" --------- Co-authored-by: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { create } from 'zustand';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { usePlayerStore } from './playerStore';
|
||||
import { useAuthStore } from './authStore';
|
||||
import { useOrbitStore } from './orbitStore';
|
||||
import { isOrbitPlaybackSyncActive } from '../utils/orbit';
|
||||
|
||||
/** Minimal track info needed to surface the preview in the player bar UI. */
|
||||
export interface PreviewingTrack {
|
||||
@@ -55,7 +55,7 @@ const PREVIEW_VOLUME_MATCH = true;
|
||||
* preview-specific gain, so we pre-multiply here). Master headroom is added on
|
||||
* the Rust side.
|
||||
*/
|
||||
function computePreviewVolume(): number {
|
||||
export function computePreviewVolume(): number {
|
||||
const auth = useAuthStore.getState();
|
||||
let volume = usePlayerStore.getState().volume;
|
||||
if (PREVIEW_VOLUME_MATCH && auth.normalizationEngine === 'loudness') {
|
||||
@@ -82,10 +82,7 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
// preview started by a guest would yank the host's track out from
|
||||
// under them. UI buttons are hidden via `[data-orbit-active]` CSS;
|
||||
// this guards keyboard shortcuts / programmatic callers.
|
||||
const orbit = useOrbitStore.getState();
|
||||
const inOrbit = (orbit.role === 'host' || orbit.role === 'guest')
|
||||
&& (orbit.phase === 'active' || orbit.phase === 'joining' || orbit.phase === 'starting');
|
||||
if (inOrbit) return;
|
||||
if (isOrbitPlaybackSyncActive()) return;
|
||||
|
||||
const current = get().previewingId;
|
||||
if (current === song.id) {
|
||||
@@ -158,14 +155,3 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0, audioStarted: false });
|
||||
},
|
||||
}));
|
||||
|
||||
// Keep the preview sink in sync with player volume slider movements while a
|
||||
// preview is in flight. Without this the Rust preview Sink stays at whatever
|
||||
// level was set at `audio_preview_play` — slider drags only ramp the main
|
||||
// sink. Auth/normalization changes during preview are intentionally ignored
|
||||
// (preview is short and the case is rare).
|
||||
usePlayerStore.subscribe((state, prev) => {
|
||||
if (state.volume === prev.volume) return;
|
||||
if (!usePreviewStore.getState().previewingId) return;
|
||||
invoke('audio_preview_set_volume', { volume: computePreviewVolume() }).catch(() => {});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user