2020-03-27 22:23:31 +00:00
|
|
|
import React from "react";
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
|
|
|
|
import Controls from "./components/controls";
|
|
|
|
import Visualizer from "./components/visualizer";
|
|
|
|
import { State } from "./store";
|
|
|
|
|
|
|
|
type AudioState = {
|
|
|
|
audioContext: AudioContext;
|
|
|
|
audioSource: HTMLAudioElement;
|
|
|
|
audioSourceNode: MediaElementAudioSourceNode;
|
|
|
|
audioVolume: GainNode;
|
|
|
|
};
|
|
|
|
|
|
|
|
type MusicPlayerProps = {
|
|
|
|
playing: boolean;
|
|
|
|
muted: boolean;
|
|
|
|
source?: string;
|
|
|
|
};
|
|
|
|
|
2021-04-07 23:14:42 +01:00
|
|
|
class MusicPlayer extends React.Component<MusicPlayerProps, State> {
|
2020-03-27 22:23:31 +00:00
|
|
|
private audioState: AudioState;
|
|
|
|
|
|
|
|
constructor(props: MusicPlayerProps) {
|
|
|
|
super(props);
|
|
|
|
|
2021-04-07 23:14:42 +01:00
|
|
|
const context = new AudioContext();
|
|
|
|
const source = new Audio();
|
|
|
|
const sourceNode = context.createMediaElementSource(source);
|
|
|
|
const volume = context.createGain();
|
2020-03-27 22:23:31 +00:00
|
|
|
|
|
|
|
sourceNode.connect(volume);
|
|
|
|
volume.connect(context.destination);
|
|
|
|
|
|
|
|
this.audioState = {
|
|
|
|
audioContext: context,
|
|
|
|
audioSourceNode: sourceNode,
|
|
|
|
audioSource: source,
|
|
|
|
audioVolume: volume,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div id="player" style={{ height: "100%", width: "100%" }}>
|
|
|
|
<Visualizer
|
|
|
|
audioContext={this.audioState.audioContext}
|
|
|
|
audioSource={this.audioState.audioSourceNode}
|
|
|
|
/>
|
|
|
|
<Controls />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
2021-04-07 23:14:42 +01:00
|
|
|
const context = this.audioState.audioContext;
|
|
|
|
const source = this.audioState.audioSource;
|
|
|
|
const volume = this.audioState.audioVolume;
|
2020-03-27 22:23:31 +00:00
|
|
|
|
|
|
|
// First, set the audio source (if it changed)
|
|
|
|
if (this.props.source && source.src != this.props.source) {
|
|
|
|
source.src = this.props.source;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.props.playing) {
|
|
|
|
source
|
|
|
|
.play()
|
|
|
|
.then(() => {
|
|
|
|
console.info("Started playing audio");
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error(`Could not play audio: ${error}`);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
source.pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.props.muted) {
|
|
|
|
volume.gain.setValueAtTime(1, context.currentTime);
|
|
|
|
} else {
|
|
|
|
volume.gain.setValueAtTime(0, context.currentTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function mapStateToProps(state: State): MusicPlayerProps {
|
|
|
|
return {
|
|
|
|
playing: state.musicState.playing,
|
|
|
|
muted: state.musicState.muted,
|
|
|
|
source: state.musicState.source,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export default connect(mapStateToProps)(MusicPlayer);
|