Skip to content

Instantly share code, notes, and snippets.

@softpunch
Last active July 29, 2017 00:48
Show Gist options
  • Save softpunch/9a4c760069f44f6635eee42e5dc56fa9 to your computer and use it in GitHub Desktop.
Save softpunch/9a4c760069f44f6635eee42e5dc56fa9 to your computer and use it in GitHub Desktop.
WebMIDI vars & functions (WIP)
//
// useful WebMIDI variables and functions
//
//
// Chrome only; no iOS; does *not* incorporate shims
//
// Initialize WebMidi; create dropdown selector for output port
//
// HTML component:
// <select id="outputSelector" onchange="updatePort()">
// <option value="null" selected>[none]</option>
// </select>
//
// access output selector
var outputSelector = document.querySelector('#outputSelector');
// empty var to hold "midiAccess"
var midi;
// empty var to hold selected MIDI output port ID
var mOutPort;
// initialize WebMIDI
function onMIDISuccess( midiAccess ) {
midi = midiAccess;
midi.outputs.forEach(
function(port, key) {
var portName = port.name;
var portID = port.id;
var option = document.createElement("option");
option.setAttribute("value", portID);
var textNode = document.createTextNode(portName);
option.appendChild(textNode);
outputSelector.appendChild(option);
});
}
navigator.requestMIDIAccess().then(onMIDISuccess);
// define output port upon selection
function updatePort() {
var i = outputSelector.selectedIndex;
mOutPort = outputSelector.options[i].value;
}
//
// create Web Audio context for access to more convenient timing functions
//
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext();
// set latency hint; conditional feature detection to prevent errors
if ("latencyHint" in audioContext) {
audioContext.latencyHint = "playback";
};
// define current time
var now = audioContext.currentTime;
// additional basic web audio variables
// var baseFreq = 440;
// var audioOut = audioContext.destination;
//
// useful midi variables
//
// set output channel
var midiChannel = 1; // 1-16
// define commands
// var noteOn = 0x90 + (midiChannel - 1);
// define tempo
var midiTempo = 120;
// define (note) pitches
// see note name to MIDI number conversion here:
// https://github.com/sole/MIDIUtils/blob/master/src/MIDIUtils.js
//
// additional note/frequency conversion algorithms:
// https://github.com/sole/MIDIUtils
// define velocities
var maxVel = 127;
var midVel = 64;
var muteVel = 0;
// define durations
// n4 = quarter note; t4 = quarter-note triplet; m4 = four measures
// timing in ms (60000 = 60s)
var n4 = (60000 / midiTempo);
var n1 = n4 * 4;
var n2 = n4 * 2;
var n8 = n4 / 2;
var n16 = n4 / 4;
var n32 = n4 / 8;
var t4 = (40000 / midiTempo);
var t2 = t4 * 2;
var t8 = t4 / 2;
var t16 = t4 / 4;
var t32 = t4 / 8;
var m1 = n4 * 4;
var m2 = m1 * 2;
var m4 = m1 * 4;
var m8 = m1 * 8;
// add dotted durations?
//
// define midi messages; [command, data1, data2]
// var midiNoteBegin = [noteOn, midiNote, midiVel];
// var midiNoteEnd = [noteOn, midiNote, midiVel];
// midi -- single note function
function sendMidiNote( note, vel, dur ) {
var noteOn = 0x90 + (midiChannel - 1);
var noteOff = 0x80 + (midiChannel - 1);
var midiNoteBegin = [noteOn, note, vel];
var midiNoteEnd = [noteOff, note, muteVel];
var midiNoteEndAlt = [noteOn, note, muteVel];
var output = midi.outputs.get(mOutPort);
output.send(midiNoteBegin);
output.send(midiNoteEnd, now + dur);
//
// optionally include a safety margin/buffer;
// var safety = 150; // 150ms
//
// output.send(midiNoteBegin, now + safety);
// output.send(midiNoteEnd, now + safety + dur);
//
}
// use above function with MIDI note number, velocity (0-127), and duration;
// example -- A4 (440Hz), quarter note, at a velocity of 127,
// sendMidiNote(69, maxVel, n4);
//
// TODO fundamentals:
// add more MIDI commands;
// add clock input/output;
// add queue/scheduler (via Tale of Two Clocks);
// add chord player function;
// add scale creator w/ MIDI pitches/notes;
// add roman numeral chord progression vars;
// add (global) chord progression player;
// add melody generator/arpeggiator;
// add chord comp generator;
// add bassline generator;
// add polyrhythm creator;
// add composition-structure manager;
// add chaining methods;
// add percussion player;
// add percussion generator/controller;
// add LFO(s);
// add more durations;
// add MIDI tuning adjuster;
// add MIDI-to-freq func;
// add method to create html dropdown component in js;
//
// TODO abstractions:
// reich pulse (w/ volume swells)
// drone gen
// "black midi"
// interlocking gens
// CC controllers/gens
// game of life
// stats-based gens
// buffer manipulation via midi
// midi jitter-er (input/output)
// hyper-fast, super-quiet, pseudo-pads
// responsive methods -- ie chord gens that dynamically react to external impetus
//
// random value generator
// The returned value is no lower than (and may possibly equal) min,
// and is less than (but not equal to) max.
function randRange(min, max) {
return Math.random() * (max - min) + min;
}
// optional functions to convert frequencies to MIDI notes
// log function for MIDI converstion
function getBaseLog(value, base) {
return Math.log(value) / Math.log(base);
}
// Frequency to Midi Note Number
function freqNote(f) {
return Math.round(12.0 * getBaseLog(f / baseFreq, 2) + 69);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment