95 lines
2.3 KiB
TypeScript
95 lines
2.3 KiB
TypeScript
|
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;
|
||
|
};
|
||
|
|
||
|
class MusicPlayer extends React.Component<MusicPlayerProps, {}> {
|
||
|
private audioState: AudioState;
|
||
|
|
||
|
constructor(props: MusicPlayerProps) {
|
||
|
super(props);
|
||
|
|
||
|
let context = new AudioContext();
|
||
|
let source = new Audio();
|
||
|
let sourceNode = context.createMediaElementSource(source);
|
||
|
let volume = context.createGain();
|
||
|
|
||
|
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() {
|
||
|
let context = this.audioState.audioContext;
|
||
|
let source = this.audioState.audioSource;
|
||
|
let volume = this.audioState.audioVolume;
|
||
|
|
||
|
// 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);
|