]> git.0d.be Git - nanofun.git/blobdiff - nanofun.js
create pads from a template, then delete the template
[nanofun.git] / nanofun.js
index 5794cbe41e64dd28a3e1e16ee6a2083c6f338966..3fd7203ae2a86a4c8bf013364d71b9258e72edc6 100644 (file)
@@ -2,7 +2,7 @@ var NANOPAD_TOUCHS = Array(37, 39, 41, 43, 45, 47, 49, 51,
                            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 = {
@@ -54,10 +54,6 @@ onMIDIAccessChange: function(e) {
     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") {
@@ -65,12 +61,17 @@ onMIDIAccessChange: function(e) {
       } 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);
     }
 },
@@ -296,8 +297,28 @@ var nanofun = function() {
     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() {
@@ -311,23 +332,36 @@ var nanofun = 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) {
@@ -335,9 +369,14 @@ var nanofun = function() {
     }
 
     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) {
@@ -347,9 +386,33 @@ var nanofun = function() {
       }
     });
 
-    $('#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;
     });
   }
 
@@ -362,12 +425,12 @@ var nanofun = function() {
         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;
         }
@@ -384,3 +447,15 @@ var nanofun = function() {
 }
 
 $(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);
+    });
+  });
+}