Slide 1

Slide 1 text

Web Launchpad

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

eatcodetravel.com orlando @ github @eatcodetravel

Slide 4

Slide 4 text

Web Launchpad

Slide 5

Slide 5 text

Web MIDI Web Audio Launchpad

Slide 6

Slide 6 text

Web MIDI Web Audio Launchpad

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

80 buttons 3 leds 4 channels

Slide 9

Slide 9 text

Web MIDI Web Audio Launchpad

Slide 10

Slide 10 text

Web MIDI Web Audio Launchpad

Slide 11

Slide 11 text

Midi SamplePlayer SamplePackStore UIMapper PubSub

Slide 12

Slide 12 text

SamplePlayer SamplePackStore UIMapper PubSub Midi

Slide 13

Slide 13 text

Web Audio Launchpad Web MIDI

Slide 14

Slide 14 text

and Opera

Slide 15

Slide 15 text

Inputs / Outputs

Slide 16

Slide 16 text

How do we use it?

Slide 17

Slide 17 text

20 _initMidi: function () { 21 navigator.requestMIDIAccess({ 22 sysex: false 23 }).then(this._onMidiSuccessHandler); 24 }, 25 26 _onMidiMessageHandler: function _onMidiMessageHandler(message) { 27 console.log(message.data); 28 PubSub.emitEvent('onMidiMessage', [message]); 29 }, 30 31 _onMidiSuccessHandler: function _onMidiSuccessHandler(midi) { 32 var inputs = midi.inputs.values(); 33 // loop over all available inputs and listen for any MIDI input 34 for (var input = inputs.next(); input && !input.done; input = inputs.next()) { 35 // each time there is a midi message call the onMIDIMessage function 36 input.value.onmidimessage = this._onMidiMessageHandler; 37 }

Slide 18

Slide 18 text

20 _initMidi: function () { 21 navigator.requestMIDIAccess({ 22 sysex: false 23 }).then(this._onMidiSuccessHandler); 24 }, 25 26 _onMidiMessageHandler: 27 28 PubSub.emitEvent( 29 }, 30 31 _onMidiSuccessHandler: 32 33 // loop over all available inputs and listen for any MIDI input 34 inputs.next()) { 35 // each time there is a midi message call the onMIDIMessage function 36 input.value.onmidimessage 37 }

Slide 19

Slide 19 text

31 _onMidiSuccessHandler: function _onMidiSuccessHandler(midi) { 32 var inputs = midi.inputs.values(); 33 // loop over all available inputs and listen for any MIDI input 34 for (var input = inputs.next(); input && !input.done; input = inputs.next()) { 35 // each time there is a midi message call the onMIDIMessage function 36 input.value.onmidimessage = this._onMidiMessageHandler; 37 } 20 _initMidi: 21 navigator.requestMIDIAccess({ 22 23 }).then( 24 }, 25 26 _onMidiMessageHandler: 27 28 PubSub.emitEvent( 29 }, 30

Slide 20

Slide 20 text

20 _initMidi: 21 navigator.requestMIDIAccess({ 22 23 }).then( 24 }, 25 30 31 _onMidiSuccessHandler: 32 33 // loop over all available inputs and listen for any MIDI input 34 inputs.next()) { 35 // each time there is a midi message call the onMIDIMessage function 36 input.value.onmidimessage 37 } 26 _onMidiMessageHandler: function _onMidiMessageHandler(message) { 27 console.log(message.data); 28 PubSub.emitEvent('onMidiMessage', [message]); 29 },

Slide 21

Slide 21 text

[144, 48, 127]

Slide 22

Slide 22 text

[144, 48, 127] Command or Channel Note Velocity

Slide 23

Slide 23 text

[144, 48, 127] 127

Slide 24

Slide 24 text

[144, 48, ] 0

Slide 25

Slide 25 text

Web MIDI Launchpad Web Audio

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Web Audio

Slide 28

Slide 28 text

How do we use it?

Slide 29

Slide 29 text

Midi SamplePackStore UIMapper PubSub SamplePlayer

Slide 30

Slide 30 text

1 (function () { 2 var SamplePlayer = function SamplePlayer(config) { 3 this.init(config); 4 }; 5 6 SamplePlayer.prototype = Object.create(Base); 7 8 Object.assign(SamplePlayer.prototype, { 9 events: { 10 'onMidiMessage': '_onMidiMessageHandler', 11 'samplePackChange': '_loadSamples' 12 }, 13 samplePackName: null, 14 samples: null, 15 buffers: null, 16 17 init: function init(config) { 18 this._bindAll(); 19 this.samples = {}; 20 this.buffers = {}; 21 this.audioContext = new AudioContext(); 22 this._loadSamples(SamplePackStore.activeSamplePack); 23 this._listenEvents(); 24 }, 25

Slide 31

Slide 31 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 21 this.audioContext = new AudioContext();

Slide 32

Slide 32 text

AudioContext

Slide 33

Slide 33 text

.createBuffer() .createBufferSource() .decodeAudioData() .createStereoPanner() .createAnalyser() .createBiquadFilter()

Slide 34

Slide 34 text

.createStereoPanner() .createAnalyser() .createBiquadFilter() .createBuffer() .createBufferSource() .decodeAudioData()

Slide 35

Slide 35 text

1 (function () { 2 var SamplePackStore = window.SamplePackStore = Object.create({}); 3 4 Object.assign(SamplePackStore, { 5 samplePacks: {}, 6 samplePacksData: {}, 7 activeSamplePack: null, 8 set: function set(key) { 9 if (this.samplePacks[key]) { 10 this.activeSamplePack = this.samplePacks[key]; 11 PubSub.emitEvent('samplePackChange', [{name: key, data: this.activeSamplePack}]); 12 } 13 } 14 }); 15 16 SamplePackStore.samplePacks.firstOfTheYear = { 17 48: '/samples/firstyear/kick1.wav', 18 49: '/samples/firstyear/freeze1.wav', 19 50: '/samples/firstyear/freeze2.wav', 20 51: '/samples/firstyear/freeze3.wav', 21 33: '/samples/firstyear/freeze4.wav', 22 34: '/samples/firstyear/freeze5.wav', 23 35: '/samples/firstyear/freeze6.wav', 24 17: '/samples/firstyear/freeze7.wav', 25 18: '/samples/firstyear/freeze8.wav', 26 19: '/samples/firstyear/freeze9.wav', 27 2: '/samples/firstyear/freeze10.wav',

Slide 36

Slide 36 text

1 (function () { 2 var SamplePlayer = function SamplePlayer(config) { 3 this.init(config); 4 }; 5 6 SamplePlayer.prototype = Object.create(Base); 7 8 Object.assign(SamplePlayer.prototype, { 9 events: { 10 'onMidiMessage': '_onMidiMessageHandler', 11 'samplePackChange': '_loadSamples' 12 }, 13 samplePackName: null, 14 samples: null, 15 buffers: null, 16 17 init: function init(config) { 18 this._bindAll(); 19 this.samples = {}; 20 this.buffers = {}; 21 this.audioContext = new AudioContext(); 22 this._loadSamples(SamplePackStore.activeSamplePack); 23 this._listenEvents(); 24 }, 25 26 _loadSamples: function _loadSamples(samplePack) { 27 var samplePlayer = this; 28 var name = this.samplePackName = samplePack.name; 29 var data = samplePack.data;

Slide 37

Slide 37 text

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 22 this._loadSamples(SamplePackStore.activeSamplePack);

Slide 38

Slide 38 text

26 _loadSamples: function _loadSamples(samplePack) { 27 var samplePlayer = this; 28 var name = this.samplePackName = samplePack.name; 29 var data = samplePack.data; 30 var urls = []; 31 32 if (this.samples[name]) { 33 return this.samples[name]; 34 } 35 36 this.samples[name] = {}; 37 this.buffers[name] = {}; 38 39 Object.keys(data).forEach(function (key) { 40 var url = data[key]; 41 urls.push(url); 42 }); 43 44 new BufferLoader(this.audioContext, urls, function (bufferList) { 45 var keys = Object.keys(data); 46 47 keys.forEach(function (key, index) { 48 var buffer = bufferList[index]; 49 50 // Store the buffer to use it later 51 samplePlayer.buffers[name][key] = buffer; 52 }); 53 }).load(); 54 },

Slide 39

Slide 39 text

1 _onMidiMessageHandler: function _onMidiMessageHandler(message) { 2 var data = message.data; 3 4 var key = data[1]; 5 var command = data[2]; 6 7 var samplePackName = this.samplePackName; 8 9 if (command === 127) { 10 var buffer = this.buffers[samplePackName][key]; 11 12 if (buffer) { 13 var sample = this._createNode(buffer, this.loop); 14 this.samples[samplePackName][key] = sample; 15 16 sample.start(0); 17 } 18 19 this._ledOn(key, 'green', true); 20 } else { 21 var sample = this.samples[samplePackName][key]; 22 23 sample && sample.stop(0); 24 25 this._ledOff(key); 26 } 27 },

Slide 40

Slide 40 text

81 82 _createNode: function (buffer) { 83 var node = this.audioContext.createBufferSource(); 84 node.buffer = buffer; 85 node.connect(this.audioContext.destination); 86 87 return node; 88 }, 89 90 _ledOn: function _ledOn(key, color, full) { 91 PubSub.emitEvent('ledOn', [key, color, full]); 92 }, 93 94 _ledOff: function _ledOff(key) { 95 PubSub.emitEvent('ledOff', [key]); 96 } 97 }); 98 99 window.SamplePlayer = SamplePlayer; 100 }());

Slide 41

Slide 41 text

Demo

Slide 42

Slide 42 text

Resources

Slide 43

Slide 43 text

orlando/web-launchpad html5rocks.com developer.mozilla.org splice.com

Slide 44

Slide 44 text

Thanks!

Slide 45

Slide 45 text

QA

Slide 46

Slide 46 text

%