174 lines
5.6 KiB
Vue
174 lines
5.6 KiB
Vue
<template>
|
|
<div>
|
|
<div v-if="error" class="error-message">
|
|
{{ error }}
|
|
</div>
|
|
<AudioFileSelector @file-selected="onFileSelected" />
|
|
<button @click="startAll">Start all Noises</button>
|
|
<!-- Ramp Time Control -->
|
|
</div>
|
|
<div class="gain-controller">
|
|
<div v-for="frequency in frequencies" :key="frequency" class="frequency-control">
|
|
<RNBOControlValue
|
|
:v-if="!isNaN(frequency)"
|
|
:center-frequency="frequency"
|
|
:status="audioSources[frequency] != null"
|
|
@control-value-change="(value) => handleValueChange(value.frequency, value.value)"
|
|
/>
|
|
<div :v-if="audioSources[frequency] != undefined && audioSources[frequency] != ''">
|
|
<AudioTagWebAudio
|
|
:ref="el => { if (el) audioElements[frequency] = el as any}"
|
|
:src="audioSources[frequency] || ''"
|
|
:volume="Number(currentVolumes[frequency])"
|
|
/>
|
|
</div>
|
|
<div>
|
|
Frequency: {{ frequency }}Hz
|
|
<br>Gain Value (dB): {{ gainValuesDB[frequency] }}
|
|
<br>Normalized: {{ normalizedVolumes[frequency] }}
|
|
<br>Volume: {{ currentVolumes[frequency] }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, ref, onUnmounted, reactive } from 'vue'
|
|
import AudioFileSelector from '../AudioFileSelector.vue'
|
|
import AudioTagWebAudio from './AudioTagWebAudio.vue'
|
|
import RNBOControlValue from './tests/ControlValues/RNBOControlValue.vue'
|
|
import { calculateNormalizedVolume } from '~/lib/AudioFunctions'
|
|
import { useAudioStore } from '~/stores/audio'
|
|
import tracksConfig from '~/tracks.config'
|
|
|
|
export default defineComponent({
|
|
name: 'GainController',
|
|
components: {
|
|
RNBOControlValue,
|
|
AudioTagWebAudio,
|
|
AudioFileSelector
|
|
},
|
|
setup () {
|
|
const logger = useNuxtApp().$logger as any
|
|
logger.info('GainController setup')
|
|
const audioStore = useAudioStore()
|
|
logger.info('Got audioStore', audioStore)
|
|
const audioSrc = ref(window.location.origin + '/sounds/lagoon.ogg')
|
|
const rampTime = ref(25000)
|
|
logger.info('Set rampTime', 25000)
|
|
const frequencies = ref([63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000])
|
|
logger.info('Set frequencies', { frequencies })
|
|
const error = ref<string | null>(null)
|
|
|
|
const gainValuesDB = reactive<Record<number, number>>({})
|
|
const currentVolumes = reactive<Record<number, number>>({})
|
|
const audioSources = reactive<Record<number, string>>({})
|
|
const normalizedVolumes = reactive<Record<number, number>>({})
|
|
const audioElements = reactive<Record<number, InstanceType<typeof AudioTagWebAudio>>>({})
|
|
|
|
const rampIntervals: Record<number, ReturnType<typeof setInterval> | null> = {}
|
|
|
|
const onFileSelected = (file: string) => {
|
|
const fullPath = new URL(file, window.location.origin).toString()
|
|
audioSrc.value = fullPath
|
|
logger.info('User hat ein File ausgewählt ' + file)
|
|
useNuxtApp().$logger.log({ audioElements })
|
|
setTimeout(() => {
|
|
audioStore.setPlaying(true)
|
|
}, 250)
|
|
}
|
|
|
|
const startAll = () => {
|
|
const audioPaths = [tracksConfig['63_src'], tracksConfig['125_src'], tracksConfig['250_src'], tracksConfig['500_src'],
|
|
tracksConfig['1000_src'], tracksConfig['2000_src'], tracksConfig['4000_src'], tracksConfig['8000_src'], tracksConfig['16000_src']]
|
|
const recordsCount = Object.keys(audioElements).length
|
|
if (recordsCount > 0) {
|
|
for (let recordsCounter = 0; recordsCounter < recordsCount; recordsCounter++) {
|
|
const audioElement = audioElements[frequencies.value[recordsCounter]]
|
|
audioSources[frequencies.value[recordsCounter]] = `${window.location.origin}${encodeURI(audioPaths[recordsCounter])}`
|
|
}
|
|
useNuxtApp().$logger.log(audioSources[63])
|
|
}
|
|
}
|
|
|
|
const rampVolume = (frequency: number, targetVolume: number, duration: number) => {
|
|
const startVolume = currentVolumes[frequency] || 1
|
|
const startTime = Date.now()
|
|
const endTime = startTime + duration
|
|
|
|
if (rampIntervals[frequency]) {
|
|
clearInterval(rampIntervals[frequency]!)
|
|
}
|
|
|
|
rampIntervals[frequency] = setInterval(() => {
|
|
const now = Date.now()
|
|
if (now >= endTime) {
|
|
currentVolumes[frequency] = targetVolume
|
|
clearInterval(rampIntervals[frequency]!)
|
|
rampIntervals[frequency] = null
|
|
return
|
|
}
|
|
|
|
const progress = (now - startTime) / duration
|
|
currentVolumes[frequency] = startVolume + (targetVolume - startVolume) * progress
|
|
}, 50)
|
|
}
|
|
|
|
const handleValueChange = (frequency: number, value: number) => {
|
|
if (!isNaN(value)) {
|
|
gainValuesDB[frequency] = value
|
|
normalizedVolumes[frequency] = calculateNormalizedVolume(value)
|
|
currentVolumes[frequency] = normalizedVolumes[frequency]
|
|
} else {
|
|
logger.warn('value is not a number, skip...', { value })
|
|
}
|
|
}
|
|
|
|
onUnmounted(() => {
|
|
Object.values(rampIntervals).forEach((interval) => {
|
|
if (interval) { clearInterval(interval) }
|
|
})
|
|
})
|
|
|
|
return {
|
|
frequencies,
|
|
gainValuesDB,
|
|
currentVolumes,
|
|
normalizedVolumes,
|
|
audioElements,
|
|
handleValueChange,
|
|
error,
|
|
onFileSelected,
|
|
audioSrc,
|
|
rampTime,
|
|
startAll,
|
|
audioSources
|
|
}
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.error-message {
|
|
color: red;
|
|
font-weight: bold;
|
|
padding: 10px;
|
|
border: 1px solid red;
|
|
border-radius: 5px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.ramp-time-control {
|
|
margin-top: 20px;
|
|
}
|
|
.ramp-time-control input {
|
|
width: 300px;
|
|
margin: 0 10px;
|
|
}
|
|
.frequency-control {
|
|
margin-bottom: 20px;
|
|
padding: 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 5px;
|
|
}
|
|
</style>
|