midi everything!

hacking web midi to do silly stuff

by gregor

HTML

<div class="wrapper block">
  <div id="test-controls" class="centered">
    <label>bend
      <input type="range" min="0" max="127" value="64" id="bend-control" />
    </label>
    <label>mod
      <input type="range" min="0" max="127" value="0" id="mod-control" />
    </label>
    <label></label>
    <label>fader
      <!-- <input type="range" min="0" max="127" value="0" id="fader-control" /> -->
      <input type="range" min="0" max="127" value="127" id="fader-control" />
    </label>
  </div>
</div>
<div class="fake-height"></div>

CSS

body {
  margin: 0;
  padding: 0;
  font: bold 12px/3 sans-serif;
  letter-spacing: 1.5px;
  color: #999;
  /* default state */
  /* opacity: 0; */
  /*
  background-image: url('http://subtlepatterns.com/patterns/crissXcross.png');
  background-image: url('http://subtlepatterns2015.subtlepatterns.netdna-cdn.com/patterns/footer_lodyas.png');
  */
  background-image: url('http://subtlepatterns2015.subtlepatterns.netdna-cdn.com/patterns/sativa.png');
}

.wrapper {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.fake-height {
  width: 1px;
  height: 10000px;
}

#test-controls {}

#test-controls label,
#test-controls input {
  width: 50px;
  height: 100px;
  margin: 0;
  padding: 0;
}

#test-controls label {
  float: left;
  text-align: center;
}

#bend-control,
#mod-control,
#fader-control {
  -webkit-appearance: slider-vertical;
  writing-mode: bt-lr;
}

.block {
  text-align: center;
  white-space: nowrap;
}

.block:before {
  content: '';
  display: inline-block;
  height: 100%;
  vertical-align: middle;
  margin-right: -0.25em;
}

.centered {
  display: inline-block;
  vertical-align: middle;
  white-space: normal;
}

JavaScript

var log = console.log.bind(console),
  testControlsEl = document.getElementById('test-controls'),
  bendControlEl = document.getElementById('bend-control'),
  modControlEl = document.getElementById('mod-control'),
  faderControlEl = document.getElementById('fader-control');
var midi, bendIntervalId;
var data, cmd, channel, type, note, velocity;
var tickScrollDistance = 10;

// element binding

bendControlEl.addEventListener('input', function(e) {
  onBend(bendControlEl.value);
});

modControlEl.addEventListener('input', function(e) {
  onMod(modControlEl.value);
});

faderControlEl.addEventListener('input', function(e) {
  onFader(faderControlEl.value);
});

// simulate the physical control:
// jump to middle position when leaving mouse button on the bend slider
document.addEventListener('mouseup', function(e) {
  if (e.target === bendControlEl) {
    onBend(bendControlEl.value = 64);
  }
})


// request MIDI access

if (navigator.requestMIDIAccess) {
  navigator.requestMIDIAccess({
    sysex: false
  }).then(onMIDISuccess, onMIDIFailure);
} else {
  alert("No MIDI support in your browser.");
}


// midi functions

function onMIDISuccess(midiAccess) {
  midi = midiAccess;
  var inputs = midi.inputs.values();
  for (var input = inputs.next(); input && !input.done; input = inputs.next()) {
    input.value.onmidimessage = onMIDIMessage;
  }
  midi.onstatechange = onStateChange;
}

function onMIDIMessage(event) {
  data = event.data,
    cmd = data[0] >> 4,
    channel = data[0] & 0xf,
    type = data[0] & 0xf0, // channel agnostic message type. Thanks, Phil Burk.
    note = data[1],
    velocity = data[2];

  switch (type) {
    case 144: // note on 
      switch (note) {
        case 48: // C-4
          midiMessageDecorator(onKeyC4, null, velocity);
          break;
      }
      break;
    case 128: // note off 
      break;
    case 224: // pitch bend
      midiMessageDecorator(onBend, bendControlEl, velocity);
      break;
    case 176: // faders, knobs,...