diff --git a/src/App.vue b/src/App.vue index 22e4d4d..716c2c5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,7 +2,7 @@
@@ -21,16 +21,41 @@ import Channel from "@/components/Channel.vue"; }) export default class App extends Vue { private readonly N_CHANNELS = 6; + private readonly LFO_PERIOD = 30_000; + private readonly LFO_DEPTH = 33; + private readonly LFO_OFFSET = 66; + + private volumes = Array(this.N_CHANNELS).fill(50); + private animateVolumeStart?: Date; + private animateVolumeInterval?: number; private defaultMedia = [ - "https://www.youtube.com/watch?v=q76bMs-NwRk" + "https://www.youtube.com/watch?v=q76bMs-NwRk", ]; private start() { (this.$refs.channels as Channel[]).forEach((channel) => { channel.start(); + this.animateVolume(); }); } + + private animateVolume() { + clearInterval(this.animateVolumeInterval); + this.animateVolumeStart = new Date(); + this.animateVolumeInterval = setInterval(() => { + if (this.animateVolumeStart) { + const delta = new Date().getTime() - this.animateVolumeStart.getTime(); + + this.volumes = [...Array(this.N_CHANNELS).keys()] + .map((idx) => { + const offset = idx * (1 / this.N_CHANNELS); + const progress = delta / this.LFO_PERIOD + offset; + return Math.sin(progress * 2 * Math.PI) * this.LFO_DEPTH + this.LFO_OFFSET; + }); + } + }, 1000 / 60); + } } diff --git a/src/components/Channel.vue b/src/components/Channel.vue index 6c13664..6b48ccb 100644 --- a/src/components/Channel.vue +++ b/src/components/Channel.vue @@ -32,14 +32,11 @@ enum ChannelState { @Component export default class Channel extends Vue { - @Prop() private url: string | undefined; + @Prop() public volume: number = 50; + @Prop() public url: string | undefined; private youtubePlayer?: YouTubePlayer; - private animateVolumeStart?: Date; - private animateVolumeInterval?: number; private state = ChannelState.UNLOADED; private title = ""; - private volume: number = 50; - private get source() { if (this.url) { @@ -63,7 +60,6 @@ export default class Channel extends Vue { this.youtubePlayer.setVolume(this.volume); this.youtubePlayer.playVideo(); this.state = ChannelState.PLAYING; - this.animateVolume(); } } @@ -117,18 +113,6 @@ export default class Channel extends Vue { this.onUrlChange(); } - private animateVolume() { - clearInterval(this.animateVolumeInterval); - const LFO_PERIOD = 3000; - this.animateVolumeStart = new Date(); - this.animateVolumeInterval = setInterval(() => { - if (this.animateVolumeStart) { - const delta = new Date().getTime() - this.animateVolumeStart.getTime(); - this.volume = Math.sin(((delta % LFO_PERIOD) / LFO_PERIOD) * 2 * Math.PI) * 50 + 50; - } - }, 1000 / 60); - } - private static fetchYoutubeTitle(videoId: string): Promise { return new Promise((resolve, reject) => { let url = `https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}`;