From 8a0cf73197b8705a01116c7c6e079a9b6e2e0fa0 Mon Sep 17 00:00:00 2001 From: Jeremy Scheff Date: Sun, 12 Jun 2016 18:17:26 -0400 Subject: [PATCH] Play/Pause/Stop buttons --- src/components/App.jsx | 105 ++++++++++++++++++++----------- src/components/TrackControls.jsx | 57 +++++++++++++++++ src/css/my.css | 2 +- src/lib/soundtouch.js | 9 +-- 4 files changed, 132 insertions(+), 41 deletions(-) create mode 100644 src/components/TrackControls.jsx diff --git a/src/components/App.jsx b/src/components/App.jsx index 7ed3bed..ae7425d 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -3,13 +3,16 @@ const React = require('react'); const {SimpleFilter, SoundTouch} = require('../lib/soundtouch'); const ErrorAlert = require('./ErrorAlert.jsx'); const FilenameLabel = require('./FilenameLabel.jsx'); +const TrackControls = require('./TrackControls.jsx'); + +const BUFFER_SIZE = 4096; class App extends React.Component { constructor(props) { super(props); this.state = { - bufferSource: undefined, + action: 'stop', error: undefined, filename: undefined, pitch: 0.8, @@ -18,6 +21,7 @@ class App extends React.Component { }; this.audioContext = new AudioContext(); + this.scriptProcessor = this.audioContext.createScriptProcessor(BUFFER_SIZE, 2, 2); this.soundTouch = new SoundTouch(); this.soundTouch.pitch = this.state.pitch; @@ -34,16 +38,13 @@ class App extends React.Component { }); } - - playSound(buffer) { + setBuffer(buffer) { const bufferSource = this.audioContext.createBufferSource(); bufferSource.buffer = buffer; - const BUFFER_SIZE = 4096; - const node = this.audioContext.createScriptProcessor(BUFFER_SIZE, 2, 2); const samples = new Float32Array(BUFFER_SIZE * 2); - const source = { + this.source = { extract: (target, numFrames, position) => { const l = buffer.getChannelData(0); const r = buffer.getChannelData(1); @@ -54,14 +55,13 @@ class App extends React.Component { return Math.min(numFrames, l.length - position); }, }; - const f = new SimpleFilter(source, this.soundTouch); - - node.onaudioprocess = e => { + this.f = new SimpleFilter(this.source, this.soundTouch); + this.scriptProcessor.onaudioprocess = e => { const l = e.outputBuffer.getChannelData(0); const r = e.outputBuffer.getChannelData(1); - const framesExtracted = f.extract(samples, BUFFER_SIZE); + const framesExtracted = this.f.extract(samples, BUFFER_SIZE); if (framesExtracted === 0) { - node.disconnect(this.audioContext.destination); + this.pause(); } for (let i = 0; i < framesExtracted; i++) { l[i] = samples[i * 2]; @@ -69,19 +69,31 @@ class App extends React.Component { } }; - node.connect(this.audioContext.destination); -// bufferSource.connect(this.audioContext.destination); -// bufferSource.start(0); + this.play(); + } + + play() { + if (this.state.action !== 'play') { + this.scriptProcessor.connect(this.audioContext.destination); + this.emitter.emit('state', {action: 'play'}); + } + } - this.setState({bufferSource}); + pause() { + if (this.state.action === 'play') { + this.scriptProcessor.disconnect(this.audioContext.destination); + this.emitter.emit('state', {action: 'pause'}); + } + } + + stop() { + this.pause(); + this.f.sourcePosition = 0; + this.emitter.emit('state', {action: 'stop'}); } handleFileChange(e) { if (e.target.files.length > 0) { - if (this.state.bufferSource) { - this.state.bufferSource.stop(); - } - this.emitter.emit('status', 'Reading file...'); this.emitter.emit('state', { error: undefined, @@ -113,24 +125,20 @@ class App extends React.Component { return; } - this.playSound(buffer); + this.setBuffer(buffer); }; } } handlePitchChange(e) { const pitch = e.target.value; - if (this.state.bufferSource) { - this.soundTouch.pitch = pitch; - } + this.soundTouch.pitch = pitch; this.setState({pitch}); } handleTempoChange(e) { const tempo = e.target.value; - if (this.state.bufferSource) { - this.soundTouch.tempo = tempo; - } + this.soundTouch.tempo = tempo; this.setState({tempo}); } @@ -154,36 +162,61 @@ class App extends React.Component { + +
-
+
+ this.play()} + onPause={() => this.pause()} + onStop={() => this.stop()} + /> +
+
+ this.handlePitchChange(e)} + /> +
+
+ +
+
Pitch ({this.state.pitch}x)
-
+
this.handlePitchChange(e)} />
+
-
+
Tempo ({this.state.tempo}x)
-
+
this.handleTempoChange(e)} /> diff --git a/src/components/TrackControls.jsx b/src/components/TrackControls.jsx new file mode 100644 index 0000000..4840e1e --- /dev/null +++ b/src/components/TrackControls.jsx @@ -0,0 +1,57 @@ +const React = require('react'); + +const TrackControls = props => { + const disabled = props.error !== undefined || props.filename === undefined; +console.log(disabled, props); + + let playOrPause; + if (props.action === 'play') { + playOrPause = ( + + ); + } else { + playOrPause = ( + + ); + } + + return ( +
+ {playOrPause} + +
+ ); +}; + +TrackControls.propTypes = { + action: React.PropTypes.string, + error: React.PropTypes.shape({ + type: React.PropTypes.string.isRequired, + message: React.PropTypes.string.isRequired, + }), + filename: React.PropTypes.string, + onPause: React.PropTypes.func, + onPlay: React.PropTypes.func, + onStop: React.PropTypes.func, +}; + +module.exports = TrackControls; diff --git a/src/css/my.css b/src/css/my.css index 534a9ed..99ca733 100644 --- a/src/css/my.css +++ b/src/css/my.css @@ -1,4 +1,4 @@ .filename-label { padding-top: 16px; vertical-align: 2px; -} \ No newline at end of file +} diff --git a/src/lib/soundtouch.js b/src/lib/soundtouch.js index d69fef1..c134d20 100644 --- a/src/lib/soundtouch.js +++ b/src/lib/soundtouch.js @@ -240,7 +240,7 @@ FifoSampleBuffer.prototype = { }, clear: function() { - this.receive(frameCount); + this.receive(this._frameCount); this.rewind(); }, @@ -1003,8 +1003,8 @@ function SoundTouch() { extend(SoundTouch.prototype, { clear: function () { - rateTransposer.clear(); - tdStretch.clear(); + this.rateTransposer.clear(); + this.tdStretch.clear(); }, clone: function () { @@ -1108,5 +1108,6 @@ extend(SoundTouch.prototype, { } }); -// This is the only part that was added for screw +// This is the only part that was added for screw (plus fixing a couple typos where `this` was +// erroneously not used) module.exports = {SimpleFilter, SoundTouch};