36, 38, 40, 42, 44, 46, 48, 50);
/* on French/Belgian keyboards, emulate pad touches with keypresses */
-var KEYBOARD_CODES = Array('a', 'z', 'e', 'r', 't', 'u', 'i', 'o',
+var KEYBOARD_CODES = Array('a', 'z', 'e', 'r', 't', 'y', 'u', 'i',
'q', 's', 'd', 'f', 'g', 'h', 'j', 'k');
var midi = {
console.log('on midi access change', e);
//console.log(this);
var port = e.port;
- var portContainer = $("#midi" + port.type + "s");
- if (portContainer.html().startsWith("<p>No connected")) {
- portContainer.empty();
- }
if (port.state == "disconnected") {
if (port.type == "input") {
} else {
this.outputs[port.name] = undefined;
}
+ if (port.name == 'nanoPAD2 MIDI 1') { $('#devices .nanopad').removeClass('on'); }
+ if (port.name == 'nanoKONTROL2 MIDI 1') { $('#devices .nanokontrol').removeClass('on'); }
} else {
if (port.type == "input") {
if (this.inputs[port.name] === undefined) { this.registerPort(port); }
} else {
if (this.outputs[port.name] === undefined) { this.registerPort(port); }
}
+ console.log('hello:', port.name);
+ if (port.name == 'nanoPAD2 MIDI 1') { $('#devices .nanopad').addClass('on'); }
+ if (port.name == 'nanoKONTROL2 MIDI 1') { $('#devices .nanokontrol').addClass('on'); }
this.renderPort(port);
}
},
self.sample_buffers = Array(16);
self.samples = Array(16);
self.audioCtx = new window.AudioContext();
- self.gainNode = self.audioCtx.createGain();
- self.gainNode.connect(self.audioCtx.destination);
+ self.touchGainNodes = Array(16);
+ self.masterGainNode = self.audioCtx.createGain();
+ for (var i=0; i<16; i++) {
+ self.touchGainNodes[i] = self.audioCtx.createGain();
+ self.touchGainNodes[i].connect(self.masterGainNode);
+ }
+ self.masterGainNode.connect(self.audioCtx.destination);
+
+ self.delay = self.audioCtx.createDelay(maxDelayTime=5);
+ self.delay.delayTime.value = 0.5;
+
+ self.feedback = self.audioCtx.createGain();
+ self.feedback.gain.value = 0.8;
+
+ self.filter = self.audioCtx.createBiquadFilter();
+ self.filter.frequency.value = 1000;
+
+ self.delay.connect(self.feedback);
+ self.feedback.connect(self.filter);
+ self.filter.connect(self.delay);
+
+ self.masterGainNode.connect(self.delay);
}
self.initMIDI = function() {
self.initUI = function() {
var $nanopad = $('#nanopad');
-
- $('.nanotouch input').on('change', function(ev) {
- var nanotouch = $(this).parent();
- var sample_idx = $nanopad.children().index(nanotouch);
- var reader = new FileReader();
- reader.onload = function(e) {
- self.audioCtx.decodeAudioData(this.result, function(buffer) {
- sample_buffers[sample_idx] = buffer;
- $(nanotouch).find('span.duration').text(parseInt(buffer.duration) + 's');
- $(nanotouch).removeClass('error').addClass('loaded');
- }, function(e) {
- $(nanotouch).find('span').text('');
- $(nanotouch).removeClass('loaded').addClass('error');
- });
+ var $nanotouch = $('.nanotouch');
+ for (var i=0; i<16; i++) {
+ var $new_touch = $nanotouch.clone();
+ $new_touch.attr('data-touch', i);
+ $new_touch.appendTo($nanopad);
+ }
+ $nanotouch.remove(); /* remove template */
+
+ $('.nanotouch input[type=file]').on('change', function(ev) {
+ var sample_idx = parseInt($(this).parent().data('touch'));
+ for (var i=0; i<this.files.length; i++) {
+ var reader = new FileReader();
+ var nanotouch = $('.nanotouch')[sample_idx + i];
+ reader.onload = function(e) {
+ var $nanotouch = $(this.nanotouch);
+ var sample_idx = this.sample_idx;
+ self.audioCtx.decodeAudioData(this.result, function(buffer) {
+ sample_buffers[sample_idx] = buffer;
+ $nanotouch.find('span.duration').text(parseInt(buffer.duration) + 's');
+ $nanotouch.removeClass('error').addClass('loaded');
+ }, function(e) {
+ $nanotouch.find('span').text('');
+ $nanotouch.removeClass('loaded').addClass('error');
+ });
+ }
+ reader.nanotouch = nanotouch;
+ reader.sample_idx = sample_idx + i;
+ reader.readAsArrayBuffer(this.files[i]);
+ $(nanotouch).find('span.name').text(this.files[i].name);
}
- reader.readAsArrayBuffer(this.files[0]);
- $(nanotouch).find('span.name').text(this.files[0].name);
});
midi.onTouchOn = function(port, data, sample_idx) {
}
midi.onControlChange = function(port, data, control, value) {
- if (control == 7) {
- $('#gain').val(value).trigger('change');
+ if (control > 7 && control < 16) return; /* range between sliders and pots */
+ if (control > 23) return; /* after pots */
+ if (control < 8) {
+ control += 8; /* sliders, control bottom pads (8-15) */
+ } else {
+ control -= 16; /* pots, control top pads (0-7) */
}
+ $('[data-touch=' + control + '] .touch-gain').val(value).trigger('change');
}
$(document).keypress(function(ev) {
}
});
- $('#gain').on('change', function() {
+ $('#master-gain').on('change', function() {
var fraction = parseInt(this.value) / parseInt(127);
- self.gainNode.gain.value = fraction * fraction;
+ self.masterGainNode.gain.value = fraction * fraction;
+ });
+
+ $('#delay').on('change', function() {
+ var value = this.value;
+ if (value == 0) {
+ self.delay.disconnect();
+ } else {
+ self.delay.delayTime.value = value;
+ self.delay.connect(self.audioCtx.destination);
+ }
+ });
+
+ $('#feedback').on('change', function() {
+ self.feedback.gain.value = this.value;
+ });
+
+ $('#filter').on('change', function() {
+ self.filter.frequency.value = this.value;
+ });
+
+ $('.touch-gain').on('change', function() {
+ var fraction = parseInt(this.value) / parseInt(127);
+ var touchIdx = parseInt($(this).parent().data('touch'));
+ self.touchGainNodes[touchIdx].gain.value = fraction * fraction;
});
}
self.samples[sample_idx] = undefined;
} else {
var sample = self.audioCtx.createBufferSource();
+ var gainNode = self.touchGainNodes[sample_idx];
self.samples[sample_idx] = sample;
sample.loop = false;
sample.connect(gainNode);
sample.buffer = sample_buffer;
sample.onended = function() {
- console.log('ended');
$(nanotouch).removeClass('playing');
self.samples[sample_idx] = undefined;
}
}
$(function() { nanofun(); });
+
+if ('serviceWorker' in navigator) {
+ window.addEventListener('load', function() {
+ navigator.serviceWorker.register('service-worker.js').then(function(registration) {
+ // Registration was successful
+ console.log('ServiceWorker registration successful with scope: ', registration.scope);
+ }).catch(function(err) {
+ // registration failed :(
+ console.log('ServiceWorker registration failed: ', err);
+ });
+ });
+}