Initial commit
This commit is contained in:
354
components/experiments/tests/showcases/PlayerComponent.vue
Normal file
354
components/experiments/tests/showcases/PlayerComponent.vue
Normal file
@@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<div>
|
||||
<h4>{{ currentScene.file }}</h4>
|
||||
<h4>Node {{ currentScene.node ? true : false }}</h4>
|
||||
<h4>{{ currentScene.title }}</h4>
|
||||
<h4>Howl {{ currentScene.howl ? true : false }}</h4>
|
||||
</div>
|
||||
<div class="rnboplayer">
|
||||
<button class="play yellow" @click="play" />
|
||||
<button v-if="playing" class="pause yellow" @click="pause" />
|
||||
<button v-if="playing" @click="useNuxtApp().$logger.log('hit play')">
|
||||
Pause
|
||||
</button>
|
||||
<div class="row">
|
||||
<div class="slider">
|
||||
<div class="icon">
|
||||
<!-- tropic icon -->
|
||||
<img style="width: 25px" src="~/assets/image/noiseicon.svg">
|
||||
</div>
|
||||
<input
|
||||
id="gain-control"
|
||||
v-model="outputNoiseGain"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
@wheel="changeNoiseGain"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="slider">
|
||||
<div class="icon">
|
||||
<!-- tropic icon -->
|
||||
<img style="width: 25px" src="~/assets/image/musicicon.svg">
|
||||
</div>
|
||||
<input
|
||||
id="gain-control"
|
||||
v-model="outputMusicGain"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
default="50"
|
||||
step="1"
|
||||
@wheel="changeMusicGain"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onBeforeUnmount, ref, computed, watch } from 'vue'
|
||||
import Player from '~/components/Player/Player.js'
|
||||
import setupNodes from '~/components/Player/Nodes'
|
||||
import { useUserStore } from '~/stores/user.js'
|
||||
import { usePlayerStore } from '~/stores/player.js'
|
||||
import tracksConfig from '~/tracks.config'
|
||||
|
||||
// Stores
|
||||
const userStore = useUserStore()
|
||||
const playerStore = usePlayerStore()
|
||||
|
||||
const playing = computed(() => usePlayerStore().playing as boolean)
|
||||
|
||||
// Refs
|
||||
const scenePlayer = ref<Player | null>(null)
|
||||
const noisePlayer = ref<Player | null>(null)
|
||||
const playlistIndex = ref(scenePlayer.value?.index || 0)
|
||||
|
||||
// Sliders
|
||||
const outputMusicGain = ref(0)
|
||||
const outputNoiseGain = ref(0)
|
||||
|
||||
// Playlists
|
||||
const scenesPlaylist = ref([
|
||||
{ title: 'Lagoon', file: 'lagoon', howl: null, node: null },
|
||||
{ title: 'Meadow', file: 'meadow', howl: null, node: null },
|
||||
{ title: 'Tropics', file: 'tropics', howl: null, node: null },
|
||||
{ title: 'Forest', file: 'forest', howl: null, node: null }
|
||||
])
|
||||
const howlsReadyCount = computed(() =>
|
||||
scenesPlaylist.value.filter(item => item.howl !== null).length
|
||||
)
|
||||
|
||||
const nodesReadyCount = computed(() =>
|
||||
scenesPlaylist.value.filter(item => item.node !== null).length
|
||||
)
|
||||
|
||||
const noisePlaylist = ref([
|
||||
{ title: 'noise', file: 'noise', howl: null, node: null }
|
||||
])
|
||||
const currentScene = computed(() => scenesPlaylist.value[0])
|
||||
|
||||
// Gain Nodes
|
||||
const noiseGainNode = ref<GainNode | null>(null)
|
||||
const musicGainNode = ref<GainNode | null>(null)
|
||||
|
||||
function play () {
|
||||
playerStore.playing = true
|
||||
useNuxtApp().$logger.log('current playing = ', playerStore.playing)
|
||||
}
|
||||
function pause () {
|
||||
playerStore.playing = false
|
||||
useNuxtApp().$logger.log('current playing = ', playerStore.playing)
|
||||
}
|
||||
|
||||
function changeNoiseGain (event: WheelEvent) {
|
||||
event.preventDefault()
|
||||
const delta = Math.sign(event.deltaY)
|
||||
if (noiseGainNode.value && isWithinRange(outputNoiseGain.value - delta)) {
|
||||
outputNoiseGain.value -= delta
|
||||
}
|
||||
}
|
||||
|
||||
function changeMusicGain (event: WheelEvent) {
|
||||
event.preventDefault()
|
||||
const delta = Math.sign(event.deltaY)
|
||||
if (musicGainNode.value && isWithinRange(outputMusicGain.value - delta)) {
|
||||
scenePlayer.value?.setVolume()
|
||||
outputMusicGain.value -= delta
|
||||
}
|
||||
}
|
||||
|
||||
function isWithinRange (val: number) {
|
||||
return val >= 0 && val <= 100
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
const logger = useNuxtApp().$logger
|
||||
|
||||
scenePlayer.value = new Player(scenesPlaylist, 'sounds')
|
||||
noisePlayer.value = new Player(noisePlaylist, 'masking')
|
||||
|
||||
scenePlayer.value.initializeHowl(scenePlayer.value.index)
|
||||
noisePlayer.value.initializeHowl(noisePlayer.value.index)
|
||||
|
||||
const userScenery = userStore.getUserScenery
|
||||
const filteredScenes = scenePlayer.value.playlist.filter(
|
||||
(playItem: { title: string }) => playItem.title.toLowerCase() === userScenery.toLowerCase()
|
||||
)
|
||||
|
||||
const noiseNode = noisePlayer.value.playlist[0].node
|
||||
const response = await setupNodes(noiseNode, filteredScenes[0].node)
|
||||
|
||||
if (response === null) {
|
||||
logger.info('Got no gain nodes from setupNodes, continue with HTML5')
|
||||
// noisePlayer.value.playlist[0].howl.play()
|
||||
// scenePlayer.value.playlist[0].howl.play()
|
||||
} else {
|
||||
try {
|
||||
// filteredScenes[0].howl.play()
|
||||
// noisePlayer.value.playlist[0].howl.play()
|
||||
if (response.length > 1) {
|
||||
noiseGainNode.value = response[0]
|
||||
musicGainNode.value = response[1]
|
||||
}
|
||||
if (musicGainNode.value && noiseGainNode.value) {
|
||||
musicGainNode.value.gain.value = 0.5
|
||||
noiseGainNode.value.gain.value = 0.5
|
||||
}
|
||||
} catch (error) {
|
||||
useNuxtApp().$logger.error(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
noisePlayer.value = null
|
||||
scenePlayer.value = null
|
||||
playerStore.resetAudioContext()
|
||||
})
|
||||
|
||||
// Watches
|
||||
watch(playlistIndex, (val) => {
|
||||
const player = scenePlayer.value as Player
|
||||
player.index = val
|
||||
// musicGainNode.value?.gain.linearRampToValueAtTime(val / 100, musicGainNode.value.context.currentTime + 0.2)
|
||||
})
|
||||
watch(outputMusicGain, (val) => {
|
||||
musicGainNode.value?.gain.linearRampToValueAtTime(val / 100, musicGainNode.value.context.currentTime + 0.2)
|
||||
})
|
||||
watch(outputNoiseGain, (val) => {
|
||||
noiseGainNode.value?.gain.linearRampToValueAtTime(val / 100, noiseGainNode.value.context.currentTime + 0.2)
|
||||
})
|
||||
watch(
|
||||
() => noisePlayer.value?.playlist[0]?.node,
|
||||
(node) => {
|
||||
if (node) { useNuxtApp().$logger.log('🎧 Node ist jetzt da:', node) }
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => playerStore.playing,
|
||||
(state) => {
|
||||
if (state && noisePlayer && scenePlayer) {
|
||||
noisePlayer.value?.play()
|
||||
scenePlayer.value?.play()
|
||||
useNuxtApp().$logger.log('🎧 Player spielt')
|
||||
} else {
|
||||
noisePlayer.value?.pause()
|
||||
scenePlayer.value?.pause()
|
||||
useNuxtApp().$logger.log('🎧 Player spielt nicht')
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.rnboplayer{
|
||||
position: fixed;
|
||||
width: 220px; /* Or specify a fixed width like 220px if you prefer */
|
||||
max-width: 220px; /* This line might be redundant depending on your width strategy */
|
||||
height: 100px;
|
||||
display: inline-grid;
|
||||
z-index: 2;
|
||||
bottom: 11%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.player {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
position:sticky;
|
||||
width: 225px;
|
||||
height: inherit;
|
||||
display:flex;
|
||||
float: bottom;
|
||||
}
|
||||
.player button {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px; /* Spacing between items */
|
||||
width: 225px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.icon, .slider {
|
||||
flex: 1 1 100px; /* Flex-grow, flex-shrink, flex-basis */
|
||||
display: flex;
|
||||
align-items: center; /* Center items vertically */
|
||||
justify-content: center; /* Center items horizontally */
|
||||
}
|
||||
.icon {
|
||||
/* Add padding around the icon for margin */
|
||||
margin-right: 15px; /* Adjust this value as needed */
|
||||
|
||||
/* Align items if using flexbox */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon img {
|
||||
/* Adjust width and height as needed or keep them auto to maintain aspect ratio */
|
||||
width: auto;
|
||||
height: 100%; /* Example height, adjust based on your icon size */
|
||||
}
|
||||
|
||||
.slider input[type=range] {
|
||||
width: 100%; /* Full width of its parent */
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.row {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.icon, .slider {
|
||||
flex: 1; /* Take up equal space */
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles the track */
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
height: 8px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
height: 8px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-ms-track {
|
||||
background: #e9c046; /* yellow track */
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.play.yellow {
|
||||
background: rgba(255, 176, 66, 0.008);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 0 rgba(255, 177, 66, 1);
|
||||
animation: pulse-yellow 4s infinite;
|
||||
position: fixed;
|
||||
bottom: 40%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-image: url('/images/playbtn.svg');
|
||||
background-repeat:no-repeat;
|
||||
background-attachment:fixed;
|
||||
background-position: 58% 55%;
|
||||
}
|
||||
.pause.yellow {
|
||||
background: rgba(255, 176, 66, 0.008);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 0 rgba(255, 177, 66, 1);
|
||||
opacity: 0.05;
|
||||
position: fixed;
|
||||
bottom: 40%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-image: url('/images/pausebtn.svg');
|
||||
background-size: 130px 100px;
|
||||
background-repeat:no-repeat;
|
||||
background-attachment:fixed;
|
||||
background-position: center;
|
||||
}
|
||||
.pause.yellow:hover{
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@keyframes pulse-yellow {
|
||||
0% {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0 0 0 0 rgba(255, 177, 66, 0.7);
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 10px rgba(255, 177, 66, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0 0 0 0 rgba(255, 177, 66, 0);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
Reference in New Issue
Block a user