UNPKG

dspjs

Version:

DSP.js is a comprehensive digital signal processing library for javascript

325 lines (267 loc) 10.3 kB
<!DOCTYPE html> <html> <head> <!-- Load JQuery and JQuery-UI --> <link type="text/css" href="css/hot-sneaks/jquery-ui-1.8.custom.css" rel="stylesheet" /> <script type="text/javascript" src="js/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="js/jquery-ui-1.8.custom.min.js"></script> <!-- Load Processing.js --> <script language="javascript" src="js/processing.js"></script> <script language="javascript" src="js/init.js"></script> <!-- Load DSP.js --> <script src="../dsp.js"></script> <script> </script> <style type="text/css"> </style> </head> <body> <script> // Setup shared variables var sampleRate = 44100; var bufferSize = 2048; var bufferTime = Math.floor(1000 / (sampleRate / bufferSize)); var amplitude = 0.1; // Default amplitude at 70% var oct = 2; // Root Octave var oscs = []; var noteOn = []; var playSample = false; // Borrowed from F1LTER's code var midiNoteFreq = [ 16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87, 32.7, 34.65, 36.71, 38.89, 41.2, 43.65, 46.25, 49, 51.91, 55, 58.27, 61.74, 65.41, 69.3, 73.42, 77.78, 82.41, 87.31, 92.5, 98, 103.83, 110, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880, 932.33, 987.77, 1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53, 2093, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978 ]; var silence = new Float32Array(bufferSize); // Setup audio channel var output = new Audio(); if ( typeof output.mozSetup === 'function' ) { output.mozSetup(1, sampleRate, 1); } var timePerWrite = 0; var programStart; // load the voice formant var v = new Sampler('audio/formant.ogg', bufferSize, sampleRate); v.envelope = new ADSR(0, 0, 1, Infinity, 0, sampleRate); v.envelope.disable(); // turn off so it does not auto trigger // load the synth carrier var s = new Sampler('audio/carrier.ogg', bufferSize, sampleRate); s.envelope = new ADSR(0, 0, 1, Infinity, 0, sampleRate); s.envelope.disable(); // turn off so it does not auto trigger s.loopMode = 3; // back and forth loop var fftcar = new FFT(bufferSize, sampleRate); var fftmod = new FFT(bufferSize, sampleRate); var hann = new WindowFunction(DSP.HANN); var real = new Float32Array(bufferSize); var imag = new Float32Array(bufferSize); var spec1, spec2; var numBands = 32; var bands = []; for (var i = 0; i < bufferSize/2; i+= Math.round((bufferSize/2)/numBands) ) { bands.push(i); } bands[bands.length-1] = bufferSize/2; var audioWriter = function() { if (s.loaded) { var startTime = (new Date()).getTime(); if ( programStart === undefined ) { programStart = new Date(); } var carrier, formant, additiveSignal = []; if ( s.envelope.isActive() && v.envelope.isActive() ) { s.generate(); v.generate(); carrier = s.applyEnvelope(); formant = v.applyEnvelope(); spec1 = fftcar.forward(hann.process(carrier)); spec2 = fftmod.forward(hann.process(formant)); for (var i = 0; i < numBands-1; i++) { var totalReal = 0; var totalImag = 0; var count = 0; for (var b = bands[i]; b < bands[i+1]; b++) { totalReal += Math.abs(fftmod.real[b]); totalImag += Math.abs(fftmod.imag[b]); count++; } var meanReal = totalReal/count; var meanImag = totalImag/count; for (var b = bands[i]; b < bands[i+1]; b++) { real[b] = fftcar.real[b] * meanReal; imag[b] = fftcar.imag[b] * meanImag; } } additiveSignal = fftcar.inverse(real, imag); /* for (var i = 0; i < additiveSignal.length; i++) { if (additiveSignal[i] > 0.8) { additiveSignal[i] = 0.7; } else if (additiveSignal[i] < -0.8) { additiveSignal[i] = -0.7; } } */ } else if ( s.envelope.isActive() ) { s.generate(); additiveSignal = s.applyEnvelope(); } else if ( v.envelope.isActive() ) { v.generate(); additiveSignal = v.applyEnvelope(); } // Set the global osc object if ( typeof additiveSignal === 'undefined' ) { additiveSignal = silence; } // Flush buffer output.mozWriteAudio([]); // Write next audio frame output.mozWriteAudio(additiveSignal); var endTime = (new Date()).getTime(); timePerWrite = endTime - startTime; } } </script> <script target="#keyboard" type="application/processing"> void setup() { size(1024, 400); setInterval(audioWriter, bufferTime); // start audioWriter timer stroke(255); frameRate(20); } void draw() { background(255); fill(0) stroke(255); if (!s.loaded) { var loadPercent = s.samples.length / (s.duration * sampleRate); text("Loading carrier: " + Math.round(loadPercent * 100) + "%", 0, 20); } if (!v.loaded) { var loadPercent = v.samples.length / (v.duration * sampleRate); text("Loading formant: " + Math.round(loadPercent * 100) + "%", 0, 40); } if ( s.loaded && v.loaded ) { /* // Draw formant: stroke(0, 0, 255); for (int i = 0; i < v.samples.length; i+=100) { line(i/100, 50-v.samples[i]*50, i/100, 50+v.samples[i]*50); } // Draw carrier stroke(255, 0, 0); for (int i = 0; i < s.samples.length; i+=100) { line(i/100, 150-s.samples[i]*50, i/100, 150+s.samples[i]*50); } */ noStroke(); fill(0); for (var i = 0; i < bufferSize/4; i+= 4) { if (real[i] && imag[i]) { rect(i, 100, 2, - fftmod.spectrum[i] * 1000); } } fill(0); for (var i = 0; i < bufferSize/4; i+= 4) { if (real[i] && imag[i]) { rect(i, 200, 2, - fftcar.spectrum[i] * 1000); } } fill(255, 0, 0); for (var i = 0; i < bufferSize/4; i+= 4) { if (real[i] && imag[i]) { rect(i, height, 2, - (Math.sqrt(real[i] * real[i] + imag[i] * imag[i])) / bufferSize * 1000); } } } } void keyPressed() { var semi = undefined; if ( key == 'z' ) { // C semi = 0; } if ( key == 's' ) { // C# semi = 1; } if ( key == 'x' ) { // D semi = 2; } if ( key == 'd' ) { // D# semi = 3; } if ( key == 'c' ) { // E semi = 4; } if ( key == 'v' ) { // F semi = 5; } if ( key == 'g' ) { // F# semi = 6; } if ( key == 'b' ) { // G semi = 7; } if ( key == 'h' ) { // G# semi = 8; } if ( key == 'n' ) { // A semi = 9; } if ( key == 'j' ) { // A# semi = 10; } if ( key == 'm' ) { // B semi = 11; } if ( key == '=') { // increase octave oct++; } if ( key == '-') { // descrease octave oct--; } if (typeof semi !== 'undefined' && s.loaded && v.loaded) { s.envelope.noteOn(); s.setFreq(midiNoteFreq[12*oct+semi]); v.envelope.noteOn(); v.setFreq(midiNoteFreq[12*oct+semi]); } if (key == 'w') { s.envelope.noteOn(); s.setFreq(midiNoteFreq[12*oct]); } if (key == 'q') { v.envelope.noteOn(); v.setFreq(midiNoteFreq[12*oct]); } if (key == 'e') { s.envelope.noteOn(); s.setFreq(midiNoteFreq[12*oct]); v.envelope.noteOn(); v.setFreq(midiNoteFreq[12*oct]); } } void keyReleased() { if ( s.envelope.isActive() ) { s.envelope.noteOff(); s.reset(); } if ( v.envelope.isActive() ) { v.envelope.noteOff(); v.reset(); } } </script> <h1>Vocoder</h1> <canvas id="keyboard" width="200px" height="200px"></canvas> <h2>Playing sample</h2> <p><b>Q</b> Play the voice formant sample</p> <p><b>W</b> Play the carrier synth sample</p> <p><b>E</b> Play the vocoded sample</p> <p>Bottom row keys z to m are the white keys of one octave of a piano.</p> <p>Middle row keys s,d and g,h,j are the black keys of one octave of a piano</p> <p>- and = decrease or increase the octave</p> </body> </html>