scratch-gui
Version:
GraphicaL User Interface for creating and running Scratch 3.0 projects
155 lines (143 loc) • 4.88 kB
JSX
import bindAll from 'lodash.bindall';
import PropTypes from 'prop-types';
import React from 'react';
import VM from 'scratch-vm';
import WavEncoder from 'wav-encoder';
import {connect} from 'react-redux';
import RecordModalComponent from '../components/record-modal/record-modal.jsx';
import {
closeSoundRecorder
} from '../reducers/modals';
class RecordModal extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleRecord',
'handleStopRecording',
'handlePlay',
'handleStopPlaying',
'handleBack',
'handleSubmit',
'handleCancel',
'handleSetPlayhead',
'handleSetTrimStart',
'handleSetTrimEnd'
]);
this.state = {
samples: null,
encoding: false,
levels: null,
playhead: null,
playing: false,
recording: false,
sampleRate: null,
trimStart: 0,
trimEnd: 1
};
}
handleRecord () {
this.setState({recording: true});
}
handleStopRecording (samples, sampleRate, levels, trimStart, trimEnd) {
this.setState({samples, sampleRate, levels, trimStart, trimEnd, recording: false});
}
handlePlay () {
this.setState({playing: true});
}
handleStopPlaying () {
this.setState({playing: false, playhead: null});
}
handleBack () {
this.setState({playing: false, samples: null});
}
handleSetTrimEnd (trimEnd) {
this.setState({trimEnd});
}
handleSetTrimStart (trimStart) {
this.setState({trimStart});
}
handleSetPlayhead (playhead) {
this.setState({playhead});
}
handleSubmit () {
this.setState({encoding: true}, () => {
const sampleCount = this.state.samples.length;
const startIndex = Math.floor(this.state.trimStart * sampleCount);
const endIndex = Math.floor(this.state.trimEnd * sampleCount);
const clippedSamples = this.state.samples.slice(startIndex, endIndex);
WavEncoder.encode({
sampleRate: this.state.sampleRate,
channelData: [clippedSamples]
}).then(wavBuffer => {
const vmSound = {
format: '',
dataFormat: 'wav',
rate: this.state.sampleRate,
sampleCount: clippedSamples.length
};
// Load the encoded .wav into the storage cache and get resulting
// md5 from storage
const storage = this.props.vm.runtime.storage;
const md5 = storage.builtinHelper.cache(
storage.AssetType.Sound,
storage.DataFormat.WAV,
new Uint8Array(wavBuffer),
);
// update vmSound object with md5 property
vmSound.md5 = `${md5}.${vmSound.dataFormat}`;
// The VM will update the sound name to a fresh name
// if the following is already taken
vmSound.name = 'recording1';
this.props.vm.addSound(vmSound).then(() => {
this.props.onClose();
this.props.onNewSound();
});
});
});
}
handleCancel () {
this.props.onClose();
}
render () {
return (
<RecordModalComponent
encoding={this.state.encoding}
levels={this.state.levels}
playhead={this.state.playhead}
playing={this.state.playing}
recording={this.state.recording}
sampleRate={this.state.sampleRate}
samples={this.state.samples}
trimEnd={this.state.trimEnd}
trimStart={this.state.trimStart}
onBack={this.handleBack}
onCancel={this.handleCancel}
onPlay={this.handlePlay}
onRecord={this.handleRecord}
onSetPlayhead={this.handleSetPlayhead}
onSetTrimEnd={this.handleSetTrimEnd}
onSetTrimStart={this.handleSetTrimStart}
onStopPlaying={this.handleStopPlaying}
onStopRecording={this.handleStopRecording}
onSubmit={this.handleSubmit}
/>
);
}
}
RecordModal.propTypes = {
onClose: PropTypes.func,
onNewSound: PropTypes.func,
vm: PropTypes.instanceOf(VM)
};
const mapStateToProps = state => ({
vm: state.vm
});
const mapDispatchToProps = dispatch => ({
onClose: () => {
dispatch(closeSoundRecorder());
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(RecordModal);