JSFiddle - React, Tailwind, and code Playground

by Arto Chydenius

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
<div class="chilicorn"></div>

CSS

.chilicorn {
  background: url('http://spiceprogram.org/assets/img/logo/chilicorn_no_text-512.png') center center no-repeat;
  width: 512px;
  height: 512px;
}

JavaScript

'use strict';

// Convert the promise to Observable, select the first input device and get stream of messages
const inputStream = Rx.Observable.fromPromise(navigator.requestMIDIAccess())
  .map(midi => midi.inputs.values().next().value)
  .flatMap(input => midimessageAsObservable(input))
  .map(message => parseEvent(message));

const noteOnEvent = 144;
const firstPadNote = 36;
const controlEvent = 176;
const firstKnobIndex = 1;

const padStream = inputStream
  .filter(x => x.status === noteOnEvent)
  .filter(x => x.data[0] === firstPadNote);

const controlStream = inputStream
  .filter(x => x.status === controlEvent)
  .filter(x => x.data[0] === firstKnobIndex);

const tapTempoStream = padStream
  .timeInterval()
  .skip(1)
  .map(x => msToBpm(x.interval))
  .filter(x => x > 40);

const knobTempoStream = controlStream
  .map(x => x.data[1])	
  .map(x => Math.round(x / 127 * 200));

const tempoStream = tapTempoStream.merge(knobTempoStream);

tempoStream.subscribe(bpm => {
	console.log(bpm);
  // chilicornEffect.setBpm(bpm);
});

function parseEvent(event) {
  return {
    status: event.data[0] & 0xf0,
    data: [
      event.data[1],
      event.data[2]
    ]
  };
}

// Convert millisecond time to beats per minute
function msToBpm(ms) {
	console.log('ms: ' + ms);
  return Math.round(60000 / ms);
}

/* chilicornEffect */

const chilicornEffect = (function() {
	const fps = 100;
	let phase = 0;
	let bpm = 0;

  setInterval(() => {
    const scale = Math.sin(Math.PI * 2 / fps * phase * bpm / 60) * 0.25 + 0.75;
    const size = scale * 512;
    document.querySelector('.chilicorn').style.backgroundSize = `${size}px`;

    phase++;
  }, 1000 / fps);

	return {
  	setBpm: function(x) {
    	bpm = x;
    }
  };
})();

chilicornEffect.setBpm(60);

/* rxjs-web-midi */
function midimessageAsObservable(input) {
    return createObservable(input, 'onmidimessage');
}

function statechangeAsObservable(midi) {
    return createObservable(midi, 'onstatechange');
}

function...