UNPKG

react-orchestra

Version:

A toolbox to build interactive and smart instruments on the web and mobile.

148 lines (142 loc) 4.7 kB
import React, { PropTypes } from 'react'; import { View } from 'react-native'; import MidiIO from '../MidiIO/src/'; import Note from './Note'; import Instrument from './Instrument'; import { sharpToBemol, generateNoteKey, delay, } from '../MusicManager'; import callIfExists from '../utils/callIfExists'; import isDefined from '../utils/isDefined'; const waitAndRun = (fnc, waitTime, ...args) => setTimeout(fnc.bind(...args), waitTime); export default class MidiTrack extends React.PureComponent { constructor(props) { super(props); this.state = { uniqueNotes: MidiIO.getUniqueFromMidiNotes(isDefined(props.notes, [])), playingNotes: {}, }; this.onTimerCall = this.onTimerCall.bind(this); this.onInstrumentLoaded = this.onInstrumentLoaded.bind(this); this.noteTimers = []; } componentDidMount() { if (this.props.play) { this.playTrack(); } } componentWillReceiveProps(nextProps) { if (nextProps.play && !this.props.play) { this.playTrack(); } else if (!nextProps.play && this.props.play) { this.stopPlayingTrack(); } } async onTimerCall(note) { const { noteName, instrumentName, durationInMS } = note; const noteInstrumentName = this.props.instrumentName || instrumentName; const key = generateNoteKey(noteInstrumentName, noteName); this.setState({ playingNotes: { [key]: true, }, }); callIfExists(this.props.onNotePlayed, noteInstrumentName, noteName); const updatedPlayingNotes = Object.assign({}, this.state.playingNotes); delete updatedPlayingNotes[key]; await delay(durationInMS); this.setState({ playingNotes: updatedPlayingNotes }); callIfExists(this.props.onNoteStopPlaying, noteInstrumentName, noteName); } onInstrumentLoaded(instrument) { callIfExists(this.props.onInstrumentsReady, instrument); } async playTrack() { const notes = this.props.notes; for (let i = 0; i < notes.length; i += 1) { const currentNote = notes[i]; const { startTimeInMS } = currentNote; const noteTimer = waitAndRun(this.onTimerCall, startTimeInMS, this, currentNote); this.noteTimers.push(noteTimer); } } stopPlayingTrack() { for (let i = 0; i < this.noteTimers.length; i += 1) { clearTimeout(this.noteTimers[i]); } this.noteTimers = []; } renderNotes(uniqueNotes) { const notes = uniqueNotes.map((noteName, i) => { const meta = this.props.meta; const trackIndex = this.props.trackIndex; const instrumentName = this.props.instrumentName || meta.instrumentNames[trackIndex]; return (<Note play={ generateNoteKey(instrumentName, noteName) in isDefined(this.state.playingNotes, {}) } name={sharpToBemol(noteName)} key={i} onStartPlayingNote={this.props.onNotePlayed} onStopPlayingNote={this.props.onNoteStopPlaying} delayPressOut={400} > { this.props.renderNote(instrumentName, sharpToBemol(noteName), i) } </Note>); }); return notes; } render() { const notes = this.props.notes; const meta = this.props.meta; const trackIndex = this.props.trackIndex; const uniqueNotes = MidiIO.getUniqueFromMidiNotes(notes); const instrumentName = this.props.instrumentName || meta.instrumentNames[trackIndex]; return ( <Instrument name={instrumentName} onInstrumentLoaded={this.onInstrumentLoaded} style={this.props.instrumentStyle} > { this.renderNotes(uniqueNotes) // uniqueNotes.map((noteName, i) => ( // <Note // play={ // generateNoteKey(instrumentName, noteName) in isDefined(this.state.playingNotes, {}) // } // name={sharpToBemol(noteName)} // key={i} // onStartPlayingNote={this.props.onNotePlayed} // onStopPlayingNote={this.props.onNoteStopPlaying} // > // { // this.props.renderNote(instrumentName, sharpToBemol(noteName), i) // } // </Note>)) } </Instrument> ); } } MidiTrack.propTypes = { onNotePlayed: PropTypes.func, onNoteStopPlaying: PropTypes.func, notes: PropTypes.arrayOf(PropTypes.shape( { noteNumber: PropTypes.number, noteName: PropTypes.string, startTimeInMS: PropTypes.number, durationInMS: PropTypes.number, endTimeInMS: PropTypes.number, instrumentName: PropTypes.string, deltaTime: PropTypes.number, msPerTick: PropTypes.number, style: View.propTypes.style, }, )), };