UNPKG

akko

Version:

Music visualising framework based on WebGL and Web Audio API.

166 lines (147 loc) 5.92 kB
/** * @author Timur Kuzhagaliyev <tim.kuzh@gmail.com> * @copyright 2017 * @license GPL-3.0 */ // eslint-disable-next-line const {Component, h} = require('preact'); const PlayerStates = require('./MusicPlayer').States; class UIComponent extends Component { constructor(props) { super(props); this.state = { playerState: null, trackList: [], currentTrackIndex: null, visualisers: [], currentVisualiserIndex: null, }; props.musicPlayer.addListener(this.playbackListener.bind(this)); props.visCore.addListener(this.visualiserListener.bind(this)); } playbackListener(playerState, trackList, currentTrackIndex) { this.setState({ playerState, trackList, currentTrackIndex, }); } visualiserListener(visualisers, currentVisualiserIndex) { this.setState({ visualisers, currentVisualiserIndex, }); } playTrack(index, event) { event.preventDefault(); this.props.musicPlayer.playTrack(index); } togglePlayback(event) { event.preventDefault(); let state = this.state; state.playing = this.props.musicPlayer.togglePlayback(); this.setState(state); } addTrackByUrl(event) { event.preventDefault(); let audioUrl = prompt('Enter the URL of an audio file'); if (audioUrl) { this.props.musicPlayer.addTrack(audioUrl); } } uploadAudioFile(event) { event.preventDefault(); if (!this.fileInput) return; if (!this.fileInput.onchange) this.fileInput.onchange = this.addAudioFile.bind(this); this.fileInput.click(); } addAudioFile() { let files = this.fileInput.files; for (let i = 0; i < files.length; i++) { let file = files[i]; if (file.type.match(/audio.*/)) { this.props.musicPlayer.addTrack(file); } } } getTrackList() { let trackList = this.state.trackList; if (trackList) { let trackComponents = []; for (let i = 0; i < trackList.length; i++) { let track = trackList[i]; let isActive = this.state.currentTrackIndex === i; let activeClass = isActive ? 'active' : ''; let symbol = isActive ? this.getPlaybackSymbol() : `#${i + 1}`; trackComponents.push(<a href="#" alt={`Play track #${i + 1}`} onClick={this.playTrack.bind(this, i)} className={`akko-ui-container-list-item ${activeClass}`}> <span>{symbol}</span> {track.title}</a>); } return <div className="akko-ui-container-list">{trackComponents}</div>; } else { return null; } } getPlaybackSymbol() { return !this.isPlaying() ? '❚❚' : '►'; } getPlaybackButtonSymbol() { return this.isPlaying() ? '❚❚' : '►'; } isPlaying() { return this.state.playerState === PlayerStates.PLAYING; } useVisualiser(index, event) { event.preventDefault(); this.props.visCore.useVisualiser(index); } getVisualiserList() { let visualisers = this.state.visualisers; if (visualisers) { let visualiserComponents = []; for (let i = 0; i < visualisers.length; i++) { let visualiser = visualisers[i]; let isActive = this.state.currentVisualiserIndex === i; let activeClass = isActive ? 'active' : ''; let symbol = visualiser.code; visualiserComponents.push(<a href="#" alt={`Use visualiser #${i + 1}`} onClick={this.useVisualiser.bind(this, i)} className={`akko-ui-container-list-item ${activeClass}`}> <span>{symbol}</span> {visualiser.name}</a>); } return <div className="akko-ui-container-list">{visualiserComponents}</div>; } else { return null; } } render() { return ( <div className="akko-ui"> <div className="akko-ui-container akko-ui-tracks"> <div className="akko-ui-container-title">Player: {this.state.playerState}</div> {this.getTrackList()} <div className="akko-ui-add-tracks"> <input ref={input => this.fileInput = input} type="file" style="display: none;"/> <a href="#" alt="Add a track by URL" onClick={this.addTrackByUrl.bind(this)}>Add track by URL</a> or <a href="#" alt="Upload an audio file" onClick={this.uploadAudioFile.bind(this)}>upload audio file</a> <br/>or drag & drop a file into the visualiser. </div> </div> <div className="akko-ui-container akko-ui-visualisers"> <div className="akko-ui-container-title">Visualisers</div> {this.getVisualiserList()} </div> <div className="akko-ui-controls"> <a href="#" alt="Toggle playback" onClick={this.togglePlayback.bind(this)} className={`akko-ui-controls-play ${this.isPlaying() ? 'active' : ''}`}>{this.getPlaybackButtonSymbol()}</a> <div className="akko-ui-controls-progress"> <div className="akko-ui-controls-progress-indicator"/> </div> <div className="akko-ui-controls-volume"/> </div> </div> ); } } module.exports = UIComponent;