Added more documentation.

This commit is contained in:
Harrison Deng 2022-04-16 04:57:34 -05:00
parent bf35220703
commit d2343a611b
8 changed files with 129 additions and 20 deletions

View File

@ -3,6 +3,8 @@ import SongPlaylist from "./SongPlaylist.js";
/**
* A song with metadata that can be used as part of a {@link SongPlaylist}.
*
* Typically should not be manually instantiated. Instead, create the song via {@link SongPlaylist}.
*/
export default class PlayListSong {
@ -98,6 +100,8 @@ export default class PlayListSong {
/**
* Begins audio playback as soon as possible.
*
* This function uses the {@link PlaylistSong#getAudio} function and specifically, the {@link AudioEventCallback}.
*/
play() {
this.getAudio((audio) => {
@ -156,6 +160,9 @@ export default class PlayListSong {
/**
* Unloads the audio data.
* Makes sure the audio is paused.
*
* Also calls {@link PlaylistSong#unloadVisualizer}.
*/
unloadAudio() {
if (!this.isAudioInstantiated()) return;
@ -186,6 +193,7 @@ export default class PlayListSong {
/**
* Unloads the visualizer.
* Stops the visualizer.
*/
unloadVisualizer() {
this._visualizer.stop();

View File

@ -2,7 +2,7 @@ import "../styles/songplayer.css";
import SongPlaylist from "./SongPlaylist.js";
/**
* A player to play songs.
* A player that keeps track of global properties for playback as well as traversing a playlist. Additionally keeps track of song audio data and attempts to reduce memory usage when possible.
*/
export default class SongPlayer {
@ -149,23 +149,40 @@ export default class SongPlayer {
return this._volume;
}
/**
* Attempts to seek to the given position.
*
* @param {number} position the position to seek to.
* @returns {boolean} true if and only if the position to seek to is within the duration of the track. This also means that if the track has not finished loading the duration data, than this will always return false.
*/
seek(position) {
if (position > this.getCurrentSong().getAudio().duration || position < 0) return;
if (position > this.getCurrentSong().getAudio().duration || position < 0) return false;
this.getCurrentSong().getAudio(audio => {
// TODO: May need to perform synchronization check to see if this is still the song to be played.
audio.currentTime = position;
});
return true;
}
/**
*
* @returns {number} how many seconds into the audio track has been played in seconds.
*/
getCurrentPosition() {
return this.getCurrentSong().getAudio().currentTime;
}
/**
*
* @returns {number} the total length of the song, or NaN if this information has not loaded yet.
*/
getCurrentDuration() {
return this.getCurrentSong().getAudio().duration;
}
/**
* Convenience method for creating a play button complete with CSS for transitioning to a paused button.
*
* Automatically hooked up to the player's state change updates and play and pause functions.
*
* @returns {HTMLElement} the play button element that can be added to a DOM.
*/
@ -175,12 +192,15 @@ export default class SongPlayer {
playButton.classList.add("play-btn");
if (!this._playing) playButton.classList.add("paused");
playButton.addEventListener("click", (e) => {
playButton.addEventListener("click", () => {
this.togglePlay();
if (this._playing) {
e.currentTarget.classList.remove("paused");
});
this.addPlayChangeListener((old, current) => {
if (current) {
playButton.classList.remove("paused");
} else {
e.currentTarget.classList.add("paused");
playButton.classList.add("paused");
}
});
return playButton;

View File

@ -1,7 +1,7 @@
import PlaylistSong from "./PlaylistSong.js";
/**
* A playlist that holds a multitude of songs.
* A playlist that holds a multitude of songs in the form of {@see PlaylistSong}.
*/
export default class SongPlaylist {
@ -36,14 +36,23 @@ export default class SongPlaylist {
return this.list[index];
}
songsWithName(name) {
return this._list.filter((item) => item.getDisplayName() == name);
}
/**
* Automatically creates and adds a {@see PlaylistSong} to this playlist.
*
* @param {string} url where the audio data can be found.
* @param {string} name the name of the song.
* @param {string} author the author(s) of the song.
*/
add(url, name, author) {
this._list.push(new PlaylistSong(url, name, author, this, this._list.length));
this._list.push(new PlaylistSong(url, name, author, this));
}
/**
* Removes a {@see playlistSong} from this playlist.
*
* @param {number} index the index of the song to be removed.
* @returns {PlaylistSong} the song that was removed, or null if the index of was invalid.
*/
remove(index) {
if (index >= this._list.length) {
return null;
@ -54,6 +63,12 @@ export default class SongPlaylist {
}
}
/**
* Attempts to find a {@link PlaylistSong} given a name.
*
* @param {string} name the name of the song to be found.
* @returns {number} the index of the song found, or -1 if it was not found.
*/
findSongIndex(name) {
return this._list.findIndex((item) => item.getDisplayName() == name);
}

View File

@ -13,6 +13,7 @@ import SongPlaylist from "./SongPlaylist.js";
export default class VisualizedSongPlayer extends SongPlayer {
/**
* Instantiates a song player with visualization features.
*
* @param {SongPlaylist} playlist the playlist this player manages.
* @param {number} [fftSize=1024] the size of the fft window for analysis.
@ -24,6 +25,7 @@ export default class VisualizedSongPlayer extends SongPlayer {
}
/**
* Sets the the playlist.
*
* @param {SongPlaylist} playlist the new playlist of songs that this player is in charge of.
*/

View File

@ -1,4 +1,37 @@
export { default as PlaylistSong } from "./PlaylistSong.js";
export { default as SongPlayer } from "./SongPlayer.js";
export { default as SongPlaylist } from "./SongPlaylist.js";
export { default as VisualizedSongPlayer } from "./VisualizedSongPlayer.js";
import SongPlayer from "./SongPlayer.js";
import SongPlaylist from "./SongPlaylist.js";
import VisualizedSongPlayer from "./VisualizedSongPlayer.js";
/**
* Instantiates a song player with a given playlist.
*
* @see SongPlayer for more information about the returned object.
* @param {SongPlaylist} playlist the playlist this player will play through.
* @returns {SongPlayer} the instantiated song player.
*/
export function createSongPlayer(playlist) {
return new SongPlayer(playlist);
}
/**
* Instantiates a song playlist.
*
* @see SongPlaylist for more information about the returned object.
* @param {string} name the name of the playlist.
* @returns {SongPlaylist} the instantiated song playlist.
*/
export function createSongPlaylist(name) {
return new SongPlaylist(name);
}
/**
* Creates a song player that manages the visualizers for individual songs, as well as the listeners for the visualizations.
*
* @see VisualizedSongPlayer for more information about the returned object.
* @param {SongPlaylist} playlist the playlist this visualized song player will play through.
* @param {number} [fftSize=1024] the FFT window size.
* @returns {VisualizedSongPlayer} a song player capable of retrieving the visualizer for the current playing song.
*/
export function createVisualizedSongPlayer(playlist, fftSize = 1024) {
return new VisualizedSongPlayer(playlist, fftSize);
}

View File

@ -1,5 +1,6 @@
/**
* A visualizer for an audio stream.
* Instantiates a visualizer with a given FFT window size and media source.
* Provides a simplified access point to the frequency bins in the form of a visualization update listener.
*/
export default class Visualizer {

View File

@ -1,5 +1,12 @@
import Visualizer from "./Visualizer.js";
/**
* A visualizer update manager offers an extra layer of abstraction on top of the {@link Visualizer}'s update listener.
*
* Specifically, the update manager handles updates directly from the {@link Visualizer} and checks for changes in the individual bins. These changes are then broadcasted to the individual bin listeners.
* If a bin has not changed, then it will not receive an update call. This means that there may be savings in function calls if this is used over the {@link Visualizer} directly.
*/
export default class VisualizerUpdateManager {
/**
*

View File

@ -1,2 +1,25 @@
export { default as Visualizer } from "./Visualizer.js";
export { default as VisualizerUpdateManager } from "./VisualizerUpdateManager.js";
import Visualizer from "./Visualizer.js";
import VisualizerUpdateManager from "./VisualizerUpdateManager.js";
/**
* Instantiates a visualizer.
*
* @see Visualizer for information on the returned object.
* @param {HTMLMediaElement|MediaSource} mediaSource the source of audio to be visualized.
* @param {number} [fftSize=1024] the FFT window size.
* @returns {Visualizer} the visualizer with the given media source and the given FFT size.
*/
export function createVisualizer(mediaSource, fftSize = 1024) {
return new Visualizer(mediaSource, fftSize);
}
/**
* Instantiates a VisualizerUpdateManager.
*
* @see VisualizerUpdateManager for information on the returned object.
* @param {Visualizer} visualizer the visualizer this update manager manages.
* @returns {VisualizerUpdateManager} the instantiated visualizer update manager for the given visualizer.
*/
export function createVisualizerUpdateManager(visualizer) {
return new VisualizerUpdateManager(visualizer);
}