diff --git a/publish/changeLog.md b/publish/changeLog.md index a7644abbc2..0241911da5 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,5 +1,6 @@ ### 新增 +- 新增 设置-播放设置-使用设备能处理的最大声道数输出音频 设置并默认启用(#1873) - 允许添加 `m4a`、`oga` 格式的本地歌曲到列表中(#1864) - 开放API支持跨域请求(#1872 @Ceale) @@ -19,6 +20,7 @@ ### 变更 - 设置-播放设置-优先播放320k音质选项改为“优先播放的音质”,允许选择更高优先播放的音质,如果歌曲及音源支持的话(#1839) +- 设置-播放设置-使用设备能处理的最大声道数输出音频 设置默认启用,此前固定为2声道输出 ### 开放API变更 diff --git a/src/common/defaultSetting.ts b/src/common/defaultSetting.ts index 176dd45e2a..2f6c599b60 100644 --- a/src/common/defaultSetting.ts +++ b/src/common/defaultSetting.ts @@ -31,6 +31,7 @@ const defaultSetting: LX.AppSetting = { 'player.isMute': false, 'player.playbackRate': 1, 'player.preservesPitch': true, + 'player.isMaxOutputChannelCount': true, 'player.mediaDeviceId': 'default', 'player.isMediaDeviceRemovedStopPlay': false, 'player.isShowLyricTranslation': false, diff --git a/src/common/types/app_setting.d.ts b/src/common/types/app_setting.d.ts index 610dc569d0..b61467d6a3 100644 --- a/src/common/types/app_setting.d.ts +++ b/src/common/types/app_setting.d.ts @@ -123,6 +123,11 @@ declare global { */ 'player.preservesPitch': boolean + /** + * 使用设备能处理的最大声道数输出音频 + */ + 'player.isMaxOutputChannelCount': boolean + /** * 音频输出设备id */ diff --git a/src/lang/en-us.json b/src/lang/en-us.json index 469a4fdcc0..155b26d965 100644 --- a/src/lang/en-us.json +++ b/src/lang/en-us.json @@ -513,6 +513,7 @@ "setting__play_lyric_roma": "Show lyrics roman", "setting__play_lyric_s2t": "Convert the playing and downloading lyrics to Traditional Chinese", "setting__play_lyric_transition": "Show lyrics translation", + "setting__play_max_output_channel_count": "Output audio using the maximum number of channels the device can handle", "setting__play_mediaDevice": "Audio output", "setting__play_mediaDevice_remove_stop_play": "Pause the song when the current sound output device is changed", "setting__play_mediaDevice_title": "Select a media device for audio output", diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json index 270d0b8837..72df826eee 100644 --- a/src/lang/zh-cn.json +++ b/src/lang/zh-cn.json @@ -513,6 +513,7 @@ "setting__play_lyric_roma": "显示歌词罗马音(如果可用)", "setting__play_lyric_s2t": "将播放与下载的歌词转换为繁体中文", "setting__play_lyric_transition": "显示歌词翻译(如果可用)", + "setting__play_max_output_channel_count": "使用设备能处理的最大声道数输出音频", "setting__play_mediaDevice": "音频输出", "setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲", "setting__play_mediaDevice_title": "选择声音输出的媒体设备", diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json index c5737a3312..99d4404cda 100644 --- a/src/lang/zh-tw.json +++ b/src/lang/zh-tw.json @@ -513,6 +513,7 @@ "setting__play_lyric_roma": "顯示歌詞羅馬音(如果可用)", "setting__play_lyric_s2t": "將播放與下載的歌詞轉換為繁體中文", "setting__play_lyric_transition": "顯示歌詞翻譯(如果可用)", + "setting__play_max_output_channel_count": "使用設備能處理的最大聲道數輸出音頻", "setting__play_mediaDevice": "音訊輸出", "setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出裝置被改變時暫停播放歌曲", "setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備", diff --git a/src/renderer/core/useApp/usePlayer/useMaxOutputChannelCount.ts b/src/renderer/core/useApp/usePlayer/useMaxOutputChannelCount.ts new file mode 100644 index 0000000000..4034752b45 --- /dev/null +++ b/src/renderer/core/useApp/usePlayer/useMaxOutputChannelCount.ts @@ -0,0 +1,14 @@ +import { watch } from '@common/utils/vueTools' +import { setMaxOutputChannelCount } from '@renderer/plugins/player' + +import { appSetting } from '@renderer/store/setting' + +export default () => { + // console.log(appSetting['player.soundEffect.panner.enable']) + setMaxOutputChannelCount(appSetting['player.isMaxOutputChannelCount']) + + watch(() => appSetting['player.isMaxOutputChannelCount'], (val) => { + setMaxOutputChannelCount(val) + }) +} + diff --git a/src/renderer/core/useApp/usePlayer/useMediaDevice.ts b/src/renderer/core/useApp/usePlayer/useMediaDevice.ts index 6523c7461d..27bb29c79a 100644 --- a/src/renderer/core/useApp/usePlayer/useMediaDevice.ts +++ b/src/renderer/core/useApp/usePlayer/useMediaDevice.ts @@ -41,16 +41,16 @@ export default () => { }) } - const handleDeviceChangeStopPlay = (label: string) => { + const handleDeviceChange = (label: string) => { // console.log(device) // console.log(appSetting['player.isMediaDeviceRemovedStopPlay'], isPlay.value, label, prevDeviceLabel) - if ( - appSetting['player.isMediaDeviceRemovedStopPlay'] && - isPlay.value && - label != prevDeviceLabel - ) { - window.lx.isPlayedStop = true - pause() + if (label != prevDeviceLabel) { + window.app_event.playerDeviceChanged() + + if (appSetting['player.isMediaDeviceRemovedStopPlay'] && isPlay.value) { + window.lx.isPlayedStop = true + pause() + } } } @@ -58,7 +58,7 @@ export default () => { const mediaDeviceId = appSetting['player.mediaDeviceId'] const device = await getMediaDevice(mediaDeviceId) - handleDeviceChangeStopPlay(device.label) + handleDeviceChange(device.label) if (device.deviceId == mediaDeviceId) prevDeviceLabel = device.label else void setMediaDevice(device.deviceId, device.label) diff --git a/src/renderer/core/useApp/usePlayer/usePlayer.ts b/src/renderer/core/useApp/usePlayer/usePlayer.ts index d3a69d42c7..4608af552a 100644 --- a/src/renderer/core/useApp/usePlayer/usePlayer.ts +++ b/src/renderer/core/useApp/usePlayer/usePlayer.ts @@ -32,6 +32,7 @@ import { HOTKEY_PLAYER } from '@common/hotKey' import { playNext, pause, playPrev, togglePlay, collectMusic, uncollectMusic, dislikeMusic } from '@renderer/core/player' import usePlaybackRate from './usePlaybackRate' import useSoundEffect from './useSoundEffect' +import useMaxOutputChannelCount from './useMaxOutputChannelCount' import { setPowerSaveBlocker } from '@renderer/core/player/utils' @@ -43,6 +44,7 @@ export default () => { usePlayEvent() useLyric() useVolume() + useMaxOutputChannelCount() useSoundEffect() usePlaybackRate() useWatchList() diff --git a/src/renderer/event/appEvent.ts b/src/renderer/event/appEvent.ts index cca2696ca3..1086c5b8ad 100644 --- a/src/renderer/event/appEvent.ts +++ b/src/renderer/event/appEvent.ts @@ -124,6 +124,10 @@ export class AppEvent extends Event { this.emit('playerWaiting') } + playerDeviceChanged() { + this.emit('playerDeviceChanged') + } + // 激活进度条动画事件 activePlayProgressTransition() { this.emit('activePlayProgressTransition') diff --git a/src/renderer/plugins/player/index.ts b/src/renderer/plugins/player/index.ts index 36dd8b31b1..7ee404faa7 100644 --- a/src/renderer/plugins/player/index.ts +++ b/src/renderer/plugins/player/index.ts @@ -54,6 +54,7 @@ let pitchShifterNode: AudioWorkletNode let pitchShifterNodePitchFactor: AudioParam let pitchShifterNodeLoadStatus: 'none' | 'loading' | 'unconnect' | 'connected' = 'none' let pitchShifterNodeTempValue = 1 +let defaultChannelCount = 2 export const soundR = 0.5 @@ -111,6 +112,7 @@ const initAdvancedAudioFeatures = () => { if (audioContext) return if (!audio) throw new Error('audio not defined') audioContext = new window.AudioContext() + defaultChannelCount = audioContext.destination.channelCount initAnalyser() initBiquadFilter() @@ -134,6 +136,32 @@ export const getAudioContext = () => { return audioContext } +let unsubMediaListChangeEvent: (() => void) | null = null +export const setMaxOutputChannelCount = (enable: boolean) => { + if (enable) { + initAdvancedAudioFeatures() + audioContext.destination.channelCount = audioContext.destination.maxChannelCount + audioContext.destination.channelCountMode = 'max' + // navigator.mediaDevices.addEventListener('devicechange', handleMediaListChange) + if (!unsubMediaListChangeEvent) { + let handleMediaListChange = () => { + setMaxOutputChannelCount(true) + } + window.app_event.on('playerDeviceChanged', handleMediaListChange) + unsubMediaListChangeEvent = () => { + window.app_event.off('playerDeviceChanged', handleMediaListChange) + unsubMediaListChangeEvent = null + } + } + } else { + unsubMediaListChangeEvent?.() + if (audioContext && audioContext.destination.channelCountMode != 'explicit') { + audioContext.destination.channelCount = defaultChannelCount + // audioContext.destination.channelInterpretation + audioContext.destination.channelCountMode = 'explicit' + } + } +} export const getAnalyser = (): AnalyserNode | null => { initAdvancedAudioFeatures() diff --git a/src/renderer/views/Setting/components/SettingPlay.vue b/src/renderer/views/Setting/components/SettingPlay.vue index e6a529c5a6..31b7aefb2d 100644 --- a/src/renderer/views/Setting/components/SettingPlay.vue +++ b/src/renderer/views/Setting/components/SettingPlay.vue @@ -21,6 +21,8 @@ dd base-checkbox(id="setting_player_lyric_play_lxlrc" :model-value="appSetting['player.isPlayLxlrc']" :label="$t('setting__play_lyric_lxlrc')" @update:model-value="updateSetting({'player.isPlayLxlrc': $event})") .gap-top base-checkbox(id="setting_player_showTaskProgess" :model-value="appSetting['player.isShowTaskProgess']" :label="$t('setting__play_task_bar')" @update:model-value="updateSetting({'player.isShowTaskProgess': $event})") + .gap-top + base-checkbox(id="setting_player_isMaxOutputChannelCount" :model-value="appSetting['player.isMaxOutputChannelCount']" :label="$t('setting__play_max_output_channel_count')" @update:model-value="updateSetting({'player.isMaxOutputChannelCount': $event})") .gap-top base-checkbox(id="setting_player_isMediaDeviceRemovedStopPlay" :model-value="appSetting['player.isMediaDeviceRemovedStopPlay']" :label="$t('setting__play_mediaDevice_remove_stop_play')" @update:model-value="updateSetting({'player.isMediaDeviceRemovedStopPlay': $event})")