Source

components/Music/PracticeMusicHeader/MusicControls/MusicControls.js

// NPM module imports
import React, { Component } from "react";

// File imports
import alphaTabVars from "../../../../vendors/AlphaTab/variables";
import { stopPlayingMusic } from "../../../../vendors/AlphaTab/actions";
import pitchDetectionVars from "../../../../vendors/ML5/PitchDetection/variables";
import { isPitchDetectionAvailable } from "../../../../vendors/ML5/PitchDetection/actions";
import { sheetMusicError } from "../../../../vendors/Firebase/logs";

// Image imports
import playButtonImg from "../../../../assets/icons/play-icon-blue.svg";
import pauseButtonImg from "../../../../assets/icons/pause-icon-blue.svg";
import stopButtonImg from "../../../../assets/icons/stop-icon-blue.svg";

// Style imports
import styles from "./MusicControls.module.scss";

/**
 * Renders the MusicControls component.
 * Handles the play, pause, and stop controls for the sheet music.
 * @extends {Component}
 * @component
 * @category Music
 * @author Dan Levy <danlevy124@gmail.com>
 */
class MusicControls extends Component {
    /**
     * MusicControls component state
     * @property {boolean} isPlaying - Indicates if the music is currently playing
     */
    state = {
        isPlaying: false,
    };

    /**
     * Adds an AlphaTab player finished observer
     */
    componentDidMount() {
        alphaTabVars.api.addPlayerFinished(this.donePlaying);
    }

    /**
     * Removes the AlphaTab player finished observer
     */
    componentWillUnmount() {
        alphaTabVars.api.removePlayerFinished(this.donePlaying);
    }

    /**
     * Plays or pauses the music
     * @function
     */
    playPauseButtonHandler = () => {
        if (alphaTabVars.texLoaded === null) {
            return;
        }

        // Flips the isPlaying property in state
        this.setState((prevState) => ({
            isPlaying: !prevState.isPlaying,
        }));

        // AudioContext must be resumed before playing can begin (the first time)
        if (
            isPitchDetectionAvailable() &&
            pitchDetectionVars.audioContext.state !== "running"
        ) {
            pitchDetectionVars.audioContext
                .resume()
                .then(alphaTabVars.api.playPause)
                .catch((error) => {
                    // Logs an error
                    sheetMusicError(
                        null,
                        error,
                        "[MusicControls/playPauseButtonHandler]"
                    );
                });
        } else {
            alphaTabVars.api.playPause();
        }
    };

    /**
     * Stops the music
     * @function
     */
    stopButtonHandler = () => {
        // Updates state
        this.donePlaying();

        // Tells AlphaTab to stop playing the music
        stopPlayingMusic();
    };

    /**
     * Sets isPlaying to false in state
     * @function
     */
    donePlaying = () => {
        this.setState({
            isPlaying: false,
        });
    };

    /**
     * Gets a play icon or a pause icon
     * @returns An img element (JSX)
     */
    getPlayPauseIcon = () => {
        // Gets play/pause button details based on state
        let imgSrc;
        let altText;
        if (this.state.isPlaying) {
            // Get pause icon
            imgSrc = pauseButtonImg;
            altText = "Pause Button";
        } else {
            // Get play icon
            imgSrc = playButtonImg;
            altText = "Play Button";
        }

        // Returns the image element
        return (
            <img
                className={styles.musicControlsButtonImg}
                src={imgSrc}
                alt={altText}
            />
        );
    };

    /**
     * Renders the MusicControls component
     */
    render() {
        return (
            <div className={styles.musicControls}>
                {/* Play/Pause Button */}
                <button
                    className={styles.musicControlsButton}
                    type="button"
                    onClick={this.playPauseButtonHandler}
                >
                    {this.getPlayPauseIcon()}
                </button>

                {/* Stop Button */}
                <button
                    className={styles.musicControlsButton}
                    type="button"
                    onClick={this.stopButtonHandler}
                >
                    <img
                        className={styles.musicControlsButtonImg}
                        src={stopButtonImg}
                        alt="Stop Button"
                    />
                </button>
            </div>
        );
    }
}

export default MusicControls;