添加音效用户预设
parent
df58c8eb80
commit
04337ef4b8
|
@ -12,5 +12,6 @@
|
|||
],
|
||||
"i18n-ally.sortKeys": true,
|
||||
"javascript.preferences.importModuleSpecifier": "non-relative",
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"vue.codeActions.enabled": false
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
### 新增
|
||||
|
||||
- 新增音效设置(实验性功能),支持10段均衡器设置、3D立体环绕音效、内置的一些环境混响音效
|
||||
- 新增音效设置(实验性功能),支持10段均衡器设置、内置的一些环境混响音效、3D立体环绕音效
|
||||
|
|
|
@ -10,6 +10,7 @@ export const STORE_NAMES = {
|
|||
LRC_RAW: 'lyrics',
|
||||
LRC_EDITED: 'lyrics_edited',
|
||||
THEME: 'theme',
|
||||
SOUND_EFFECT: 'sound_effect',
|
||||
} as const
|
||||
|
||||
export const APP_EVENT_NAMES = {
|
||||
|
|
|
@ -90,6 +90,10 @@ const modules = {
|
|||
get_other_source_count: 'get_other_source_count',
|
||||
get_data: 'get_data',
|
||||
save_data: 'save_data',
|
||||
get_sound_effect_eq_preset: 'get_sound_effect_eq_preset',
|
||||
save_sound_effect_eq_preset: 'save_sound_effect_eq_preset',
|
||||
get_sound_effect_convolution_preset: 'get_sound_effect_convolution_preset',
|
||||
save_sound_effect_convolution_preset: 'save_sound_effect_convolution_preset',
|
||||
get_hot_key: 'get_hot_key',
|
||||
|
||||
import_user_api: 'import_user_api',
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
declare namespace LX {
|
||||
namespace SoundEffect {
|
||||
interface EQPreset {
|
||||
id: string
|
||||
name: string
|
||||
hz31: number
|
||||
hz62: number
|
||||
hz125: number
|
||||
hz250: number
|
||||
hz500: number
|
||||
hz1000: number
|
||||
hz2000: number
|
||||
hz4000: number
|
||||
hz8000: number
|
||||
hz16000: number
|
||||
}
|
||||
interface ConvolutionPreset {
|
||||
id: string
|
||||
name: string
|
||||
source: string
|
||||
mainGain: number
|
||||
sendGain: number
|
||||
}
|
||||
}
|
||||
}
|
|
@ -228,9 +228,20 @@
|
|||
"player__playing": "Now playing...",
|
||||
"player__prev": "Prev",
|
||||
"player__refresh_url": "Music URL expired, refreshing...",
|
||||
"player__sound_effect": "Sound settings",
|
||||
"player__sound_effect": "Sound settings (experimental)",
|
||||
"player__sound_effect_biquad_filter": "Equalizer",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "Reset equalizer",
|
||||
"player__sound_effect_biquad_filter_preset_classical": "Classical",
|
||||
"player__sound_effect_biquad_filter_preset_dance": "Dance",
|
||||
"player__sound_effect_biquad_filter_preset_electronic": "Electronic",
|
||||
"player__sound_effect_biquad_filter_preset_pop": "Pop",
|
||||
"player__sound_effect_biquad_filter_preset_rock": "Rock",
|
||||
"player__sound_effect_biquad_filter_preset_slow": "Slow",
|
||||
"player__sound_effect_biquad_filter_preset_soft": "Soft",
|
||||
"player__sound_effect_biquad_filter_preset_subwoofer": "Subwoofer",
|
||||
"player__sound_effect_biquad_filter_preset_vocal": "Vocal",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "Reset",
|
||||
"player__sound_effect_biquad_filter_save_btn": "Save preset as",
|
||||
"player__sound_effect_biquad_filter_save_input": "New presets...",
|
||||
"player__sound_effect_convolution": "Ambient reverb sound effect",
|
||||
"player__sound_effect_convolution_file_bright_hall": "Hall",
|
||||
"player__sound_effect_convolution_file_cardiod_35_10_spread": "Rock",
|
||||
|
@ -241,7 +252,7 @@
|
|||
"player__sound_effect_convolution_file_matrix_1": "Matrix",
|
||||
"player__sound_effect_convolution_file_matrix_2": "Matrix 2",
|
||||
"player__sound_effect_convolution_file_s2_r4_bd": "Church",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "Church 2",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "Stereo",
|
||||
"player__sound_effect_convolution_file_spreader25_125ms": "Indoor 2",
|
||||
"player__sound_effect_convolution_file_spreader50_65ms": "Indoor",
|
||||
"player__sound_effect_convolution_file_telephone": "Telephone",
|
||||
|
|
|
@ -228,24 +228,34 @@
|
|||
"player__playing": "播放中...",
|
||||
"player__prev": "上一首",
|
||||
"player__refresh_url": "URL过期,正在刷新URL...",
|
||||
"player__sound_effect": "音效设置",
|
||||
"player__sound_effect": "音效设置(实验性)",
|
||||
"player__sound_effect_biquad_filter": "均衡器",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "重置均衡器",
|
||||
"player__sound_effect_biquad_filter_preset_classical": "古典",
|
||||
"player__sound_effect_biquad_filter_preset_dance": "舞曲",
|
||||
"player__sound_effect_biquad_filter_preset_electronic": "电子乐",
|
||||
"player__sound_effect_biquad_filter_preset_pop": "流行",
|
||||
"player__sound_effect_biquad_filter_preset_rock": "摇滚",
|
||||
"player__sound_effect_biquad_filter_preset_slow": "慢歌",
|
||||
"player__sound_effect_biquad_filter_preset_soft": "柔和",
|
||||
"player__sound_effect_biquad_filter_preset_subwoofer": "重低音",
|
||||
"player__sound_effect_biquad_filter_preset_vocal": "人声",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "重置",
|
||||
"player__sound_effect_biquad_filter_save_btn": "另存预设",
|
||||
"player__sound_effect_biquad_filter_save_input": "新预设...",
|
||||
"player__sound_effect_convolution": "环境混响音效",
|
||||
"player__sound_effect_convolution_file_bright_hall": "大厅",
|
||||
"player__sound_effect_convolution_file_cardiod_35_10_spread": "摇滚",
|
||||
"player__sound_effect_convolution_file_cardiod_35_10_spread": "心形扩散",
|
||||
"player__sound_effect_convolution_file_cinema_diningroom": "电影院",
|
||||
"player__sound_effect_convolution_file_dining_living_true_stereo": "餐厅",
|
||||
"player__sound_effect_convolution_file_feedback_spring": "反馈弹簧",
|
||||
"player__sound_effect_convolution_file_living_bedroom_leveled": "卫生间",
|
||||
"player__sound_effect_convolution_file_matrix_1": "矩阵",
|
||||
"player__sound_effect_convolution_file_matrix_2": "矩阵2",
|
||||
"player__sound_effect_convolution_file_matrix_1": "矩阵混响",
|
||||
"player__sound_effect_convolution_file_matrix_2": "矩阵混响2",
|
||||
"player__sound_effect_convolution_file_s2_r4_bd": "教堂",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "教堂2",
|
||||
"player__sound_effect_convolution_file_spreader25_125ms": "室内2",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "立体声",
|
||||
"player__sound_effect_convolution_file_spreader50_65ms": "室内",
|
||||
"player__sound_effect_convolution_file_telephone": "电话",
|
||||
"player__sound_effect_convolution_file_tim_omni_35_10_magnetic": "摇滚2",
|
||||
"player__sound_effect_convolution_file_tim_omni_35_10_magnetic": "磁性立体声",
|
||||
"player__sound_effect_convolution_main_gain": "原始音频增益",
|
||||
"player__sound_effect_convolution_send_gain": "环境音效增益",
|
||||
"player__sound_effect_panner": "3D立体环绕(需使用耳机)",
|
||||
|
|
|
@ -228,9 +228,20 @@
|
|||
"player__playing": "播放中...",
|
||||
"player__prev": "上一首",
|
||||
"player__refresh_url": "URL過期,正在刷新URL...",
|
||||
"player__sound_effect": "音效設置",
|
||||
"player__sound_effect": "音效設置(實驗性)",
|
||||
"player__sound_effect_biquad_filter": "均衡器",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "重置均衡器",
|
||||
"player__sound_effect_biquad_filter_preset_classical": "古典",
|
||||
"player__sound_effect_biquad_filter_preset_dance": "舞曲",
|
||||
"player__sound_effect_biquad_filter_preset_electronic": "電子樂",
|
||||
"player__sound_effect_biquad_filter_preset_pop": "流行",
|
||||
"player__sound_effect_biquad_filter_preset_rock": "搖滾",
|
||||
"player__sound_effect_biquad_filter_preset_slow": "慢歌",
|
||||
"player__sound_effect_biquad_filter_preset_soft": "柔和",
|
||||
"player__sound_effect_biquad_filter_preset_subwoofer": "重低音",
|
||||
"player__sound_effect_biquad_filter_preset_vocal": "人聲",
|
||||
"player__sound_effect_biquad_filter_reset_btn": "重置",
|
||||
"player__sound_effect_biquad_filter_save_btn": "另存預設",
|
||||
"player__sound_effect_biquad_filter_save_input": "新預設...",
|
||||
"player__sound_effect_convolution": "環境混響音效",
|
||||
"player__sound_effect_convolution_file_bright_hall": "大廳",
|
||||
"player__sound_effect_convolution_file_cardiod_35_10_spread": "搖滾",
|
||||
|
@ -241,7 +252,7 @@
|
|||
"player__sound_effect_convolution_file_matrix_1": "矩陣",
|
||||
"player__sound_effect_convolution_file_matrix_2": "矩陣2",
|
||||
"player__sound_effect_convolution_file_s2_r4_bd": "教堂",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "教堂2",
|
||||
"player__sound_effect_convolution_file_s3_r1_bd": "立體聲",
|
||||
"player__sound_effect_convolution_file_spreader25_125ms": "室內2",
|
||||
"player__sound_effect_convolution_file_spreader50_65ms": "室內",
|
||||
"player__sound_effect_convolution_file_telephone": "電話",
|
||||
|
|
|
@ -9,6 +9,7 @@ import sync from './sync'
|
|||
import data from './data'
|
||||
import music from './music'
|
||||
import download from './download'
|
||||
import soundEffect from './soundEffect'
|
||||
import { sendEvent } from '../main'
|
||||
|
||||
export * from './app'
|
||||
|
@ -33,6 +34,7 @@ export default () => {
|
|||
data()
|
||||
music()
|
||||
download()
|
||||
soundEffect()
|
||||
|
||||
global.lx.event_app.on('updated_config', (keys, setting) => {
|
||||
sendConfigChange(setting)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { STORE_NAMES } from '@common/constants'
|
||||
import { WIN_MAIN_RENDERER_EVENT_NAME } from '@common/ipcNames'
|
||||
import { mainOn, mainHandle } from '@common/mainIpc'
|
||||
import getStore from '@main/utils/store'
|
||||
|
||||
export default () => {
|
||||
mainHandle<LX.SoundEffect.EQPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.get_sound_effect_eq_preset, async() => {
|
||||
return getStore(STORE_NAMES.SOUND_EFFECT).get('eqPreset') as LX.SoundEffect.EQPreset[] | null ?? []
|
||||
})
|
||||
mainOn<LX.SoundEffect.EQPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.save_sound_effect_eq_preset, ({ params }) => {
|
||||
getStore(STORE_NAMES.SOUND_EFFECT).set('eqPreset', params)
|
||||
})
|
||||
|
||||
mainHandle<LX.SoundEffect.ConvolutionPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.get_sound_effect_convolution_preset, async() => {
|
||||
return getStore(STORE_NAMES.SOUND_EFFECT).get('convolutionPreset') as LX.SoundEffect.ConvolutionPreset[] | null ?? []
|
||||
})
|
||||
mainOn<LX.SoundEffect.ConvolutionPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.save_sound_effect_convolution_preset, ({ params }) => {
|
||||
getStore(STORE_NAMES.SOUND_EFFECT).set('convolutionPreset', params)
|
||||
})
|
||||
}
|
|
@ -10,3 +10,4 @@ import '@common/types/player'
|
|||
import '@common/types/desktop_lyric'
|
||||
import '@common/types/theme'
|
||||
import '@common/types/ipc_main'
|
||||
import '@common/types/sound_effect'
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<base-btn min :class="[$style.newPreset, {[$style.editing]: isEditing}]" :aria-label="$t('player__sound_effect_biquad_filter_save_btn')" @click="handleEditing($event)">
|
||||
<svg-icon name="plus" />
|
||||
<base-input ref="input" :class="$style.newPresetInput" :value="newPresetName" :placeholder="$t('player__sound_effect_biquad_filter_save_input')" @keyup.enter="handleSave($event)" @blur="handleSave($event)" />
|
||||
</base-btn>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick } from '@common/utils/vueTools'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { saveUserConvolutionPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const isEditing = ref(false)
|
||||
const input = ref(false)
|
||||
const newPresetName = ref('')
|
||||
|
||||
const handleEditing = () => {
|
||||
if (isEditing.value) return
|
||||
// if (!this.newPresetName) this.newPresetName = this.listName
|
||||
isEditing.value = true
|
||||
nextTick(() => {
|
||||
input.value.$el.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleSave = (event) => {
|
||||
let name = event.target.value.trim()
|
||||
newPresetName.value = event.target.value = ''
|
||||
isEditing.value = false
|
||||
if (!name) return
|
||||
if (name.length > 20) name = name.substring(0, 20)
|
||||
saveUserConvolutionPreset({
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
source: appSetting['player.soundEffect.convolution.fileName'],
|
||||
mainGain: appSetting['player.soundEffect.convolution.mainGain'],
|
||||
sendGain: appSetting['player.soundEffect.convolution.sendGain'],
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.newPreset {
|
||||
position: relative;
|
||||
border: 1px dashed var(--color-primary-font-hover);
|
||||
// background-color: var(--color-main-background);
|
||||
color: var(--color-primary-font-hover);
|
||||
opacity: .7;
|
||||
height: 22px;
|
||||
|
||||
&.editing {
|
||||
opacity: 1;
|
||||
width: 90px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
.newPresetInput {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.svg-icon {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.newPresetInput {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// line-height: 16px;
|
||||
background: none !important;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
padding: 0 3px;
|
||||
border-radius: 0;
|
||||
display: none;
|
||||
&::placeholder {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<base-btn min :class="[$style.newPreset, {[$style.editing]: isEditing}]" :aria-label="$t('player__sound_effect_biquad_filter_save_btn')" @click="handleEditing($event)">
|
||||
<svg-icon name="plus" />
|
||||
<base-input ref="input" :class="$style.newPresetInput" :value="newPresetName" :placeholder="$t('player__sound_effect_biquad_filter_save_input')" @keyup.enter="handleSave($event)" @blur="handleSave($event)" />
|
||||
</base-btn>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick } from '@common/utils/vueTools'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { saveUserEQPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const isEditing = ref(false)
|
||||
const input = ref(false)
|
||||
const newPresetName = ref('')
|
||||
|
||||
const handleEditing = () => {
|
||||
if (isEditing.value) return
|
||||
// if (!this.newPresetName) this.newPresetName = this.listName
|
||||
isEditing.value = true
|
||||
nextTick(() => {
|
||||
input.value.$el.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleSave = (event) => {
|
||||
let name = event.target.value.trim()
|
||||
newPresetName.value = event.target.value = ''
|
||||
isEditing.value = false
|
||||
if (!name) return
|
||||
if (name.length > 20) name = name.substring(0, 20)
|
||||
saveUserEQPreset({
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
hz31: appSetting['player.soundEffect.biquadFilter.hz31'],
|
||||
hz62: appSetting['player.soundEffect.biquadFilter.hz62'],
|
||||
hz125: appSetting['player.soundEffect.biquadFilter.hz125'],
|
||||
hz250: appSetting['player.soundEffect.biquadFilter.hz250'],
|
||||
hz500: appSetting['player.soundEffect.biquadFilter.hz500'],
|
||||
hz1000: appSetting['player.soundEffect.biquadFilter.hz1000'],
|
||||
hz2000: appSetting['player.soundEffect.biquadFilter.hz2000'],
|
||||
hz4000: appSetting['player.soundEffect.biquadFilter.hz4000'],
|
||||
hz8000: appSetting['player.soundEffect.biquadFilter.hz8000'],
|
||||
hz16000: appSetting['player.soundEffect.biquadFilter.hz16000'],
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.newPreset {
|
||||
position: relative;
|
||||
border: 1px dashed var(--color-primary-font-hover);
|
||||
// background-color: var(--color-main-background);
|
||||
color: var(--color-primary-font-hover);
|
||||
opacity: .7;
|
||||
height: 22px;
|
||||
|
||||
&.editing {
|
||||
opacity: 1;
|
||||
width: 90px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
.newPresetInput {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.svg-icon {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.newPresetInput {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// line-height: 16px;
|
||||
background: none !important;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
padding: 0 3px;
|
||||
border-radius: 0;
|
||||
display: none;
|
||||
&::placeholder {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -27,13 +27,19 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['scroll', $style.saveList]">
|
||||
<base-btn v-for="item in userPresetList" :key="item.id" min @click="handleSetPreset(item)" @contextmenu="handleRemovePreset(item.id)">{{ item.name }}</base-btn>
|
||||
<AddConvolutionPresetBtn />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { ref } from '@common/utils/vueTools'
|
||||
import { ref, onMounted } from '@common/utils/vueTools'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { convolutions } from '@renderer/plugins/player'
|
||||
import AddConvolutionPresetBtn from './AddConvolutionPresetBtn'
|
||||
import { getUserConvolutionPresetList, removeUserConvolutionPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const updateConvolution = val => {
|
||||
const target = convolutions.find(c => c.source == val)
|
||||
|
@ -54,6 +60,24 @@ const handleUpdateSendGain = (value) => {
|
|||
updateSetting({ 'player.soundEffect.convolution.sendGain': Math.round(value) })
|
||||
}
|
||||
|
||||
const handleSetPreset = (item) => {
|
||||
updateSetting({
|
||||
'player.soundEffect.convolution.fileName': item.source,
|
||||
'player.soundEffect.convolution.mainGain': item.mainGain,
|
||||
'player.soundEffect.convolution.sendGain': item.sendGain,
|
||||
})
|
||||
}
|
||||
const userPresetList = ref([])
|
||||
const handleRemovePreset = id => {
|
||||
removeUserConvolutionPreset(id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserConvolutionPresetList().then(list => {
|
||||
userPresetList.value = list
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -63,6 +87,7 @@ const handleUpdateSendGain = (value) => {
|
|||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 3px;
|
||||
min-height: 0;
|
||||
}
|
||||
.convolution {
|
||||
display: flex;
|
||||
|
@ -110,4 +135,11 @@ const handleUpdateSendGain = (value) => {
|
|||
color: var(--color-primary-font);
|
||||
}
|
||||
}
|
||||
.saveList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div :class="$style.contnet">
|
||||
<div :class="$style.header">
|
||||
<h3 class="player__sound_effect_title">{{ $t('player__sound_effect_panner') }}</h3>
|
||||
<div class="player__sound_effect_title" :class="$style.header">
|
||||
<h3>{{ $t('player__sound_effect_panner') }}</h3>
|
||||
<base-checkbox
|
||||
id="player__sound_effect_panner_enabled"
|
||||
:class="$style.checkbox"
|
||||
|
@ -11,16 +11,16 @@
|
|||
/>
|
||||
</div>
|
||||
<div :class="$style.eqList">
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_r') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.soundR']" :min="1" :max="30" @change="handleUpdateSoundR" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.soundR'] != 5 }]">{{ appSetting['player.soundEffect.panner.soundR'] }}</span>
|
||||
</div>
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_speed') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.speed']" :min="1" :max="50" @change="handleUpdateSpeed" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.speed'] != 25 }]">{{ appSetting['player.soundEffect.panner.speed'] }}</span>
|
||||
</div>
|
||||
<div :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ $t('player__sound_effect_panner_sound_r') }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.panner.soundR']" :min="1" :max="30" @change="handleUpdateSoundR" />
|
||||
<span :class="[$style.value, { [$style.active]: appSetting['player.soundEffect.panner.soundR'] != 5 }]">{{ appSetting['player.soundEffect.panner.soundR'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -53,9 +53,19 @@ const handleUpdateSpeed = (value) => {
|
|||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
.contnet {
|
||||
padding-top: 15px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 8px;
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border-top: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
|
@ -63,7 +73,7 @@ const handleUpdateSpeed = (value) => {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
// padding-top: 5px;
|
||||
}
|
||||
.eqList {
|
||||
display: flex;
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
<template>
|
||||
<div :class="$style.contnet">
|
||||
<div :class="$style.header">
|
||||
<h3 class="player__sound_effect_title">{{ $t('player__sound_effect_biquad_filter') }}</h3>
|
||||
<div class="player__sound_effect_title" :class="$style.header">
|
||||
<h3>{{ $t('player__sound_effect_biquad_filter') }}</h3>
|
||||
<base-btn min @click="handleReset">{{ $t('player__sound_effect_biquad_filter_reset_btn') }}</base-btn>
|
||||
</div>
|
||||
<div :class="$style.eqList">
|
||||
<div v-for="(v, i) in freqs" :key="v" :class="$style.eqItem">
|
||||
<span :class="$style.label">{{ labels[i] }}</span>
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting[`player.soundEffect.biquadFilter.hz${v}`]" :min="-20" :max="20" @change="handleUpdate(v, $event)" />
|
||||
<base-slider-bar :class="$style.slider" :value="appSetting[`player.soundEffect.biquadFilter.hz${v}`]" :min="-15" :max="15" @change="handleUpdate(v, $event)" />
|
||||
<span :class="$style.value">{{ appSetting[`player.soundEffect.biquadFilter.hz${v}`] }}db</span>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['scroll', $style.saveList]">
|
||||
<!-- <base-btn min @click="handleSetPreset(item)">{{ $t(`player__sound_effect_biquad_filter_preset_slow`) }}</base-btn> -->
|
||||
<base-btn v-for="item in freqsPreset" :key="item.name" min @click="handleSetPreset(item)">{{ $t(`player__sound_effect_biquad_filter_preset_${item.name}`) }}</base-btn>
|
||||
<base-btn v-for="item in userPresetList" :key="item.id" min @click="handleSetPreset(item)" @contextmenu="handleRemovePreset(item.id)">{{ item.name }}</base-btn>
|
||||
<AddEQPresetBtn />
|
||||
</div>
|
||||
<!-- <div :class="$style.footer">
|
||||
<base-btn min @click="handleReset">{{ $t('player__sound_effect_biquad_filter_reset_btn') }}</base-btn>
|
||||
</div> -->
|
||||
|
@ -18,9 +24,11 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { reactive } from '@common/utils/vueTools'
|
||||
import { freqs } from '@renderer/plugins/player'
|
||||
import { onMounted, ref } from '@common/utils/vueTools'
|
||||
import { freqs, freqsPreset } from '@renderer/plugins/player'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import AddEQPresetBtn from './AddEQPresetBtn'
|
||||
import { getUserEQPresetList, removeUserEQPreset } from '@renderer/store/soundEffect'
|
||||
|
||||
const labels = freqs.map(num => num < 1000 ? num : `${num / 1000}k`)
|
||||
|
||||
|
@ -39,6 +47,33 @@ const handleReset = () => {
|
|||
updateSetting(setting)
|
||||
}
|
||||
|
||||
const handleSetPreset = (item) => {
|
||||
updateSetting({
|
||||
'player.soundEffect.biquadFilter.hz31': item.hz31,
|
||||
'player.soundEffect.biquadFilter.hz62': item.hz62,
|
||||
'player.soundEffect.biquadFilter.hz125': item.hz125,
|
||||
'player.soundEffect.biquadFilter.hz250': item.hz250,
|
||||
'player.soundEffect.biquadFilter.hz500': item.hz500,
|
||||
'player.soundEffect.biquadFilter.hz1000': item.hz1000,
|
||||
'player.soundEffect.biquadFilter.hz2000': item.hz2000,
|
||||
'player.soundEffect.biquadFilter.hz4000': item.hz4000,
|
||||
'player.soundEffect.biquadFilter.hz8000': item.hz8000,
|
||||
'player.soundEffect.biquadFilter.hz16000': item.hz16000,
|
||||
})
|
||||
}
|
||||
|
||||
const userPresetList = ref([])
|
||||
|
||||
const handleRemovePreset = id => {
|
||||
removeUserEQPreset(id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserEQPresetList().then(list => {
|
||||
userPresetList.value = list
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
|
@ -47,6 +82,7 @@ const handleReset = () => {
|
|||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
|
@ -54,18 +90,40 @@ const handleReset = () => {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
// padding-top: 5px;
|
||||
}
|
||||
.eqList {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 15px;
|
||||
flex-flow: row wrap;
|
||||
// gap: 15px;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
border-left: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
}
|
||||
.eqItem {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
width: 50%;
|
||||
gap: 8px;
|
||||
margin-bottom: 15px;
|
||||
box-sizing: border-box;
|
||||
&:nth-child(odd) {
|
||||
padding-right: 10px;
|
||||
}
|
||||
&:nth-child(even) {
|
||||
padding-left: 10px;
|
||||
}
|
||||
&:nth-last-child(1), &:nth-last-child(2) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.label {
|
||||
flex: none;
|
||||
|
@ -95,4 +153,11 @@ const handleReset = () => {
|
|||
flex: auto;
|
||||
}
|
||||
|
||||
.saveList {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
<template>
|
||||
<material-popup-btn :class="$style.btnContent">
|
||||
<button :class="$style.btn" :aria-label="$t('player__sound_effect')">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="90%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-tune-variant" />
|
||||
</svg>
|
||||
</button>
|
||||
<template #content>
|
||||
<div :class="$style.content">
|
||||
<button :class="$style.btn" :aria-label="$t('player__sound_effect')" @click="visible = true">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="90%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-tune-variant" />
|
||||
</svg>
|
||||
</button>
|
||||
<material-modal :show="visible" bg-close="bg-close" :teleport="teleport" @close="visible = false">
|
||||
<!-- <main :class="$style.main"> -->
|
||||
<!-- <h2 :class="$style.title">{{ $t('theme_edit_modal__title') }}</h2> -->
|
||||
<div :class="$style.content">
|
||||
<div :class="$style.row">
|
||||
<AudioConvolution />
|
||||
<AudioPanner />
|
||||
</div>
|
||||
<div :class="$style.row">
|
||||
<BiquadFilter />
|
||||
</div>
|
||||
</template>
|
||||
</material-popup-btn>
|
||||
</div>
|
||||
<!-- </main> -->
|
||||
</material-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { reactive, ref } from '@common/utils/vueTools'
|
||||
import { ref } from '@common/utils/vueTools'
|
||||
// import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
||||
// import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
||||
// import { musicInfo, playMusicInfo } from '@renderer/store/player/state'
|
||||
|
@ -27,16 +32,20 @@ import BiquadFilter from './BiquadFilter'
|
|||
import AudioPanner from './AudioPanner'
|
||||
import AudioConvolution from './AudioConvolution'
|
||||
|
||||
defineProps({
|
||||
teleport: {
|
||||
type: String,
|
||||
default: '#root',
|
||||
},
|
||||
})
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
.btnContent {
|
||||
flex: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: relative;
|
||||
// color: var(--color-button-font);
|
||||
|
@ -68,12 +77,40 @@ import AudioConvolution from './AudioConvolution'
|
|||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
.main {
|
||||
min-width: 300px;
|
||||
// max-height: 100%;
|
||||
// overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 5px 3px;
|
||||
gap: 15px;
|
||||
width: 400px;
|
||||
justify-content: center;
|
||||
min-height: 0;
|
||||
}
|
||||
// .title {
|
||||
// flex: none;
|
||||
// font-size: 16px;
|
||||
// color: var(--color-font);
|
||||
// line-height: 1.3;
|
||||
// text-align: center;
|
||||
// padding: 10px;
|
||||
// }
|
||||
.content {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
padding: 0 15px;
|
||||
margin: 15px 0;
|
||||
gap: 30px;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
|
||||
&:before {
|
||||
.mixin-after;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
border-left: 1px dashed var(--color-primary-light-100-alpha-700);
|
||||
}
|
||||
// width: 400px;
|
||||
|
||||
:global {
|
||||
// .player__sound_effect_contnet {
|
||||
|
@ -82,10 +119,16 @@ import AudioConvolution from './AudioConvolution'
|
|||
.player__sound_effect_title {
|
||||
// margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
padding-bottom: 5px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -7,21 +7,32 @@ let analyser: AnalyserNode
|
|||
export const freqs = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000] as const
|
||||
type Freqs = (typeof freqs)[number]
|
||||
let biquads: Map<`hz${Freqs}`, BiquadFilterNode>
|
||||
export const freqsPreset = [
|
||||
{ name: 'pop', hz31: 6, hz62: 5, hz125: -3, hz250: -2, hz500: 5, hz1000: 4, hz2000: -4, hz4000: -3, hz8000: 6, hz16000: 4 },
|
||||
{ name: 'dance', hz31: 4, hz62: 3, hz125: -4, hz250: -6, hz500: 0, hz1000: 0, hz2000: 3, hz4000: 4, hz8000: 4, hz16000: 5 },
|
||||
{ name: 'rock', hz31: 7, hz62: 6, hz125: 2, hz250: 1, hz500: -3, hz1000: -4, hz2000: 2, hz4000: 1, hz8000: 4, hz16000: 5 },
|
||||
{ name: 'classical', hz31: 6, hz62: 7, hz125: 1, hz250: 2, hz500: -1, hz1000: 1, hz2000: -4, hz4000: -6, hz8000: -7, hz16000: -8 },
|
||||
{ name: 'vocal', hz31: -5, hz62: -6, hz125: -4, hz250: -3, hz500: 3, hz1000: 4, hz2000: 5, hz4000: 4, hz8000: -3, hz16000: -3 },
|
||||
{ name: 'slow', hz31: 5, hz62: 4, hz125: 2, hz250: 0, hz500: -2, hz1000: 0, hz2000: 3, hz4000: 6, hz8000: 7, hz16000: 8 },
|
||||
{ name: 'electronic', hz31: 6, hz62: 5, hz125: 0, hz250: -5, hz500: -4, hz1000: 0, hz2000: 6, hz4000: 8, hz8000: 8, hz16000: 7 },
|
||||
{ name: 'subwoofer', hz31: 8, hz62: 7, hz125: 5, hz250: 4, hz500: 0, hz1000: 0, hz2000: 0, hz4000: 0, hz8000: 0, hz16000: 0 },
|
||||
{ name: 'soft', hz31: -5, hz62: -5, hz125: -4, hz250: -4, hz500: 3, hz1000: 2, hz2000: 4, hz4000: 4, hz8000: 0, hz16000: 0 },
|
||||
] as const
|
||||
export const convolutions = [
|
||||
{ name: 'telephone', mainGain: 0.0, sendGain: 3.0, source: 'filter-telephone.wav' }, // 电话
|
||||
{ name: 's2_r4_bd', mainGain: 1.8, sendGain: 0.9, source: 's2_r4_bd.wav' }, // 教堂
|
||||
{ name: 's3_r1_bd', mainGain: 1.8, sendGain: 0.8, source: 's3_r1_bd.wav' },
|
||||
{ name: 'matrix_1', mainGain: 1.5, sendGain: 0.9, source: 'matrix-reverb1.wav' },
|
||||
{ name: 'matrix_2', mainGain: 1.3, sendGain: 1, source: 'matrix-reverb2.wav' },
|
||||
{ name: 'bright_hall', mainGain: 0.8, sendGain: 2.4, source: 'bright-hall.wav' },
|
||||
{ name: 'cinema_diningroom', mainGain: 0.6, sendGain: 2.3, source: 'cinema-diningroom.wav' },
|
||||
{ name: 'dining_living_true_stereo', mainGain: 0.6, sendGain: 1.8, source: 'dining-living-true-stereo.wav' },
|
||||
{ name: 'living_bedroom_leveled', mainGain: 0.6, sendGain: 2.1, source: 'living-bedroom-leveled.wav' },
|
||||
{ name: 'spreader50_65ms', mainGain: 1, sendGain: 2.5, source: 'spreader50-65ms.wav' },
|
||||
{ name: 'spreader25_125ms', mainGain: 1, sendGain: 2.5, source: 'spreader25-125ms.wav' },
|
||||
// { name: 'spreader25_125ms', mainGain: 1, sendGain: 2.5, source: 'spreader25-125ms.wav' },
|
||||
// { name: 'backslap', mainGain: 1.8, sendGain: 0.8, source: 'backslap1.wav' },
|
||||
{ name: 'cardiod_35_10_spread', mainGain: 1.8, sendGain: 0.8, source: 'cardiod-35-10-spread.wav' },
|
||||
{ name: 'tim_omni_35_10_magnetic', mainGain: 1.8, sendGain: 0.8, source: 'tim-omni-35-10-magnetic.wav' },
|
||||
{ name: 's3_r1_bd', mainGain: 1.8, sendGain: 0.8, source: 's3_r1_bd.wav' },
|
||||
{ name: 'matrix_1', mainGain: 1.5, sendGain: 0.9, source: 'matrix-reverb1.wav' },
|
||||
{ name: 'matrix_2', mainGain: 1.3, sendGain: 1, source: 'matrix-reverb2.wav' },
|
||||
{ name: 'cardiod_35_10_spread', mainGain: 1.8, sendGain: 0.6, source: 'cardiod-35-10-spread.wav' },
|
||||
{ name: 'tim_omni_35_10_magnetic', mainGain: 1, sendGain: 0.2, source: 'tim-omni-35-10-magnetic.wav' },
|
||||
// { name: 'spatialized', mainGain: 1.8, sendGain: 0.8, source: 'spatialized8.wav' },
|
||||
// { name: 'zing_long_stereo', mainGain: 0.8, sendGain: 1.8, source: 'zing-long-stereo.wav' },
|
||||
{ name: 'feedback_spring', mainGain: 1.8, sendGain: 0.8, source: 'feedback-spring.wav' },
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import { reactive, toRaw } from '@common/utils/vueTools'
|
||||
import { getUserSoundEffectConvolutionPresetList, getUserSoundEffectEQPresetList, saveUserSoundEffectConvolutionPresetList, saveUserSoundEffectEQPresetList } from '@renderer/utils/ipc'
|
||||
|
||||
let userEqPresetList: LX.SoundEffect.EQPreset[] | null = null
|
||||
|
||||
export const getUserEQPresetList = async() => {
|
||||
if (userEqPresetList == null) {
|
||||
userEqPresetList = reactive(await getUserSoundEffectEQPresetList())
|
||||
}
|
||||
return userEqPresetList
|
||||
}
|
||||
export const saveUserEQPreset = async(preset: LX.SoundEffect.EQPreset) => {
|
||||
if (userEqPresetList == null) {
|
||||
userEqPresetList = reactive(await getUserSoundEffectEQPresetList())
|
||||
}
|
||||
const target = userEqPresetList.find(p => p.id == preset.id)
|
||||
if (target) Object.assign(target, preset)
|
||||
else userEqPresetList.push(preset)
|
||||
saveUserSoundEffectEQPresetList(toRaw(userEqPresetList))
|
||||
}
|
||||
export const removeUserEQPreset = async(id: string) => {
|
||||
if (userEqPresetList == null) {
|
||||
userEqPresetList = reactive(await getUserSoundEffectEQPresetList())
|
||||
}
|
||||
const index = userEqPresetList.findIndex(p => p.id == id)
|
||||
if (index < 0) return
|
||||
userEqPresetList.splice(index, 1)
|
||||
saveUserSoundEffectEQPresetList(toRaw(userEqPresetList))
|
||||
}
|
||||
|
||||
|
||||
let userConvolutionPresetList: LX.SoundEffect.ConvolutionPreset[] | null = null
|
||||
export const getUserConvolutionPresetList = async() => {
|
||||
if (userEqPresetList == null) {
|
||||
userConvolutionPresetList = reactive(await getUserSoundEffectConvolutionPresetList())
|
||||
}
|
||||
return userConvolutionPresetList
|
||||
}
|
||||
export const saveUserConvolutionPreset = async(preset: LX.SoundEffect.ConvolutionPreset) => {
|
||||
if (userConvolutionPresetList == null) {
|
||||
userConvolutionPresetList = reactive(await getUserSoundEffectConvolutionPresetList())
|
||||
}
|
||||
const target = userConvolutionPresetList.find(p => p.id == preset.id)
|
||||
if (target) Object.assign(target, preset)
|
||||
else userConvolutionPresetList.push(preset)
|
||||
saveUserSoundEffectConvolutionPresetList(toRaw(userConvolutionPresetList))
|
||||
}
|
||||
export const removeUserConvolutionPreset = async(id: string) => {
|
||||
if (userConvolutionPresetList == null) {
|
||||
userConvolutionPresetList = reactive(await getUserSoundEffectConvolutionPresetList())
|
||||
}
|
||||
const index = userConvolutionPresetList.findIndex(p => p.id == id)
|
||||
if (index < 0) return
|
||||
userConvolutionPresetList.splice(index, 1)
|
||||
saveUserSoundEffectConvolutionPresetList(toRaw(userConvolutionPresetList))
|
||||
}
|
|
@ -13,3 +13,4 @@ import '@common/types/desktop_lyric'
|
|||
import '@common/types/ipc_renderer'
|
||||
import '@common/types/config_files'
|
||||
import '@common/types/music_metadata'
|
||||
import '@common/types/sound_effect'
|
||||
|
|
|
@ -291,6 +291,22 @@ export const getSystemFonts = async() => {
|
|||
})
|
||||
}
|
||||
|
||||
export const getUserSoundEffectEQPresetList = async() => {
|
||||
return await rendererInvoke<LX.SoundEffect.EQPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.get_sound_effect_eq_preset)
|
||||
}
|
||||
|
||||
export const saveUserSoundEffectEQPresetList = (list: LX.SoundEffect.EQPreset[]) => {
|
||||
rendererSend<LX.SoundEffect.EQPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.save_sound_effect_eq_preset, list)
|
||||
}
|
||||
|
||||
export const getUserSoundEffectConvolutionPresetList = async() => {
|
||||
return await rendererInvoke<LX.SoundEffect.ConvolutionPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.get_sound_effect_convolution_preset)
|
||||
}
|
||||
|
||||
export const saveUserSoundEffectConvolutionPresetList = (list: LX.SoundEffect.ConvolutionPreset[]) => {
|
||||
rendererSend<LX.SoundEffect.ConvolutionPreset[]>(WIN_MAIN_RENDERER_EVENT_NAME.save_sound_effect_convolution_preset, list)
|
||||
}
|
||||
|
||||
|
||||
export const allHotKeys = markRaw({
|
||||
local: [
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue