添加更多环境混响音效

pull/1395/head
lyswhut 2023-05-04 19:14:00 +08:00
parent 9dc927b50b
commit 735f629ca1
23 changed files with 201 additions and 93 deletions

View File

@ -1,3 +1,3 @@
### 新增
- 新增音效设置实验性功能支持16段均衡器设置、3D立体环绕音效、内置的几个环境音效
- 新增音效设置实验性功能支持10段均衡器设置、3D立体环绕音效、内置的一些环境混响音效

View File

@ -41,6 +41,8 @@ const defaultSetting: LX.AppSetting = {
'player.waitPlayEndStopTime': '',
'player.autoSkipOnError': true,
'player.soundEffect.convolution.fileName': '',
'player.soundEffect.convolution.mainGain': 10,
'player.soundEffect.convolution.sendGain': 0,
'player.soundEffect.biquadFilter.hz31': 0,
'player.soundEffect.biquadFilter.hz62': 0,
'player.soundEffect.biquadFilter.hz125': 0,

View File

@ -168,6 +168,16 @@ declare global {
*/
'player.soundEffect.convolution.fileName': string | null
/**
*
*/
'player.soundEffect.convolution.mainGain': number
/**
*
*/
'player.soundEffect.convolution.sendGain': number
/**
* 31hz
*/

View File

@ -230,13 +230,23 @@
"player__sound_effect": "Sound settings",
"player__sound_effect_biquad_filter": "Equalizer",
"player__sound_effect_biquad_filter_reset_btn": "Reset equalizer",
"player__sound_effect_convolution": "Ambient sound",
"player__sound_effect_convolution_church": "Church",
"player__sound_effect_convolution_feedback_spring": "Cave",
"player__sound_effect_convolution_kitchen": "Kitchen",
"player__sound_effect_convolution_spreader": "Indoor",
"player__sound_effect_convolution_telephone": "Telephone",
"player__sound_effect_convolution_wc": "Bathroom",
"player__sound_effect_convolution": "Ambient reverb sound effect",
"player__sound_effect_convolution_file_telephone": "Telephone",
"player__sound_effect_convolution_file_s2_r4_bd": "Church",
"player__sound_effect_convolution_file_s3_r1_bd": "Church 2",
"player__sound_effect_convolution_file_matrix_1": "Matrix",
"player__sound_effect_convolution_file_matrix_2": "Matrix 2",
"player__sound_effect_convolution_file_bright_hall": "Hall",
"player__sound_effect_convolution_file_cinema_diningroom": "Cinema",
"player__sound_effect_convolution_file_dining_living_true_stereo": "Dining Room",
"player__sound_effect_convolution_file_living_bedroom_leveled": "Bathroom",
"player__sound_effect_convolution_file_spreader50_65ms": "Indoor",
"player__sound_effect_convolution_file_spreader25_125ms": "Indoor 2",
"player__sound_effect_convolution_file_cardiod_35_10_spread": "Rock",
"player__sound_effect_convolution_file_tim_omni_35_10_magnetic": "Rock 2",
"player__sound_effect_convolution_file_feedback_spring": "Feedback Spring",
"player__sound_effect_convolution_main_gain": "Original Audio Gain",
"player__sound_effect_convolution_send_gain": "Ambient Sound Effect Gain",
"player__sound_effect_panner": "3D stereo surround (need to use headphones)",
"player__sound_effect_panner_enabled": "enable",
"player__sound_effect_panner_sound_r": "Sound distance",
@ -464,7 +474,7 @@
"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",
"setting__play_media_device_error_tip": "This function conflicts with the audio visualization function. You have enabled audio visualization when you started the software this time. This setting is temporarily unavailable. Please restart the software and then modify this setting.",
"setting__play_media_device_error_tip": "This function conflicts with advanced audio functions (audio visualization, sound effect settings). These functions have been enabled when you start the software this time. This setting is not available for now. Please close these functions and restart the software before modifying this setting.",
"setting__play_media_device_tip": "This feature conflicts with Audio Visualization, both cannot be enabled at the same time, would you like to turn Audio Visualization off and apply the selected audio output settings?",
"setting__play_quality": "Priority playback of 320K quality songs (if available)",
"setting__play_save_play_time": "Remember playback progress",

View File

@ -72,7 +72,7 @@ const createI18n = (): I18n => {
return message
},
getMessage(key: keyof Message, val?: TranslateValues): string {
let targetMessage = this.message[key] ?? this.messages[this.fallbackLocale][key] ?? ''
let targetMessage = this.message[key] ?? this.messages[this.fallbackLocale][key] ?? key
return val ? this.fillMessage(targetMessage, val) : targetMessage
},
t(key: keyof Message, val?: TranslateValues): string {

View File

@ -230,13 +230,23 @@
"player__sound_effect": "音效设置",
"player__sound_effect_biquad_filter": "均衡器",
"player__sound_effect_biquad_filter_reset_btn": "重置均衡器",
"player__sound_effect_convolution": "环境音效",
"player__sound_effect_convolution_church": "教堂",
"player__sound_effect_convolution_feedback_spring": "山洞",
"player__sound_effect_convolution_kitchen": "厨房",
"player__sound_effect_convolution_spreader": "室内",
"player__sound_effect_convolution_telephone": "电话",
"player__sound_effect_convolution_wc": "厕所",
"player__sound_effect_convolution": "环境混响音效",
"player__sound_effect_convolution_file_telephone": "电话",
"player__sound_effect_convolution_file_s2_r4_bd": "教堂",
"player__sound_effect_convolution_file_s3_r1_bd": "教堂2",
"player__sound_effect_convolution_file_matrix_1": "矩阵",
"player__sound_effect_convolution_file_matrix_2": "矩阵2",
"player__sound_effect_convolution_file_bright_hall": "大厅",
"player__sound_effect_convolution_file_cinema_diningroom": "电影院",
"player__sound_effect_convolution_file_dining_living_true_stereo": "餐厅",
"player__sound_effect_convolution_file_living_bedroom_leveled": "卫生间",
"player__sound_effect_convolution_file_spreader50_65ms": "室内",
"player__sound_effect_convolution_file_spreader25_125ms": "室内2",
"player__sound_effect_convolution_file_cardiod_35_10_spread": "摇滚",
"player__sound_effect_convolution_file_tim_omni_35_10_magnetic": "摇滚2",
"player__sound_effect_convolution_file_feedback_spring": "反馈弹簧",
"player__sound_effect_convolution_main_gain": "原始音频增益",
"player__sound_effect_convolution_send_gain": "环境音效增益",
"player__sound_effect_panner": "3D立体环绕需使用耳机",
"player__sound_effect_panner_enabled": "启用",
"player__sound_effect_panner_sound_r": "声音距离",
@ -464,7 +474,7 @@
"setting__play_mediaDevice": "音频输出",
"setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲",
"setting__play_mediaDevice_title": "选择声音输出的媒体设备",
"setting__play_media_device_error_tip": "此功能与音频可视化功能冲突,你本次启动软件时已启用过音频可视化,此设置暂不可用,请 重启 软件后,再来修改此设置。",
"setting__play_media_device_error_tip": "此功能与高级音频功能(音频可视化、音效设置)冲突,你本次启动软件时已启用这些功能,此设置暂不可用,请 关闭这些功能 并 重启 软件后,再来修改此设置。",
"setting__play_media_device_tip": "此功能与音频可视化功能冲突,两者无法同时启用,是否将音频可视化关闭 并 应用所选音频输出设置?",
"setting__play_quality": "优先播放320K品质的歌曲如果可用",
"setting__play_save_play_time": "记住播放进度",

View File

@ -230,13 +230,23 @@
"player__sound_effect": "音效設置",
"player__sound_effect_biquad_filter": "均衡器",
"player__sound_effect_biquad_filter_reset_btn": "重置均衡器",
"player__sound_effect_convolution": "環境音效",
"player__sound_effect_convolution_church": "教堂",
"player__sound_effect_convolution_feedback_spring": "山洞",
"player__sound_effect_convolution_kitchen": "廚房",
"player__sound_effect_convolution_spreader": "室內",
"player__sound_effect_convolution_telephone": "電話",
"player__sound_effect_convolution_wc": "廁所",
"player__sound_effect_convolution": "環境混響音效",
"player__sound_effect_convolution_file_telephone": "電話",
"player__sound_effect_convolution_file_s2_r4_bd": "教堂",
"player__sound_effect_convolution_file_s3_r1_bd": "教堂2",
"player__sound_effect_convolution_file_matrix_1": "矩陣",
"player__sound_effect_convolution_file_matrix_2": "矩陣2",
"player__sound_effect_convolution_file_bright_hall": "大廳",
"player__sound_effect_convolution_file_cinema_diningroom": "電影院",
"player__sound_effect_convolution_file_dining_living_true_stereo": "餐廳",
"player__sound_effect_convolution_file_living_bedroom_leveled": "衛生間",
"player__sound_effect_convolution_file_spreader50_65ms": "室內",
"player__sound_effect_convolution_file_spreader25_125ms": "室內2",
"player__sound_effect_convolution_file_cardiod_35_10_spread": "搖滾",
"player__sound_effect_convolution_file_tim_omni_35_10_magnetic": "搖滾2",
"player__sound_effect_convolution_file_feedback_spring": "反饋彈簧",
"player__sound_effect_convolution_main_gain": "原始音頻增益",
"player__sound_effect_convolution_send_gain": "環境音效增益",
"player__sound_effect_panner": "3D立體環繞需使用耳機",
"player__sound_effect_panner_enabled": "啟用",
"player__sound_effect_panner_sound_r": "聲音距離",
@ -464,7 +474,7 @@
"setting__play_mediaDevice": "音頻輸出",
"setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出設備被改變時暫停播放歌曲",
"setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備",
"setting__play_media_device_error_tip": "此功能與音頻可視化功能衝突,你本次啟動軟件時已啟用過音頻可視化,此設置暫不可用,請 重啟 軟件後,再來修改此設置。",
"setting__play_media_device_error_tip": "此功能與高級音頻功能(音頻可視化、音效設置)衝突,你本次啟動軟件時已啟用這些功能,此設置暫不可用,請 關閉這些功能 並 重啟 軟件後,再來修改此設置。",
"setting__play_media_device_tip": "此功能與音頻可視化功能衝突,兩者無法同時啟用,是否將音頻可視化關閉 並 應用所選音頻輸出設置?",
"setting__play_quality": "優先播放320K品質的歌曲如果可用",
"setting__play_save_play_time": "記住播放進度",

View File

@ -56,6 +56,7 @@ const popupStyle = reactive({
const arrowHeight = 9
const arrowWidth = 8
const sidePadding = 50
watch(() => props.visible, (visible) => {
if (!visible || !dom_content.value || !props.btnEl) return
@ -63,24 +64,24 @@ watch(() => props.visible, (visible) => {
const maxHeight = document.body.clientHeight
const elTop = rect.top - window.lx.rootOffset
const bottomTopVal = elTop + rect.height
const contentHeight = dom_content.value.scrollHeight + arrowHeight + 10
const contentHeight = dom_content.value.scrollHeight + arrowHeight + sidePadding
if (bottomTopVal + contentHeight < maxHeight || (contentHeight > elTop && elTop <= maxHeight - bottomTopVal)) {
isShowTop.value = false
popupStyle.top = bottomTopVal + arrowHeight + 'px'
popupStyle.maxHeight = maxHeight - bottomTopVal - arrowHeight - 10 + 'px'
popupStyle.maxHeight = maxHeight - bottomTopVal - arrowHeight - sidePadding + 'px'
} else {
isShowTop.value = true
let maxContentHeight = elTop - arrowHeight - 10
popupStyle.top = (elTop - (elTop < contentHeight ? elTop : contentHeight) + 10) + 'px'
let maxContentHeight = elTop - arrowHeight - sidePadding
popupStyle.top = (elTop - (elTop < contentHeight ? elTop : contentHeight) + sidePadding) + 'px'
popupStyle.maxHeight = maxContentHeight + 'px'
}
const maxWidth = document.body.clientWidth - 20
let center = dom_content.value.clientWidth / 2
let left = rect.left + rect.width / 2 - window.lx.rootOffset - center
if (left < 10) {
center -= 10 - left
left = 10
if (left < sidePadding) {
center -= sidePadding - left
left = sidePadding
} else if (left + dom_content.value.clientWidth > maxWidth) {
let newLeft = maxWidth - dom_content.value.clientWidth
center = center + left - newLeft

View File

@ -1,17 +1,31 @@
<template>
<div :class="$style.contnet">
<h3 class="player__sound_effect_title">{{ $t('player__sound_effect_convolution') }}</h3>
<div :class="$style.convolutionList">
<base-checkbox
v-for="item in convolutions"
:id="`player__convolution_${item.name}`"
:key="item.name"
:class="$style.checkbox"
:model-value="appSetting['player.soundEffect.convolution.fileName']"
:label="$t(`player__sound_effect_convolution_${item.name}`)"
:value="item.source"
@update:model-value="updateConvolution($event)"
/>
<div :class="$style.convolution">
<div :class="$style.convolutionList">
<base-checkbox
v-for="item in convolutions"
:id="`player__convolution_${item.name}`"
:key="item.name"
:class="$style.checkbox"
:model-value="appSetting['player.soundEffect.convolution.fileName']"
:label="$t(`player__sound_effect_convolution_file_${item.name}`)"
:value="item.source"
@update:model-value="updateConvolution($event)"
/>
</div>
<div :class="$style.sliderList">
<div :class="$style.sliderItem">
<span :class="$style.label">{{ $t('player__sound_effect_convolution_main_gain') }}</span>
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.convolution.mainGain']" :min="0" :max="50" @change="handleUpdateMainGain" />
<span :class="[$style.value]">{{ appSetting['player.soundEffect.convolution.mainGain'] * 10 }}%</span>
</div>
<div :class="$style.sliderItem">
<span :class="$style.label">{{ $t('player__sound_effect_convolution_send_gain') }}</span>
<base-slider-bar :class="$style.slider" :value="appSetting['player.soundEffect.convolution.sendGain']" :min="0" :max="50" @change="handleUpdateSendGain" />
<span :class="[$style.value]">{{ appSetting['player.soundEffect.convolution.sendGain'] * 10 }}%</span>
</div>
</div>
</div>
</div>
</template>
@ -22,10 +36,25 @@ import { appSetting, updateSetting } from '@renderer/store/setting'
import { convolutions } from '@renderer/plugins/player'
const updateConvolution = val => {
console.log(val)
updateSetting({ 'player.soundEffect.convolution.fileName': val })
const target = convolutions.find(c => c.source == val)
const setting = {
'player.soundEffect.convolution.fileName': val,
}
if (target) {
setting['player.soundEffect.convolution.mainGain'] = target.mainGain * 10
setting['player.soundEffect.convolution.sendGain'] = target.sendGain * 10
}
updateSetting(setting)
}
const handleUpdateMainGain = (value) => {
updateSetting({ 'player.soundEffect.convolution.mainGain': Math.round(value) })
}
const handleUpdateSendGain = (value) => {
updateSetting({ 'player.soundEffect.convolution.sendGain': Math.round(value) })
}
</script>
<style lang="less" module>
@ -35,6 +64,12 @@ const updateConvolution = val => {
flex-flow: column nowrap;
gap: 3px;
}
.convolution {
display: flex;
flex-flow: column wrap;
gap: 15px;
width: 100%;
}
.convolutionList {
display: flex;
flex-flow: row wrap;
@ -45,4 +80,34 @@ const updateConvolution = val => {
margin-right: 10px;
font-size: 12px;
}
.sliderList {
display: flex;
flex-flow: column nowrap;
gap: 15px;
width: 100%;
}
.sliderItem {
display: flex;
flex-flow: row nowrap;
gap: 8px;
}
.slider {
flex: auto;
}
.label {
flex: none;
// width: 50px;
font-size: 12px;
}
.value {
flex: none;
width: 40px;
font-size: 12px;
text-align: center;
&.active {
color: var(--color-primary-font);
}
}
</style>

View File

@ -1,7 +1,6 @@
import { watch } from '@common/utils/vueTools'
import {
freqs,
convolutions,
getAudioContext,
getBiquadFilter,
setConvolver,
@ -9,6 +8,8 @@ import {
setPannerSpeed,
startPanner,
stopPanner,
setConvolverMainGain,
setConvolverSendGain,
} from '@renderer/plugins/player'
import { appSetting } from '@renderer/store/setting'
@ -62,8 +63,7 @@ export default () => {
}
if (appSetting['player.soundEffect.convolution.fileName']) {
void loadBuffer(appSetting['player.soundEffect.convolution.fileName']).then((buffer) => {
const target = convolutions.find(c => c.source == appSetting['player.soundEffect.convolution.fileName'])
setConvolver(buffer, target!.sendGain, target!.mainGain)
setConvolver(buffer, appSetting['player.soundEffect.convolution.mainGain'] / 10, appSetting['player.soundEffect.convolution.sendGain'] / 10)
})
}
@ -85,14 +85,19 @@ export default () => {
setTimeout(() => {
if (fileName) {
void loadBuffer(fileName).then((buffer) => {
const target = convolutions.find(c => c.source == fileName)
setConvolver(buffer, target!.sendGain, target!.mainGain)
setConvolver(buffer, appSetting['player.soundEffect.convolution.mainGain'] / 10, appSetting['player.soundEffect.convolution.sendGain'] / 10)
})
} else {
setConvolver(null, 0, 0)
}
})
})
watch(() => appSetting['player.soundEffect.convolution.mainGain'], (mainGain) => {
setConvolverMainGain(mainGain / 10)
})
watch(() => appSetting['player.soundEffect.convolution.sendGain'], (sendGain) => {
setConvolverSendGain(sendGain / 10)
})
watch(() => appSetting['player.soundEffect.biquadFilter.hz31'], (hz31) => {
const bfs = getBiquadFilter()
bfs.get('hz31')!.gain.value = hz31

View File

@ -8,42 +8,24 @@ export const freqs = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000] as c
type Freqs = (typeof freqs)[number]
let biquads: Map<`hz${Freqs}`, BiquadFilterNode>
export const convolutions = [
{
name: 'telephone', // 电话
mainGain: 0.0,
sendGain: 3.0,
source: 'filter-telephone.wav',
},
{
name: 'spreader', // 室内
mainGain: 1.0,
sendGain: 2.5,
source: 'spreader50-65ms.wav',
},
{
name: 'feedback_spring', // 山洞
mainGain: 0.0,
sendGain: 2.4,
source: 'feedback-spring.wav',
},
{
name: 'church', // 教堂
mainGain: 1.8,
sendGain: 0.9,
source: 's2_r4_bd.wav',
},
{
name: 'kitchen', // 厨房
mainGain: 0.6,
sendGain: 3.0,
source: 'kitchen-true-stereo.wav',
},
{
name: 'wc', // 厕所
mainGain: 0.6,
sendGain: 2.1,
source: 'living-bedroom-leveled.wav',
},
{ 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: '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: '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' },
// { name: 'tim_omni_rear_blend', mainGain: 1.8, sendGain: 0.8, source: 'tim-omni-rear-blend.wav' },
] as const
let convolver: ConvolverNode
let convolverSourceGainNode: GainNode
@ -147,18 +129,31 @@ export const getBiquadFilter = () => {
}
// let isConvolverConnected = false
export const setConvolver = (buffer: AudioBuffer | null, sendGain: number, mainGain: number) => {
export const setConvolver = (buffer: AudioBuffer | null, mainGain: number, sendGain: number) => {
initAdvancedAudioFeatures()
convolver.buffer = buffer
// console.log(mainGain, sendGain)
if (buffer) {
convolverOutputGainNode.gain.value = sendGain
convolverSourceGainNode.gain.value = mainGain
convolverOutputGainNode.gain.value = sendGain
} else {
convolverOutputGainNode.gain.value = 0
convolverSourceGainNode.gain.value = 1
convolverOutputGainNode.gain.value = 0
}
}
export const setConvolverMainGain = (gain: number) => {
if (convolverSourceGainNode.gain.value == gain) return
// console.log(gain)
convolverSourceGainNode.gain.value = gain
}
export const setConvolverSendGain = (gain: number) => {
if (convolverOutputGainNode.gain.value == gain) return
// console.log(gain)
convolverOutputGainNode.gain.value = gain
}
let pannerInfo = {
x: 0,
y: 0,
@ -210,7 +205,7 @@ export const startPanner = () => {
}, pannerInfo.speed * 10)
}
export const hasInitedAnalyser = (): boolean => audioContext != null
export const hasInitedAdvancedAudioFeatures = (): boolean => audioContext != null
export const setResource = (src: string) => {
if (audio) audio.src = src

View File

@ -29,7 +29,7 @@ dd(:aria-label="$t('setting__play_mediaDevice_title')")
<script>
import { ref, onBeforeUnmount, watch } from '@common/utils/vueTools'
import { hasInitedAnalyser } from '@renderer/plugins/player'
import { hasInitedAdvancedAudioFeatures } from '@renderer/plugins/player'
import { dialog } from '@renderer/plugins/Dialog'
import { useI18n } from '@renderer/plugins/i18n'
import { appSetting, updateSetting } from '@renderer/store/setting'
@ -56,7 +56,7 @@ export default {
const mediaDeviceId = ref(appSetting['player.mediaDeviceId'])
const handleMediaDeviceIdChnage = async() => {
if (hasInitedAnalyser()) {
if (hasInitedAdvancedAudioFeatures()) {
await dialog({
message: t('setting__play_media_device_error_tip'),
confirmButtonText: t('alert_button_text'),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.