添加音调升降调节

This commit is contained in:
lyswhut
2023-05-31 21:40:25 +08:00
parent 677c3f16e4
commit 40997c34ff
21 changed files with 1435 additions and 20 deletions
@@ -0,0 +1,90 @@
<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 { saveUserPitchShifterPreset } 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)
saveUserPitchShifterPreset({
id: Date.now().toString(),
name,
playbackRate: appSetting['player.soundEffect.pitchShifter.playbackRate'],
})
}
</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,7 +27,7 @@
</div>
</div>
</div>
<div :class="['scroll', $style.saveList]">
<div :class="$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 v-if="userPresetList.length < 31" />
</div>
@@ -88,6 +88,7 @@ onMounted(() => {
flex-flow: column nowrap;
gap: 3px;
min-height: 0;
flex: none;
}
.convolution {
display: flex;
@@ -11,7 +11,7 @@
<span :class="$style.value">{{ appSetting[`player.soundEffect.biquadFilter.hz${v}`] }}db</span>
</div>
</div>
<div :class="['scroll', $style.saveList]">
<div :class="$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>
@@ -83,6 +83,7 @@ onMounted(() => {
flex-flow: column nowrap;
gap: 8px;
min-height: 0;
flex: none;
}
.header {
display: flex;
@@ -0,0 +1,149 @@
<template>
<div :class="$style.contnet">
<div class="player__sound_effect_title" :class="$style.header">
<h3>{{ $t('player__sound_effect_pitch_shifter') }}</h3>
<base-btn min @click="handleSetPreset(1)">{{ $t('player__sound_effect_pitch_shifter_reset_btn') }}</base-btn>
</div>
<div :class="$style.eqList">
<div :class="$style.eqItem">
<span :class="$style.label">{{ playbackRate.toFixed(2) }}x</span>
<base-slider-bar :class="$style.slider" :value="playbackRate * 100" :min="50" :max="150" @change="handleUpdatePlaybackRate" />
</div>
</div>
<div :class="$style.saveList">
<base-btn v-for="num in semitones" :key="num" min @click="handleSetSemitones(num)">{{ $t(`player__sound_effect_pitch_shifter_preset_semitones`, { num: num > 0 ? `+${num}` : num }) }}</base-btn>
<base-btn v-for="item in userPresetList" :key="item.id" min @click="handleSetPreset(item.playbackRate)" @contextmenu="handleRemovePreset(item.id)">{{ item.name }}</base-btn>
<AddPitchShifterPresetBtn v-if="userPresetList.length < 31" />
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from '@common/utils/vueTools'
import { appSetting, updateSetting } from '@renderer/store/setting'
import AddPitchShifterPresetBtn from './AddPitchShifterPresetBtn.vue'
import { getUserPitchShifterPresetList, removeUserPitchShifterPreset } from '@renderer/store/soundEffect'
import { semitones } from '@renderer/plugins/player'
// const setting = reactive({
// enabled: false,
// soundR: 5,
// speed: 25,
// })
const playbackRate = computed(() => appSetting['player.soundEffect.pitchShifter.playbackRate'])
const handleSetPreset = (value) => {
updateSetting({ 'player.soundEffect.pitchShifter.playbackRate': value })
}
const handleSetSemitones = (value) => {
// https://zpl.fi/pitch-shifting-in-web-audio-api/
handleSetPreset(2 ** (value / 12))
}
const handleUpdatePlaybackRate = (value) => {
value = parseFloat((Math.round(value) / 100).toFixed(2))
handleSetPreset(value)
}
const userPresetList = ref([])
const handleRemovePreset = id => {
removeUserPitchShifterPreset(id)
}
onMounted(() => {
getUserPitchShifterPresetList().then(list => {
userPresetList.value = list
})
})
</script>
<style lang="less" module>
@import '@renderer/assets/styles/layout.less';
.contnet {
padding-top: 15px;
position: relative;
display: flex;
flex-flow: column nowrap;
gap: 8px;
min-height: 0;
flex: none;
&: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;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding-bottom: 5px;
// padding-top: 5px;
}
.eqList {
display: flex;
flex-flow: column nowrap;
gap: 15px;
width: 100%;
}
.eqItem {
display: flex;
flex-flow: row nowrap;
gap: 8px;
}
.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);
}
}
.footer {
display: flex;
flex-flow: row nowrap;
// justify-content: space-between;
justify-content: center;
align-items: center;
// font-size: 13px;
span {
line-height: 1;
}
}
.slider {
flex: auto;
}
.checkbox {
margin-right: 10px;
font-size: 13px;
}
.saveList {
display: flex;
flex-flow: row wrap;
margin-top: 10px;
gap: 10px;
}
</style>
@@ -8,12 +8,13 @@
<!-- <main :class="$style.main"> -->
<!-- <h2 :class="$style.title">{{ $t('theme_edit_modal__title') }}</h2> -->
<div :class="$style.content">
<div :class="$style.row">
<div :class="['scroll', $style.row]">
<AudioConvolution />
<AudioPanner />
<PitchShifter />
</div>
<div :class="$style.row">
<div :class="['scroll', $style.row]">
<BiquadFilter />
<AudioPanner />
</div>
</div>
<!-- </main> -->
@@ -31,6 +32,7 @@ import { ref } from '@common/utils/vueTools'
import BiquadFilter from './BiquadFilter'
import AudioPanner from './AudioPanner'
import AudioConvolution from './AudioConvolution'
import PitchShifter from './PitchShifter.vue'
defineProps({
teleport: {
@@ -97,9 +99,9 @@ const visible = ref(false)
.content {
display: flex;
flex-flow: row nowrap;
padding: 0 15px;
padding: 0 5px;
margin: 15px 0;
gap: 30px;
gap: 10px;
position: relative;
min-height: 0;
@@ -129,6 +131,7 @@ const visible = ref(false)
display: flex;
gap: 15px;
flex-flow: column nowrap;
padding: 0 10px;
}
</style>