diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 3997bd64..d0d97cce 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -510,7 +510,7 @@ "replayGainPreamp": "{{ReplayGain}} preamp (dB)", "replayGainPreamp_description": "adjust the preamp gain applied to the {{ReplayGain}} values", "sampleRate": "sample rate", - "sampleRate_description": "select the output sample rate to be used if the sample frequency selected is different from that of the current media", + "sampleRate_description": "select the output sample rate to be used if the sample frequency selected is different from that of the current media. a value less than 8000 will use the default frequency", "savePlayQueue": "save play queue", "savePlayQueue_description": "save the play queue when the application is closed and restore it when the application is opened", "scrobble": "scrobble", diff --git a/src/renderer/components/audio-player/index.tsx b/src/renderer/components/audio-player/index.tsx index 7f8b1904..6490144c 100644 --- a/src/renderer/components/audio-player/index.tsx +++ b/src/renderer/components/audio-player/index.tsx @@ -7,10 +7,11 @@ import { crossfadeHandler, gaplessHandler, } from '/@/renderer/components/audio-player/utils/list-handlers'; -import { useSettingsStore } from '/@/renderer/store/settings.store'; +import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store'; import type { CrossfadeStyle } from '/@/renderer/types'; import { PlaybackStyle, PlayerStatus } from '/@/renderer/types'; import { useSpeed } from '/@/renderer/store'; +import { toast } from '/@/renderer/components/toast'; interface AudioPlayerProps extends ReactPlayerProps { crossfadeDuration: number; @@ -60,6 +61,7 @@ export const AudioPlayer = forwardRef( const [isTransitioning, setIsTransitioning] = useState(false); const audioDeviceId = useSettingsStore((state) => state.playback.audioDeviceId); const playback = useSettingsStore((state) => state.playback.mpvProperties); + const { resetSampleRate } = useSettingsStoreActions(); const playbackSpeed = useSpeed(); const [webAudio, setWebAudio] = useState(null); @@ -119,10 +121,21 @@ export const AudioPlayer = forwardRef( useEffect(() => { if ('AudioContext' in window) { - const context = new AudioContext({ - latencyHint: 'playback', - sampleRate: playback.audioSampleRateHz || undefined, - }); + let context: AudioContext; + + try { + context = new AudioContext({ + latencyHint: 'playback', + sampleRate: playback.audioSampleRateHz || undefined, + }); + } catch (error) { + // In practice, this should never be hit because the UI should validate + // the range. However, the actual supported range is not guaranteed + toast.error({ message: (error as Error).message }); + context = new AudioContext({ latencyHint: 'playback' }); + resetSampleRate(); + } + const gain = context.createGain(); gain.connect(context.destination); diff --git a/src/renderer/features/settings/components/playback/mpv-settings.tsx b/src/renderer/features/settings/components/playback/mpv-settings.tsx index a7ab461f..15443673 100644 --- a/src/renderer/features/settings/components/playback/mpv-settings.tsx +++ b/src/renderer/features/settings/components/playback/mpv-settings.tsx @@ -206,11 +206,16 @@ export const MpvSettings = () => { { control: ( { const value = Number(e.currentTarget.value); - handleSetMpvProperty('audioSampleRateHz', value > 0 ? value : undefined); + // Setting a value of `undefined` causes an error for MPV. Use 0 instead + handleSetMpvProperty('audioSampleRateHz', value >= 8000 ? value : value); }} /> ), diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts index 75144475..f933bf2e 100644 --- a/src/renderer/store/settings.store.ts +++ b/src/renderer/store/settings.store.ts @@ -251,6 +251,7 @@ export interface SettingsState { export interface SettingsSlice extends SettingsState { actions: { reset: () => void; + resetSampleRate: () => void; setSettings: (data: Partial) => void; setSidebarItems: (items: SidebarItemType[]) => void; setTable: (type: TableType, data: DataTableProps) => void; @@ -567,6 +568,11 @@ export const useSettingsStore = create()( set(initialState); } }, + resetSampleRate: () => { + set((state) => { + state.playback.mpvProperties.audioSampleRateHz = 0; + }); + }, setSettings: (data) => { set({ ...get(), ...data }); },