Created
February 15, 2016 07:42
-
-
Save jussi-kalliokoski/9e6e1fd28c08b973cf2b to your computer and use it in GitHub Desktop.
Web MIDI Streams examples
This file contains hidden or 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
const NOTE = 69; | |
const NOTE_ON = 0x90; | |
const NOTE_OFF = 0x80; | |
const SECONDS = 1000; | |
function startSequencer (destination) { | |
let active = false; | |
setInterval(() => { | |
const now = performance.now(); | |
const type = active ? NOTE_OFF : NOTE_ON; | |
destination.write({ data: [type, NOTE, VELOCITY], timestamp: now }); | |
active = !active; | |
}, 1 * SECONDS); | |
} | |
function handleMIDIError (error) { | |
alert("The MIDI system failed to start. You're gonna have a bad time."); | |
} | |
function handleMIDIReady (midiAccess) { | |
const destination = [...midiAccess.outputs.values()][0]; | |
if ( !destination ) { throw new Error("You don't have any MIDI output devices. You're gonna have a bad time."); } | |
return destination.openAsStream() | |
.then(destinationStream => { | |
startSequencer(destinationStream); | |
}); | |
} | |
window.addEventListener("load", () => { | |
if ( !navigator.requestMIDIAccess ) { | |
alert("No MIDI support in your browser. You're gonna have a bad time."); | |
return; | |
} | |
navigator.requestMIDIAccess() | |
.then(handleMIDIReady, handleMIDIError) | |
.catch(error => alert(error.message)); | |
}); |
This file contains hidden or 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
const OCTAVES = 12; | |
const NOTE_ON = 0x90; | |
const NOTE_OFF = 0x80; | |
const CHANNEL_MASK = 0xF0; | |
function filter (condition) { | |
return new TransformStream({ | |
transform (chunk, enqueue, done) { | |
if ( condition(chunk) ) { enqueue(chunk); } | |
done(); | |
}, | |
}); | |
} | |
function map (transform) { | |
return new TransformStream({ | |
transform (chunk, enqueue, done) { | |
enqueue(transform(chunk)); | |
done(); | |
}, | |
}); | |
} | |
/** | |
* Pushes all messages to given channel number. | |
*/ | |
function pushToChannel (channel) { | |
return map(chunk => { | |
chunk.data &= CHANNEL_MASK; | |
chunk.data += channel; | |
return chunk; | |
}); | |
} | |
function isNoteOnOrNoteOff (chunk) { | |
const messageType = chunk.data[0] & CHANNEL_MASK; | |
return messageType === NOTE_ON || messageType === NOTE_OFF; | |
} | |
function pitchShift (amount) { | |
return map(chunk => { | |
chunk.data[1] += amount; | |
return chunk; | |
}); | |
} | |
function octaver (octaves) { | |
return pitchShift(octaves * OCTAVES); | |
} | |
function prepareConnections (source, destination) { | |
source | |
// move all messages to channel 3 | |
.pipeThrough(pushToChannel(3)) | |
// filter out non-note messages | |
.pipeThrough(filter(isNoteOnOrNoteOff)) | |
// raise the pitch by two octaves | |
.pipeThrough(octaver(2)) | |
// pipe to destination port | |
.pipeTo(destination); | |
} | |
function handleMIDIError (error) { | |
alert("The MIDI system failed to start. You're gonna have a bad time."); | |
} | |
function handleMIDIReady (midiAccess) { | |
const source = [...midiAccess.inputs.values()][0]; | |
const destination = [...midiAccess.outputs.values()][0]; | |
if ( !source ) { throw new Error("You don't have any MIDI input devices. You're gonna have a bad time."); } | |
if ( !destination ) { throw new Error("You don't have any MIDI output devices. You're gonna have a bad time."); } | |
return Promise.all([ | |
source.openAsStream(), | |
// Hold a FIFO queue of 1000 items | |
destination.openAsStream(new CountQueuingStrategy({ highWaterMark: 1000 })), | |
]) | |
.then(([sourceStream, destinationStream]) => { | |
prepareConnections(sourceStream, destinationStream); | |
}); | |
} | |
window.addEventListener("load", () => { | |
if ( !navigator.requestMIDIAccess ) { | |
alert("No MIDI support in your browser. You're gonna have a bad time."); | |
return; | |
} | |
navigator.requestMIDIAccess() | |
.then(handleMIDIReady, handleMIDIError) | |
.catch(error => alert(error.data)); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment