-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
383 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>SoundCloud React Redux App</title> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
<script src="bundle.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "keysight2", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "webpack-dev-server --progress --colors --hot --config ./webpack.config.js", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"babel": { | ||
"presets": [ | ||
"es2015", | ||
"react", | ||
"stage-2" | ||
] | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.9.1", | ||
"babel-loader": "^6.2.4", | ||
"babel-preset-es2015": "^6.9.0", | ||
"babel-preset-react": "^6.5.0", | ||
"babel-preset-stage-2": "^6.5.0", | ||
"less": "^2.7.1", | ||
"less-loader": "^2.2.3", | ||
"react-bootstrap": "^0.29.5", | ||
"react-hot-loader": "^1.3.0", | ||
"style-loader": "^0.13.1", | ||
"teoria": "^2.2.0", | ||
"webpack": "^1.13.1", | ||
"webpack-dev-server": "^1.14.1" | ||
}, | ||
"dependencies": { | ||
"midi": "github:mudcube/MIDI.js", | ||
"react": "^15.1.0", | ||
"react-dom": "^15.1.0", | ||
"react-redux": "^4.4.5", | ||
"redux": "^3.5.2", | ||
"redux-logger": "^2.6.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
import { gotMidiEvent } from './midi'; | ||
|
||
export { | ||
gotMidiEvent | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import * as actionTypes from '../constants/actionTypes'; | ||
|
||
export function gotMidiEvent(midiEvent) { | ||
return { | ||
type: actionTypes.MIDI_EVENT, | ||
midiEvent | ||
}; | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react'; | ||
|
||
function Container(){ | ||
return ( | ||
<div>HELLO4!</div> | ||
); | ||
} | ||
|
||
export default Container; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from 'react'; | ||
import { connect } from 'react-redux'; | ||
|
||
|
||
class ExampleComponent extends React.Component { | ||
constructor() { | ||
super(); | ||
this. _handleClick = this. _handleClick.bind(this); | ||
} | ||
|
||
render() { | ||
return <div onClick={this._handleClick}>Hello, world.</div>; | ||
} | ||
_handleClick() { | ||
console.log(this); // this is undefined | ||
} | ||
} | ||
|
||
|
||
export default ExampleComponent; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const MIDI_EVENT = 'MIDI_EVENT'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React from 'react'; | ||
import RaisedButton from 'material-ui/RaisedButton'; | ||
import ReactDOM from 'react-dom'; | ||
import Container from './components/Container'; | ||
import getMuiTheme from 'material-ui/styles/getMuiTheme'; | ||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; | ||
import { Provider } from 'react-redux'; | ||
import ThemeManager from 'material-ui/styles/ThemeManager'; | ||
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme'; | ||
import {MidiEventDebuggerDisplay, getMidiData, midiSetup} from './midihandler'; | ||
import configureStore from './stores/configureStore'; | ||
import * as actions from './actions'; | ||
import {Synth} from './synth'; | ||
|
||
|
||
const store = configureStore(); | ||
function init() { | ||
// Create a list of callbacks that we can push to. Each time a midi event is | ||
// received, we broadcast the event to all the callbacks in the list. | ||
let midiCallbacks = [ (x) => {store.dispatch(actions.gotMidiEvent(x))} ] | ||
|
||
try { | ||
// Fix up for prefixing | ||
window.AudioContext = window.AudioContext||window.webkitAudioContext; | ||
let soundGen = new Synth(new AudioContext()); | ||
midiCallbacks.push((e) => {soundGen.handleMidiEvent(e)}) | ||
} | ||
catch(e) { | ||
console.log('Web Audio API is not supported in this browser', e); | ||
} | ||
|
||
midiSetup((event) => { | ||
for(let cb of midiCallbacks){ | ||
console.log("calling!", cb) | ||
cb(event) | ||
} | ||
}) | ||
} | ||
|
||
window.addEventListener('load', init, false); | ||
|
||
ReactDOM.render( | ||
<div> | ||
<Provider store={store}> | ||
<MidiEventDebuggerDisplay/> | ||
</Provider> | ||
</div>, | ||
document.getElementById('app') | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { connect } from 'react-redux' | ||
import React from 'react'; | ||
export const EVENT_NOTEOFF = "Note Off"; | ||
export const EVENT_NOTEON = "Note On"; | ||
export const EVENT_SUSTAIN = "Sustain"; | ||
export const EVENT_Expr = "Expression"; | ||
|
||
export function midiSetup(callback) { | ||
if (navigator.requestMIDIAccess) { | ||
navigator.requestMIDIAccess({sysex:false}).then(function(midiAccess){ | ||
let midi = midiAccess; | ||
let inputs = midi.inputs.values(); | ||
for (let input = inputs.next(); input && !input.done; input = inputs.next()) { | ||
input.value.onmidimessage = (message) => callback(message) | ||
} | ||
}, function(){ | ||
throw Exception("No access to MIDI devices or your browser doesn't support WebMIDI API. Please use WebMIDIAPIShim:"+e); | ||
}); | ||
} else { | ||
throw Exception("No MIDI support in your browser."); | ||
} | ||
} | ||
|
||
export function getMidiData(data){ | ||
let scaleMap = [ 'C', 'C♯', 'D', 'E♭', 'E', 'F', 'F♯', 'G', 'A♭', 'A', 'B♭', 'B' ] | ||
let retVal = {} | ||
|
||
if (data[0] >= 128 && data[0] <= 159) { | ||
retVal.velocity = data[2]; | ||
retVal.note = data[1]; | ||
retVal.letter = scaleMap[data[1] % 12]; | ||
retVal.octave = Math.floor(data[1] / 12); | ||
} | ||
|
||
if (data[0] >= 128 && data[0] <= 143) { | ||
retVal.event = EVENT_NOTEOFF; | ||
} | ||
if (data[0] >= 144 && data[0] <= 159) { | ||
retVal.event = EVENT_NOTEON; | ||
} | ||
if (data[0] === 185) { | ||
if (data[1] === 11) { | ||
retVal.event = EVENT_EXPR; | ||
} | ||
if (data[1] === 64) { | ||
retVal.event = EVENT_SUSTAIN; | ||
} | ||
} | ||
if (data[0] === 185 && data[1] === 11) { | ||
retVal.event = EVENT_EXPR; | ||
} | ||
return retVal; | ||
} | ||
|
||
let midiStateDisplay = function({midi = {}}){ | ||
return ( | ||
<div>hi {midi.notes}</div> | ||
) | ||
} | ||
|
||
function mapStateToProps(state) { | ||
const midi = state.midi; | ||
return { | ||
midi | ||
} | ||
} | ||
|
||
|
||
const MidiEventDebuggerDisplay = connect(mapStateToProps)(midiStateDisplay) | ||
|
||
export {MidiEventDebuggerDisplay} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { combineReducers } from 'redux'; | ||
import midi from './midi'; | ||
|
||
export default combineReducers({ | ||
midi | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as actionTypes from '../constants/actionTypes'; | ||
import * as midihandler from '../midihandler' | ||
|
||
const initialState = {notes:new Set()}; | ||
|
||
export default function(state = initialState, action) { | ||
switch (action.type) { | ||
case actionTypes.MIDI_EVENT: | ||
return updateMidiState(state, action); | ||
} | ||
return state; | ||
} | ||
|
||
function updateMidiState(state, action) { | ||
let noteSet = new Set(state.notes.values()) | ||
let parsedMidi = midihandler.getMidiData(action.midiEvent.data) | ||
let noteKey = `${parsedMidi.letter}${parsedMidi.octave}` | ||
if(parsedMidi.event == midihandler.EVENT_NOTEOFF){ | ||
noteSet.delete(noteKey) | ||
}else if (parsedMidi.event == midihandler.EVENT_NOTEON){ | ||
noteSet.add(noteKey) | ||
} | ||
return {notes:noteSet}; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { createStore, applyMiddleware } from 'redux'; | ||
import createLogger from 'redux-logger'; | ||
import rootReducer from '../reducers/index'; | ||
|
||
const logger = createLogger(); | ||
|
||
const createStoreWithMiddleware = applyMiddleware(logger)(createStore); | ||
|
||
export default function configureStore(initialState) { | ||
return createStoreWithMiddleware(rootReducer, initialState); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import * as midihandler from '../midihandler' | ||
|
||
let noteNumToFreq = (note) => 440 * Math.pow(2,(note-69)/12); | ||
|
||
const waveforms = ["sine","square","sawtooth","triangle"]; | ||
|
||
// TODO: make these non-constants! | ||
const PORTAMENTO = 0.05; | ||
const ATTACK = 0.05; | ||
const RELEASE = 0.05; | ||
const PITCHWHEEL = 0.0; | ||
|
||
class Synth { | ||
constructor(context){ | ||
this.context = context; | ||
this.activeNotes = {}; | ||
} | ||
|
||
noteOn(noteNum){ | ||
let voice = new Voice(this.context, noteNum) | ||
voice.on() | ||
this.activeNotes[noteNum] = voice | ||
} | ||
|
||
noteOff(noteNum){ | ||
let voice = this.activeNotes[noteNum] | ||
if(voice){ | ||
voice.off() | ||
} | ||
} | ||
|
||
handleMidiEvent(event){ | ||
console.log("synth handling midi event!", event) | ||
let parsedMidi = midihandler.getMidiData(event.data) | ||
if(parsedMidi.event == midihandler.EVENT_NOTEOFF){ | ||
this.noteOff(parsedMidi.note) | ||
}else if (parsedMidi.event == midihandler.EVENT_NOTEON){ | ||
this.noteOn(parsedMidi.note) | ||
}else{ | ||
console.log("doing whatever ", parsedMidi.event) | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
class Voice{ | ||
constructor(context, note){ | ||
this.note = note | ||
let baseFreq = noteNumToFreq(note) | ||
// set up the basic oscillator chain, muted to begin with. | ||
this.oscillator = context.createOscillator(); | ||
this.oscillator.frequency.setValueAtTime(baseFreq, 0); | ||
this.envelope = context.createGain(); | ||
this.oscillator.connect(this.envelope); | ||
this.envelope.connect(context.destination); | ||
this.envelope.gain.value = 0.0; // Mute the sound | ||
this.oscillator.start(0); // Go ahead and start up the oscillator | ||
} | ||
|
||
on() { | ||
this.oscillator.frequency.cancelScheduledValues(0); | ||
this.oscillator.frequency.setTargetAtTime(noteNumToFreq(this.note), 0, PORTAMENTO); | ||
this.envelope.gain.cancelScheduledValues(0); | ||
this.envelope.gain.setTargetAtTime(1.0, 0, ATTACK); | ||
} | ||
off(){ | ||
this.envelope.gain.cancelScheduledValues(0); | ||
this.envelope.gain.setTargetAtTime(0.0, 0, RELEASE ); | ||
this.oscillator.frequency.cancelScheduledValues(0); | ||
this.oscillator.frequency.setTargetAtTime( noteNumToFreq(this.note), 0, PORTAMENTO ); | ||
} | ||
} | ||
|
||
export {Synth} |
Oops, something went wrong.