Advertisement
Guest User

JamAudio

a guest
Sep 8th, 2011
619
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var JamSynth;
  2. var JamKit;
  3. var JamKitBox;
  4. var JamScorePlayer;
  5.  
  6. (function()
  7. {
  8.     function constructStandardKitList(folder)
  9.     {
  10.         var toReturn = [];
  11.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/hihat.wav");
  12.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/kick.wav");
  13.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/snare.wav");
  14.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/tom1.wav");
  15.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/tom2.wav");
  16.         toReturn.push("/static/js/JamAudio/samples/" + folder + "/tom3.wav");
  17.         return toReturn;
  18.     }
  19.    
  20.     var kitLoops =  {
  21.         "acoustic": constructStandardKitList("acoustic"),
  22.         "techno": constructStandardKitList("Techno"),
  23.         "R8": constructStandardKitList("R8"),
  24.         "bongos": constructStandardKitList("Bongos")
  25.     };
  26.    
  27.     console.log(kitLoops);
  28.    
  29.     var Synth = Class.$extend(
  30.     {
  31.         __init__: function(context, sampleRate, numChannels)
  32.         {
  33.             sampleRate || (sampleRate = 44100);
  34.             numChannels || (numChannels = 2);
  35.             this.sample_rate(sampleRate);
  36.             this.num_channels(numChannels);
  37.             this._dsp = new signalProcessor();
  38.             context ? this._context = context : this._context = new webkitAudioContext();
  39.             this._masterGainNode = this._context.createGainNode();
  40.             this._masterGainNode.gain.value = 0.7;
  41.             this._masterGainNode.connect(this._context.destination);
  42.             this._compressor = this._context.createDynamicsCompressor();
  43.             this._compressor.connect(this._masterGainNode);
  44.             this._convolver = this._context.createConvolver();
  45.             this._convolver.connect(this._masterGainNode);
  46.         },
  47.        
  48.         playNote: function(noteName, numSecs, gain, convolutions)
  49.         {
  50.             return this.playHertz(this._getHertz(noteName), numSecs, gain, convolutions);
  51.         },
  52.        
  53.         playHertz: function(hertz, numSecs, gain, convolutions)
  54.         {
  55.             numSecs || (numSecs = 1);
  56.       gain || (gain = 1);
  57.             (g = ((hertz < 200) ? 3 :
  58.             (hertz < 600) ? 1.5 :
  59.             (hertz < 800) ? 1 : 0.7));
  60.       gain = g * gain;
  61.       console.log(gain);
  62.  
  63.             var source = this._context.createBufferSource();
  64.       multiple = 0;
  65.       while(multiple < 42000) multiple += hertz;
  66.       framelen = numSecs > 0 ? numSecs * multiple: multiple;
  67.             sample = multiple;
  68.  
  69.       source.buffer = this._context.createBuffer(this.num_channels(), framelen, sample );
  70.             var osc = new this._dsp.Oscillator(this._dsp.SINE, hertz, gain, framelen, sample );
  71.             osc.generate();
  72.  
  73.             for(var i = 0; i < this.num_channels(); ++i)
  74.             {
  75.                 source.buffer.getChannelData(i).set(osc.signal);
  76.             }
  77.            
  78.             var filter = this._context.createBiquadFilter();
  79.             filter.frequency.value = 22050;
  80.             filter.Q.value = 5;
  81.             source.connect(filter);
  82.            
  83.             var dryGainNode = this._context.createGainNode();
  84.             dryGainNode.gain.value = gain;
  85.             filter.connect(dryGainNode);
  86.             dryGainNode.connect(this._compressor);
  87.            
  88.             var wetGainNode = this._context.createGainNode();
  89.             wetGainNode.gain.value = gain;
  90.             filter.connect(wetGainNode);
  91.             wetGainNode.connect(this._convolver);
  92.            
  93.             if(numSecs < 0) source.looping = true;
  94.             source.noteOn(0);
  95.             var obj = {};
  96.             obj._source = source;
  97.             obj.stop = function() { this._source.noteOff(0); };
  98.             return obj;
  99.         },
  100.        
  101.         _getHertz: function(noteName)
  102.         {
  103.             var noteTable = { "G9": 0x7F, "Gb9": 0x7E, "F9": 0x7D, "E9": 0x7C, "Eb9": 0x7B,
  104.             "D9": 0x7A, "Db9": 0x79, "C9": 0x78, "B8": 0x77, "Bb8": 0x76, "A8": 0x75, "Ab8": 0x74,
  105.             "G8": 0x73, "Gb8": 0x72, "F8": 0x71, "E8": 0x70, "Eb8": 0x6F, "D8": 0x6E, "Db8": 0x6D,
  106.             "C8": 0x6C, "B7": 0x6B, "Bb7": 0x6A, "A7": 0x69, "Ab7": 0x68, "G7": 0x67, "Gb7": 0x66,
  107.             "F7": 0x65, "E7": 0x64, "Eb7": 0x63, "D7": 0x62, "Db7": 0x61, "C7": 0x60, "B6": 0x5F,
  108.             "Bb6": 0x5E, "A6": 0x5D, "Ab6": 0x5C, "G6": 0x5B, "Gb6": 0x5A, "F6": 0x59, "E6": 0x58,
  109.             "Eb6": 0x57, "D6": 0x56, "Db6": 0x55, "C6": 0x54, "B5": 0x53, "Bb5": 0x52, "A5": 0x51,
  110.             "Ab5": 0x50, "G5": 0x4F, "Gb5": 0x4E, "F5": 0x4D, "E5": 0x4C, "Eb5": 0x4B, "D5": 0x4A,
  111.             "Db5": 0x49, "C5": 0x48, "B4": 0x47, "Bb4": 0x46, "A4": 0x45, "Ab4": 0x44, "G4": 0x43,
  112.             "Gb4": 0x42, "F4": 0x41, "E4": 0x40, "Eb4": 0x3F, "D4": 0x3E, "Db4": 0x3D, "C4": 0x3C,
  113.             "B3": 0x3B, "Bb3": 0x3A, "A3": 0x39, "Ab3": 0x38, "G3": 0x37, "Gb3": 0x36, "F3": 0x35,
  114.             "E3": 0x34, "Eb3": 0x33, "D3": 0x32, "Db3": 0x31, "C3": 0x30, "B2": 0x2F, "Bb2": 0x2E,
  115.             "A2": 0x2D, "Ab2": 0x2C, "G2": 0x2B, "Gb2": 0x2A, "F2": 0x29, "E2": 0x28, "Eb2": 0x27,
  116.             "D2": 0x26, "Db2": 0x25, "C2": 0x24, "B1": 0x23, "Bb1": 0x22, "A1": 0x21, "Ab1": 0x20,
  117.             "G1": 0x1F, "Gb1": 0x1E, "F1": 0x1D, "E1": 0x1C, "Eb1": 0x1B, "D1": 0x1A, "Db1": 0x19,
  118.             "C1": 0x18, "B0": 0x17, "Bb0": 0x16, "A0": 0x15, "Ab0": 0x14, "G0": 0x13, "Gb0": 0x12,
  119.             "F0": 0x11, "E0": 0x10, "Eb0": 0x0F, "D0": 0x0E, "Db0": 0x0D, "C0": 0x0C };
  120.             var a4 = noteTable["A4"];
  121.             var note = noteTable[noteName];
  122.             if(!note) throw new Error("You entered a note that does not exist! " + noteName);
  123.             return 440 * Math.pow(2, (note - a4)/12);
  124.         },
  125.        
  126.         __instancevars__: ["sample_rate", "num_channels"]
  127.     });
  128.    
  129.     var Kit = Class.$extend(
  130.     {
  131.         __init__: function(kitPaths, loadCallback, context, sampleRate, numChannels)
  132.         {
  133.             sampleRate || (sampleRate = 44100);
  134.             numChannels || (numChannels = 2);
  135.             this.sample_rate(sampleRate);
  136.             this.num_channels(numChannels);
  137.             if(!loadCallback) throw new Error("You have to hand me a callback function!");
  138.             this._loadCallback = loadCallback;
  139.             if(!kitPaths || !kitPaths.length || kitPaths.length < 1) throw new Error("You didn't enter anything for my kit!");
  140.             this.kit_paths(kitPaths);
  141.             context ? this._context = context : this._context = new webkitAudioContext();
  142.             this._masterGainNode = this._context.createGainNode();
  143.             this._masterGainNode.gain.value = 0.7;
  144.             this._masterGainNode.connect(this._context.destination);
  145.             this._compressor = this._context.createDynamicsCompressor();
  146.             this._compressor.connect(this._masterGainNode);
  147.             this._convolver = this._context.createConvolver();
  148.             this._convolver.connect(this._masterGainNode);
  149.            
  150.             var buffers = [];
  151.             for(var i = 0 ; i < this.kit_paths().length; ++i) buffers.push(0);
  152.             this.buffers(buffers);
  153.            
  154.             this._loadCount = 0;
  155.             for(var j = 0; j < this.kit_paths().length; ++j)
  156.             {
  157.                 this.loadSample(j);
  158.             }
  159.            
  160.             this._hasEffect = false;
  161.         },
  162.        
  163.         loadSample: function(sampleId)
  164.         {
  165.             var request = new XMLHttpRequest();
  166.             request.open("GET", this.kit_paths()[sampleId], true);
  167.             request.responseType = "arraybuffer";
  168.             var self = this;
  169.             request.onload = function()
  170.             {
  171.                 var buffer = self._context.createBuffer(request.response, false);
  172.                 self.buffers()[sampleId] = buffer;
  173.                 self._loadCount++;
  174.                 if(self._loadCount == self.kit_paths().length) self._loadCallback();
  175.             };
  176.            
  177.             request.send();
  178.         },
  179.        
  180.         playIndex: function(index, sendGain, mainGain, cutoff, resonance)
  181.         {
  182.             var source = this._context.createBufferSource();
  183.             source.buffer = this.buffers()[index];
  184.            
  185.             var filter = this._context.createBiquadFilter();
  186.             filter.frequency.value = cutoff;
  187.             filter.Q.value = resonance;
  188.            
  189.             source.connect(filter);
  190.            
  191.             var dryGainNode = this._context.createGainNode();
  192.             dryGainNode.gain.value = mainGain;
  193.             filter.connect(dryGainNode);
  194.             dryGainNode.connect(this._compressor);
  195.            
  196.             if(this._hasEffect) {
  197.                 var wetGainNode = this._context.createGainNode();
  198.                 wetGainNode.gain.value = sendGain;
  199.                 filter.connect(wetGainNode);
  200.                 wetGainNode.connect(this._convolver);
  201.             }
  202.            
  203.             source.noteOn(0);
  204.         },
  205.        
  206.         playNote: function(noteName, sendGain, mainGain, cutoff, resonance)
  207.         {
  208.             var index = this._getNoteIndex(noteName);
  209.             console.log(index);
  210.             this.playIndex(index, sendGain, mainGain, cutoff, resonance);
  211.         },
  212.        
  213.         _getNoteIndex: function(noteName)
  214.         {
  215.             var noteTable = { "G9": 0x7F, "Gb9": 0x7E, "F9": 0x7D, "E9": 0x7C, "Eb9": 0x7B,
  216.             "D9": 0x7A, "Db9": 0x79, "C9": 0x78, "B8": 0x77, "Bb8": 0x76, "A8": 0x75, "Ab8": 0x74,
  217.             "G8": 0x73, "Gb8": 0x72, "F8": 0x71, "E8": 0x70, "Eb8": 0x6F, "D8": 0x6E, "Db8": 0x6D,
  218.             "C8": 0x6C, "B7": 0x6B, "Bb7": 0x6A, "A7": 0x69, "Ab7": 0x68, "G7": 0x67, "Gb7": 0x66,
  219.             "F7": 0x65, "E7": 0x64, "Eb7": 0x63, "D7": 0x62, "Db7": 0x61, "C7": 0x60, "B6": 0x5F,
  220.             "Bb6": 0x5E, "A6": 0x5D, "Ab6": 0x5C, "G6": 0x5B, "Gb6": 0x5A, "F6": 0x59, "E6": 0x58,
  221.             "Eb6": 0x57, "D6": 0x56, "Db6": 0x55, "C6": 0x54, "B5": 0x53, "Bb5": 0x52, "A5": 0x51,
  222.             "Ab5": 0x50, "G5": 0x4F, "Gb5": 0x4E, "F5": 0x4D, "E5": 0x4C, "Eb5": 0x4B, "D5": 0x4A,
  223.             "Db5": 0x49, "C5": 0x48, "B4": 0x47, "Bb4": 0x46, "A4": 0x45, "Ab4": 0x44, "G4": 0x43,
  224.             "Gb4": 0x42, "F4": 0x41, "E4": 0x40, "Eb4": 0x3F, "D4": 0x3E, "Db4": 0x3D, "C4": 0x3C,
  225.             "B3": 0x3B, "Bb3": 0x3A, "A3": 0x39, "Ab3": 0x38, "G3": 0x37, "Gb3": 0x36, "F3": 0x35,
  226.             "E3": 0x34, "Eb3": 0x33, "D3": 0x32, "Db3": 0x31, "C3": 0x30, "B2": 0x2F, "Bb2": 0x2E,
  227.             "A2": 0x2D, "Ab2": 0x2C, "G2": 0x2B, "Gb2": 0x2A, "F2": 0x29, "E2": 0x28, "Eb2": 0x27,
  228.             "D2": 0x26, "Db2": 0x25, "C2": 0x24, "B1": 0x23, "Bb1": 0x22, "A1": 0x21, "Ab1": 0x20,
  229.             "G1": 0x1F, "Gb1": 0x1E, "F1": 0x1D, "E1": 0x1C, "Eb1": 0x1B, "D1": 0x1A, "Db1": 0x19,
  230.             "C1": 0x18, "B0": 0x17, "Bb0": 0x16, "A0": 0x15, "Ab0": 0x14, "G0": 0x13, "Gb0": 0x12,
  231.             "F0": 0x11, "E0": 0x10, "Eb0": 0x0F, "D0": 0x0E, "Db0": 0x0D, "C0": 0x0C };
  232.             var c0 = noteTable["C0"];
  233.             var note = noteTable[noteName];
  234.             console.log(c0);
  235.             console.log(note);
  236.             return (note - c0) % this.kit_paths().length;
  237.         },
  238.        
  239.         __instancevars__: ["sample_rate", "num_channels", "kit_paths", "buffers"]
  240.     });
  241.    
  242.     /*
  243.      *  Library for a bunch of kits to share an audiocontext.
  244.      *  Also convenient for playing notes.
  245.      */
  246.     var KitBox = Class.$extend(
  247.     {
  248.         __init__: function()
  249.         {
  250.             this._kits = {};
  251.             this._context = new webkitAudioContext();
  252.             this._kits["synth"] = new Synth(this._context);
  253.         },
  254.        
  255.         loadKit: function(kitName, kitList, callbackFn)
  256.         {
  257.             console.log(kitList);
  258.             this._kits[kitName] = new Kit(kitList, callbackFn, this._context);
  259.         },
  260.        
  261.         loadKitByName: function(kitName, callbackFn)
  262.         {
  263.             console.log(kitLoops);
  264.             this.loadKit(kitName, kitLoops[kitName], callbackFn);
  265.         },
  266.        
  267.         loadKitsByNames: function(kitNames, callbackFn)
  268.         {
  269.             var curCount = 0;
  270.             var total = kitNames.length;
  271.             var fn = function()
  272.             {
  273.                 curCount++;
  274.                 if(curCount === total) callbackFn();
  275.             };
  276.             for(var i = 0; i < kitNames.length; ++i)
  277.             {
  278.                 this.loadKitByName(kitNames[i], fn);
  279.             }
  280.         },
  281.        
  282.         playNote: function(kitName, noteName, numSecs)
  283.         {
  284.             if(numSecs && (this._kits[kitName] instanceof Synth)) this._kits[kitName].playNote(noteName, numSecs);
  285.             this._kits[kitName].playNote(noteName);
  286.         }
  287.     });
  288.    
  289.     /*
  290.      *  Library to play a score
  291.      */
  292.     var ScorePlayer = Class.$extend(
  293.     {
  294.         __init__: function(score, callbackFn)
  295.         {
  296.             this.score(score);
  297.             this.kitBox(new KitBox());
  298.             var self = this;
  299.             this.kitBox().loadKitsByNames(["acoustic", "techno", "R8", "bongos"], function() { self._ready = true; callbackFn(); });
  300.             this._ready = false;
  301.             this._playing = false;
  302.         },
  303.        
  304.         startPlaying: function(startPosition)
  305.         {
  306.             if(!this._ready) return;
  307.             var startIndex;
  308.             for(var i = 0; i < this.score().notes().length; ++i)
  309.             {
  310.                 console.log(this.score().notes()[i].start());
  311.                 if(startPosition <= this.score().notes()[i].start()) {
  312.                     startIndex = i;
  313.                     break;
  314.                 }
  315.             }
  316.             if(startPosition >= this.score().notes().length) return;
  317.             this._playing = true;
  318.             var startTime = this.score().getTimeForBeat(startPosition);
  319.             var firstNoteTime = this.score().getTimeForBeat(this.score().notes()[startIndex].start());
  320.             var self = this;
  321.             setTimeout( function() { self.asyncPlay(startIndex, self); }, 1000 * (firstNoteTime - startTime) );
  322.         },
  323.        
  324.         asyncPlay: function(index, self)
  325.         {
  326.             if(!self._playing) return;
  327.             if(index >= self.score().notes().length) {
  328.                 self._playing = false;
  329.                 return;
  330.             }
  331.            
  332.             var note = self.score().notes()[index];
  333.             self.kitBox().playNote(note.instrument(), note.value(), self.score().getLengthForNote(note.start(), note.length()));
  334.            
  335.             if(index + 1 >= self.score().notes().length) {
  336.                 self._playing = false;
  337.                 return;
  338.             }
  339.             var curNoteTime = this.score().getTimeForBeat(self.score().notes()[index].start());
  340.             var nextNoteTime = this.score().getTimeForBeat(self.score().notes()[index + 1].start());
  341.             setTimeout( function() { self.asyncPlay(index + 1, self); }, 1000 * (nextNoteTime - curNoteTime) );
  342.         },
  343.        
  344.         stopPlaying: function()
  345.         {
  346.             this._playing = false;
  347.         },
  348.        
  349.         __instancevars__: ["score", "kitBox"]
  350.     });
  351.    
  352.     JamSynth = Synth;
  353.     JamKit = Kit;
  354.     JamKitBox = KitBox;
  355.     JamScorePlayer = ScorePlayer;
  356.    
  357. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement