refactor(lib): fold utils/audio + autodj-overlap into lib/audio (audio-transition infra; drains utils/playback)

This commit is contained in:
Psychotoxical
2026-06-30 20:30:07 +02:00
parent aea8b7750b
commit 31d4a87401
25 changed files with 27 additions and 27 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ import type { OrbitTransitionSettings } from '@/features/orbit/api/orbit';
import { import {
sanitizeAutodjOverlapCapMode, sanitizeAutodjOverlapCapMode,
sanitizeAutodjOverlapCapSec, sanitizeAutodjOverlapCapSec,
} from '@/utils/playback/autodjOverlapCap'; } from '@/lib/audio/autodjOverlapCap';
/** /**
* Bridge between the local playback-transition settings (in `authStore`) and * Bridge between the local playback-transition settings (in `authStore`) and
@@ -28,7 +28,7 @@ import {
} from '@/features/playback/utils/playback/playbackServer'; } from '@/features/playback/utils/playback/playbackServer';
import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl'; import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb'; import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { audioPlayHiResBlendArgs } from '@/utils/audio/hiResCrossfadeResample'; import { audioPlayHiResBlendArgs } from '@/lib/audio/hiResCrossfadeResample';
import { showToast } from '@/utils/ui/toast'; import { showToast } from '@/utils/ui/toast';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { getPlayGeneration, setIsAudioPaused } from '@/features/playback/store/engineState'; import { getPlayGeneration, setIsAudioPaused } from '@/features/playback/store/engineState';
@@ -89,7 +89,7 @@ import {
} from '@/features/playback/store/seekTargetState'; } from '@/features/playback/store/seekTargetState';
import { refreshWaveformForTrack } from '@/features/playback/store/waveformRefresh'; import { refreshWaveformForTrack } from '@/features/playback/store/waveformRefresh';
import { analyzeBoundary, computeWaveformSilence } from '@/lib/waveform/waveformSilence'; import { analyzeBoundary, computeWaveformSilence } from '@/lib/waveform/waveformSilence';
import { autodjMaxOverlapCapSec } from '@/utils/playback/autodjOverlapCap'; import { autodjMaxOverlapCapSec } from '@/lib/audio/autodjOverlapCap';
import { import {
autodjJsTriggerAtSec, autodjJsTriggerAtSec,
clampCrossfadeSecs, clampCrossfadeSecs,
@@ -1,5 +1,5 @@
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { onAnalysisStorageChanged } from '@/store/analysisSync'; import { onAnalysisStorageChanged } from '@/store/analysisSync';
import { emitNormalizationDebug } from '@/features/playback/store/normalizationDebug'; import { emitNormalizationDebug } from '@/features/playback/store/normalizationDebug';
@@ -1,5 +1,5 @@
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { emitNormalizationDebug } from '@/features/playback/store/normalizationDebug'; import { emitNormalizationDebug } from '@/features/playback/store/normalizationDebug';
import { invokeAudioSetNormalizationDeduped } from '@/features/playback/store/normalizationIpcDedupe'; import { invokeAudioSetNormalizationDeduped } from '@/features/playback/store/normalizationIpcDedupe';
@@ -1,6 +1,6 @@
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { autodjMaxOverlapCapSec } from '@/utils/playback/autodjOverlapCap'; import { autodjMaxOverlapCapSec } from '@/lib/audio/autodjOverlapCap';
import { computeWaveformSilence, planCrossfadeTransition } from '@/lib/waveform/waveformSilence'; import { computeWaveformSilence, planCrossfadeTransition } from '@/lib/waveform/waveformSilence';
import { findLocalPlaybackUrl } from '@/store/localPlaybackResolve'; import { findLocalPlaybackUrl } from '@/store/localPlaybackResolve';
import { playbackCacheKeyForRef } from '@/features/playback/utils/playback/playbackServer'; import { playbackCacheKeyForRef } from '@/features/playback/utils/playback/playbackServer';
@@ -7,7 +7,7 @@ import {
} from '@/features/playback/utils/playback/playbackServer'; } from '@/features/playback/utils/playback/playbackServer';
import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl'; import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb'; import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { audioPlayHiResBlendArgs } from '@/utils/audio/hiResCrossfadeResample'; import { audioPlayHiResBlendArgs } from '@/lib/audio/hiResCrossfadeResample';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { getPlayGeneration, setIsAudioPaused } from '@/features/playback/store/engineState'; import { getPlayGeneration, setIsAudioPaused } from '@/features/playback/store/engineState';
import { touchHotCacheOnPlayback } from '@/features/playback/store/hotCacheTouch'; import { touchHotCacheOnPlayback } from '@/features/playback/store/hotCacheTouch';
@@ -17,7 +17,7 @@ const { authState, invokeMock } = vi.hoisted(() => ({
vi.mock('@tauri-apps/api/core', () => ({ invoke: invokeMock })); vi.mock('@tauri-apps/api/core', () => ({ invoke: invokeMock }));
vi.mock('@/store/authStore', () => ({ useAuthStore: { getState: () => authState } })); vi.mock('@/store/authStore', () => ({ useAuthStore: { getState: () => authState } }));
vi.mock('@/utils/audio/loudnessPreAnalysisSlider', () => ({ vi.mock('@/lib/audio/loudnessPreAnalysisSlider', () => ({
effectiveLoudnessPreAnalysisAttenuationDb: (attenuation: number) => attenuation, effectiveLoudnessPreAnalysisAttenuationDb: (attenuation: number) => attenuation,
})); }));
@@ -1,6 +1,6 @@
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
/** /**
* Two IPC entry points to the Rust normalization pipeline that get hammered * Two IPC entry points to the Rust normalization pipeline that get hammered
@@ -33,7 +33,7 @@ import {
} from '@/store/localPlaybackResolve'; } from '@/store/localPlaybackResolve';
import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl'; import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb'; import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { audioPlayHiResBlendArgs } from '@/utils/audio/hiResCrossfadeResample'; import { audioPlayHiResBlendArgs } from '@/lib/audio/hiResCrossfadeResample';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { consumeCrossfadeDynamicOverlap, getCrossfadeTransition, peekArmedCrossfadeDynamicOverlap } from '@/features/playback/store/crossfadeTrimCache'; import { consumeCrossfadeDynamicOverlap, getCrossfadeTransition, peekArmedCrossfadeDynamicOverlap } from '@/features/playback/store/crossfadeTrimCache';
import { import {
+1 -1
View File
@@ -8,7 +8,7 @@ import {
} from '@/features/playback/utils/playback/playbackServer'; } from '@/features/playback/utils/playback/playbackServer';
import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl'; import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb'; import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { audioPlayHiResBlendArgs } from '@/utils/audio/hiResCrossfadeResample'; import { audioPlayHiResBlendArgs } from '@/lib/audio/hiResCrossfadeResample';
import { songToTrack } from '@/lib/media/songToTrack'; import { songToTrack } from '@/lib/media/songToTrack';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { import {
@@ -1,4 +1,4 @@
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder'; import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb'; import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
@@ -1,5 +1,5 @@
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { autodjMaxOverlapCapSec } from '@/utils/playback/autodjOverlapCap'; import { autodjMaxOverlapCapSec } from '@/lib/audio/autodjOverlapCap';
import { import {
analyzeBoundary, analyzeBoundary,
planCrossfadeTransition, planCrossfadeTransition,
@@ -9,7 +9,7 @@ import {
renderStars, renderStars,
} from '@/utils/componentHelpers/queuePanelHelpers'; } from '@/utils/componentHelpers/queuePanelHelpers';
import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder'; import { loudnessGainPlaceholderUntilCacheDb } from '@/features/playback/utils/audio/loudnessPlaceholder';
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { formatQueueBpmTech, formatQueueMoodLabels } from '@/lib/library/trackEnrichment'; import { formatQueueBpmTech, formatQueueMoodLabels } from '@/lib/library/trackEnrichment';
import { useQueueTrackEnrichment } from '@/features/queue/hooks/useQueueTrackEnrichment'; import { useQueueTrackEnrichment } from '@/features/queue/hooks/useQueueTrackEnrichment';
import { QueueLufsTargetMenu } from '@/features/queue/components/QueueLufsTargetMenu'; import { QueueLufsTargetMenu } from '@/features/queue/components/QueueLufsTargetMenu';
@@ -6,7 +6,7 @@ import { Equalizer } from '@/features/equalizer';
import SettingsSubSection from '@/features/settings/components/SettingsSubSection'; import SettingsSubSection from '@/features/settings/components/SettingsSubSection';
import { SettingsGroup } from '@/features/settings/components/SettingsGroup'; import { SettingsGroup } from '@/features/settings/components/SettingsGroup';
import { SettingsToggle } from '@/features/settings/components/SettingsToggle'; import { SettingsToggle } from '@/features/settings/components/SettingsToggle';
import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/utils/audio/loudnessPreAnalysisSlider'; import { effectiveLoudnessPreAnalysisAttenuationDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { useAudioDevicesProbe } from '@/features/playback/hooks/useAudioDevicesProbe'; import { useAudioDevicesProbe } from '@/features/playback/hooks/useAudioDevicesProbe';
import { IS_MACOS } from '@/lib/util/platform'; import { IS_MACOS } from '@/lib/util/platform';
import { AudioOutputDeviceSection } from '@/features/settings/components/audio/AudioOutputDeviceSection'; import { AudioOutputDeviceSection } from '@/features/settings/components/audio/AudioOutputDeviceSection';
@@ -2,7 +2,7 @@ import {
HI_RES_CROSSFADE_RESAMPLE_OPTIONS, HI_RES_CROSSFADE_RESAMPLE_OPTIONS,
type HiResCrossfadeResampleHz, type HiResCrossfadeResampleHz,
sanitizeHiResCrossfadeResampleHz, sanitizeHiResCrossfadeResampleHz,
} from '@/utils/audio/hiResCrossfadeResample'; } from '@/lib/audio/hiResCrossfadeResample';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { SettingsSubCard, SettingsField } from '@/features/settings/components/SettingsSubCard'; import { SettingsSubCard, SettingsField } from '@/features/settings/components/SettingsSubCard';
@@ -5,7 +5,7 @@ import { useOrbitStore } from '@/features/orbit';
import { import {
AUTODJ_OVERLAP_CAP_MAX_SEC, AUTODJ_OVERLAP_CAP_MAX_SEC,
AUTODJ_OVERLAP_CAP_MIN_SEC, AUTODJ_OVERLAP_CAP_MIN_SEC,
} from '@/utils/playback/autodjOverlapCap'; } from '@/lib/audio/autodjOverlapCap';
import { import {
getTransitionMode, getTransitionMode,
setTransitionMode, setTransitionMode,
@@ -3,7 +3,7 @@ import {
autodjMaxOverlapCapSec, autodjMaxOverlapCapSec,
DEFAULT_AUTODJ_OVERLAP_CAP_SEC, DEFAULT_AUTODJ_OVERLAP_CAP_SEC,
sanitizeAutodjOverlapCapSec, sanitizeAutodjOverlapCapSec,
} from './autodjOverlapCap'; } from '@/lib/audio/autodjOverlapCap';
describe('autodjOverlapCap', () => { describe('autodjOverlapCap', () => {
it('sanitizes cap seconds to 230', () => { it('sanitizes cap seconds to 230', () => {
@@ -1,4 +1,4 @@
import type { AuthState } from '../../store/authStoreTypes'; import type { AuthState } from '@/store/authStoreTypes';
import { DYNAMIC_OVERLAP_HARD_CAP_SEC } from '@/lib/waveform/waveformSilence'; import { DYNAMIC_OVERLAP_HARD_CAP_SEC } from '@/lib/waveform/waveformSilence';
export type AutodjOverlapCapMode = 'auto' | 'limit'; export type AutodjOverlapCapMode = 'auto' | 'limit';
@@ -3,7 +3,7 @@ import {
DEFAULT_HI_RES_CROSSFADE_RESAMPLE_HZ, DEFAULT_HI_RES_CROSSFADE_RESAMPLE_HZ,
audioPlayHiResBlendArgs, audioPlayHiResBlendArgs,
sanitizeHiResCrossfadeResampleHz, sanitizeHiResCrossfadeResampleHz,
} from './hiResCrossfadeResample'; } from '@/lib/audio/hiResCrossfadeResample';
describe('hiResCrossfadeResample', () => { describe('hiResCrossfadeResample', () => {
it('defaults unknown values to 44.1 kHz', () => { it('defaults unknown values to 44.1 kHz', () => {
+2 -2
View File
@@ -1,8 +1,8 @@
import { clampStoredLoudnessPreAnalysisAttenuationRefDb } from '../utils/audio/loudnessPreAnalysisSlider'; import { clampStoredLoudnessPreAnalysisAttenuationRefDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { import {
sanitizeAutodjOverlapCapMode, sanitizeAutodjOverlapCapMode,
sanitizeAutodjOverlapCapSec, sanitizeAutodjOverlapCapSec,
} from '../utils/playback/autodjOverlapCap'; } from '@/lib/audio/autodjOverlapCap';
import { DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB } from './authStoreDefaults'; import { DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB } from './authStoreDefaults';
import { updateReplayGainForCurrentTrack } from './playbackEngineBridge'; import { updateReplayGainForCurrentTrack } from './playbackEngineBridge';
import type { AuthState } from './authStoreTypes'; import type { AuthState } from './authStoreTypes';
+1 -1
View File
@@ -1,4 +1,4 @@
import { clampStoredLoudnessPreAnalysisAttenuationRefDb } from '../utils/audio/loudnessPreAnalysisSlider'; import { clampStoredLoudnessPreAnalysisAttenuationRefDb } from '@/lib/audio/loudnessPreAnalysisSlider';
import { import {
DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB, DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB,
DEFAULT_LIBRARY_GRID_MAX_COLUMNS, DEFAULT_LIBRARY_GRID_MAX_COLUMNS,
+3 -3
View File
@@ -1,13 +1,13 @@
import { IS_LINUX } from '@/lib/util/platform'; import { IS_LINUX } from '@/lib/util/platform';
import { sanitizeHiResCrossfadeResampleHz } from '../utils/audio/hiResCrossfadeResample'; import { sanitizeHiResCrossfadeResampleHz } from '@/lib/audio/hiResCrossfadeResample';
import { import {
sanitizeAutodjOverlapCapMode, sanitizeAutodjOverlapCapMode,
sanitizeAutodjOverlapCapSec, sanitizeAutodjOverlapCapSec,
} from '../utils/playback/autodjOverlapCap'; } from '@/lib/audio/autodjOverlapCap';
import { import {
LOUDNESS_PRE_ANALYSIS_REF_TARGET_LUFS, LOUDNESS_PRE_ANALYSIS_REF_TARGET_LUFS,
clampStoredLoudnessPreAnalysisAttenuationRefDb, clampStoredLoudnessPreAnalysisAttenuationRefDb,
} from '../utils/audio/loudnessPreAnalysisSlider'; } from '@/lib/audio/loudnessPreAnalysisSlider';
import { DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB } from './authStoreDefaults'; import { DEFAULT_LOUDNESS_PRE_ANALYSIS_ATTENUATION_DB } from './authStoreDefaults';
import { import {
clampMixFilterMinStars, clampMixFilterMinStars,
+1 -1
View File
@@ -1,4 +1,4 @@
import type { HiResCrossfadeResampleHz } from '../utils/audio/hiResCrossfadeResample'; import type { HiResCrossfadeResampleHz } from '@/lib/audio/hiResCrossfadeResample';
import type { EntityRatingSupportLevel } from '@/lib/api/subsonicTypes'; import type { EntityRatingSupportLevel } from '@/lib/api/subsonicTypes';
import type { import type {
AudiomusePluginProbeResult, AudiomusePluginProbeResult,