170 lines
3.8 KiB
TypeScript
170 lines
3.8 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import type { Track } from '~~/types'
|
|
import Disc from '~/platine-tools/disc'
|
|
import Sampler from '~/platine-tools/sampler'
|
|
import { useCardStore } from '~/store/card'
|
|
|
|
export const usePlatineStore = defineStore('platine', () => {
|
|
// State
|
|
const currentTrack = ref<Track | null>(null)
|
|
const isPlaying = ref(false)
|
|
const isLoadingTrack = ref(false)
|
|
const isFirstDrag = ref(true)
|
|
const progressPercentage = ref(0)
|
|
const currentTurns = ref(0)
|
|
const totalTurns = ref(0)
|
|
const isMuted = ref(false)
|
|
|
|
// Refs pour les instances
|
|
const disc = ref<Disc | null>(null)
|
|
const sampler = ref<Sampler | null>(null)
|
|
const discRef = ref<HTMLElement>()
|
|
|
|
// Actions
|
|
const initPlatine = (element: HTMLElement) => {
|
|
discRef.value = element
|
|
disc.value = new Disc(element)
|
|
sampler.value = new Sampler()
|
|
|
|
// Configurer les callbacks du disque
|
|
if (disc.value) {
|
|
disc.value.callbacks.onStop = () => {
|
|
sampler.value?.pause()
|
|
}
|
|
|
|
disc.value.callbacks.onDragStart = () => {
|
|
if (isFirstDrag.value) {
|
|
isFirstDrag.value = false
|
|
togglePlay()
|
|
if (sampler.value && disc.value) {
|
|
sampler.value.play(disc.value.secondsPlayed)
|
|
disc.value.powerOn()
|
|
}
|
|
}
|
|
}
|
|
|
|
disc.value.callbacks.onDragEnded = () => {
|
|
if (!isPlaying.value) return
|
|
sampler.value?.play(disc.value?.secondsPlayed || 0)
|
|
}
|
|
|
|
disc.value.callbacks.onLoop = ({ playbackSpeed, isReversed, secondsPlayed }) => {
|
|
sampler.value?.updateSpeed(playbackSpeed, isReversed, secondsPlayed)
|
|
updateTurns()
|
|
}
|
|
}
|
|
}
|
|
|
|
const updateTurns = () => {
|
|
if (!disc.value) return
|
|
|
|
currentTurns.value = disc.value.secondsPlayed * 0.75
|
|
totalTurns.value = (disc.value as any)._duration * 0.75
|
|
progressPercentage.value = Math.min(
|
|
100,
|
|
(disc.value.secondsPlayed / (disc.value as any)._duration) * 100
|
|
)
|
|
}
|
|
|
|
const loadTrack = async (track: Track) => {
|
|
const cardStore = useCardStore()
|
|
if (!sampler.value || !track) return
|
|
|
|
currentTrack.value = track
|
|
isLoadingTrack.value = true
|
|
|
|
try {
|
|
await sampler.value.loadTrack(track.filePath)
|
|
if (disc.value) {
|
|
disc.value.setDuration(sampler.value.duration)
|
|
updateTurns()
|
|
play()
|
|
}
|
|
} finally {
|
|
isLoadingTrack.value = false
|
|
cardStore.revealCard(track.id)
|
|
}
|
|
}
|
|
|
|
const play = (position = 0) => {
|
|
if (!disc.value || !sampler.value || !currentTrack.value) return
|
|
|
|
isPlaying.value = true
|
|
sampler.value.play(position)
|
|
disc.value.powerOn()
|
|
}
|
|
|
|
const pause = () => {
|
|
if (!disc.value || !sampler.value) return
|
|
|
|
isPlaying.value = false
|
|
sampler.value.pause()
|
|
disc.value.powerOff()
|
|
}
|
|
|
|
const togglePlay = () => {
|
|
if (isPlaying.value) {
|
|
pause()
|
|
} else {
|
|
play()
|
|
}
|
|
}
|
|
|
|
const toggleMute = () => {
|
|
if (!sampler.value) return
|
|
|
|
isMuted.value = !isMuted.value
|
|
if (isMuted.value) {
|
|
sampler.value.mute()
|
|
} else {
|
|
sampler.value.unmute()
|
|
}
|
|
}
|
|
|
|
const seek = (position: number) => {
|
|
if (!disc.value) return
|
|
|
|
disc.value.secondsPlayed = position
|
|
if (sampler.value) {
|
|
sampler.value.play(position)
|
|
}
|
|
}
|
|
|
|
// Nettoyage
|
|
const cleanup = () => {
|
|
if (disc.value) {
|
|
disc.value.stop()
|
|
disc.value.powerOff()
|
|
}
|
|
if (sampler.value) {
|
|
sampler.value.pause()
|
|
}
|
|
}
|
|
|
|
return {
|
|
// State
|
|
currentTrack,
|
|
isPlaying,
|
|
isLoadingTrack,
|
|
progressPercentage,
|
|
currentTurns,
|
|
totalTurns,
|
|
isMuted,
|
|
|
|
// Getters
|
|
coverUrl: computed(() => currentTrack.value?.coverId || '/card-dock.svg'),
|
|
|
|
// Actions
|
|
initPlatine,
|
|
loadTrack,
|
|
play,
|
|
pause,
|
|
togglePlay,
|
|
toggleMute,
|
|
seek,
|
|
cleanup
|
|
}
|
|
})
|
|
|
|
export default usePlatineStore
|