react-redux.Attn: Do not use this library for processing audio events that require low latency.
Audio events are handled by React’s internal reconciliation/diffing algos and therefore the latency, in terms of audio, is huge.
Live Demo To build the examples locally, clone/fork the repo and run:
cd examples
yarn /* OR */ npm install
npm start // this will start a webpack-dev-server and open the demo in your browser
npm i react-redux-webaudio
/**
* Imports
*/
// Es6+ import
import { RRWAEngine, actionCreators, webAudioReducer } from 'react-redux-webaudio';
// Es5
const { RRWAEngine, actionCreators, webAudioReducer } = require('react-redux-webaudio');
/**
* The root reducer used in the Redux store.
*/
const rootReducer = combineReducers({
// your other reducers...
webAudioReducer
});
/**
* The application entry point.
* Best to keep RRWAEngine at the top-level but technically it can be
* anywhere, as long as it renders before any AudioEvents are emitted.
*/
ReactDOM.render(
<Provider store={store}>
<div>
<RRWAEngine />
<App />
</div>
</Provider>,
document.getElementById('app')
);
/**
* A container component that will render within the component tree of <App />
*/
const Container = connect(
state => state,
dispatch => ({ makeNoise: () => dispatch(actionCreators.emit(audioEvent)) })
)(ReactComponent);
React-Redux-Webaudio consists of three modules:
Within the context of React-Redux-Webaudio, an AudioEvent is a function that receives one or two arguments: a reference to an instance of window.AudioContext, anda function that when called, returns that instance’s currentTime value.
type AudioEvent = (audioCtx: AudioContext, getCurrentTime?: () => number) => void | any;
// a semi-practical example of what an AudioEvent could look like
let audioEvent: AudioEvent = (audioCtx, getCurrentTime) => {
let oscillator: OscillatorNode = audioCtx.createOscillator();
let gainNode: GainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.type = 'square';
oscillator.frequency.value = 100;
oscillator.start(getCurrentTime() + 500); // wait half a second, then make sound.
gainNode.gain.value = 0.1;
};
audioCtx.currentTime may result in the time when the event was queued, not invoked. Instead, use the optional function getCurrentTime, which will return the value of audioCtx.currentTime when the AudioEvent is actually invoked.emitThe emit action-creator receives a single event or an array of events.
emit action-creator:To use your own Redux action instead of the one created by emit, the action type must be 'QUEUE_EVENT' and the action must have an event key with a value of an AudioEvent or Array<AudioEvent>.
type AudioEventAction = {
type: 'QUEUE_EVENT'
event: AudioEvent | AudioEvent[]
}
let action: AudioEventAction = {
type: 'QUEUE_EVENT',
event: (audioCtx, currentTime) => {
// do something... anything.
}
};
store.dispatch(action); // more practically, include the action within a mapDispatchToProps function.
Include the RRWAEngine component anywhere in your app (best to keep RRWAEngine at the top-level but technically it can be anywhere). It must be within scope of the Redux store containing the webAudioReducer.
class App extends React.Component {
render() {
return (
<div>
<RRWAEngine />
{/* other components would go here */}
</div>
);
}
}
ReactDOM.render(
<Provider store={ store }>
<App />
</Provider>,
document.getElementById('app')
);