Files
audioshowkit/src/player/PlaylistSong.js
2022-04-17 21:13:12 -05:00

190 lines
4.6 KiB
JavaScript

import Visualizer from "../visualization/Visualizer.js";
/**
* A song with metadata that can be used as part of a {@link SongPlaylist}.
*
*/
export default class PlayListSong {
/**
* Constructs a song for a {@link SongPlaylist}.
*
* @param {string} url the url to fetch the song from.
* @param {string} name the name of the song.
* @param {string} author the author of the song.
*/
constructor(url, name, author) {
this._displayName = name;
this._author = author;
this._url = url;
this._audio = null;
this._visualizer = null;
/**
* Whether or not this song is ready to be played.
*/
this.ready = false;
}
/**
* @callback AudioEventCallback
* @param {HTMLAudioElement} audio
*/
/**
*
* @param {AudioEventCallback} [onReady] called when the song is ready, including right away if the song is already ready.
* @returns {HTMLAudioElement} The audio element that represents this song.
*/
getAudio(onReady) {
if (this._audio) {
if (this.ready) {
if (onReady) onReady(this._audio);
}
return this._audio;
}
this._audio = new Audio(this._url);
this._audio.addEventListener("canplaythrough", () => {
this.ready = true;
if (onReady && this.isAudioInstantiated()) {
onReady(this._audio);
}
});
return this._audio;
}
/**
*
* @returns {string} representing the name of the song to be displayed.
*/
getDisplayName() {
return this._displayName;
}
/**
*
* @returns {string} representing the author of the song.
*/
getAuthor() {
return this._getAuthor;
}
/**
*
* @returns {string} representing the url at which the file for this song can be found.
*/
getUrl() {
return this._url;
}
/**
*
* @returns {boolean} true if and only if there is audio data that is either already loaded or is being loaded.
*/
isAudioInstantiated() {
return this._audio ? true : false;
}
/**
* Begins audio playback as soon as possible.
*
* This function uses the {@link PlaylistSong#getAudio} function and specifically, the {@link AudioEventCallback}.
*/
play() {
this.getAudio((audio) => {
audio.play();
});
}
/**
* Pauses the audio playback, unless the audio data has yet to be instantiated.
*/
pause() {
if (!this.isAudioInstantiated()) return;
this.getAudio((audio) => {
audio.pause();
});
}
/**
*
* @returns {number} the volume on a scale of 0 to 1.
*/
getVolume() {
return this.getAudio().volume;
}
/**
*
* @param {number} volume a normalized volume on a scale of 0 to 1.
*/
setVolume(volume) {
this.getAudio().volume = volume;
}
/**
*
* @returns {number} the number of seconds into the song.
*/
getCurrentTime() {
return this.getAudio().currentTime;
}
/**
*
* @param {number} currentTime the time position in the song to jump to in seconds.
*/
setCurrentTime(currentTime) {
this.getAudio().currentTime = currentTime;
}
/**
*
* @returns {number} the duration of the song.
*/
getDuration() {
return this.getAudio().duration;
}
/**
* Unloads the audio data.
* Makes sure the audio is paused.
*
* Also calls {@link PlaylistSong#unloadVisualizer}.
*/
unloadAudio() {
if (!this.isAudioInstantiated()) return;
this._audio.pause();
this.unloadVisualizer();
this._audio = null;
this.ready = false;
}
/**
*
* @param {number} [fftSize=1024] the size of the FFT window.
* @returns {Visualizer} returns the visualizer.
*/
getVisualizer(fftSize = 1024) {
if (this._visualizer && this._visualizer.getFftSize() === fftSize) return this._visualizer;
this._visualizer = new Visualizer(this.getAudio(), fftSize);
return this._visualizer;
}
/**
*
* @returns {boolean} returns true if and only if the visualizer is instantiated.
*/
isVisualizerInstantiated() {
return this._visualizer ? true : false;
}
/**
* Unloads the visualizer.
* Stops the visualizer.
*/
unloadVisualizer() {
this._visualizer.stop();
this._visualizer = null;
}
}