cleanup, WIP converting webaudio nodes to Tone objects

This commit is contained in:
Eric Rosenbaum 2016-11-08 15:06:29 -05:00
parent 28c9bffe4d
commit f7141fe97b

View file

@ -1,68 +1,30 @@
var Tone = require('tone'); var Tone = require('tone');
var modulatorNode = null;
var carrierNode = null;
var vocoding = false;
var FILTER_QUALITY = 6; // The Q value for the carrier and modulator filters
// These are "placeholder" gain nodes - because the modulator and carrier will get swapped in
// as they are loaded, it's easier to connect these nodes to all the bands, and the "real"
// modulator & carrier AudioBufferSourceNodes connect to these.
var modulatorInput = null;
var carrierInput = null;
var modulatorGain = null;
var modulatorGainValue = 1.0;
// noise node added to the carrier signal
var noiseBuffer = null;
var noiseNode = null;
var noiseGain = null;
var noiseGainValue = 0.2;
// Carrier Synth oscillator stuff
var oscillatorNode = null;
var oscillatorType = 4; // CUSTOM
var oscillatorGain = null;
var oscillatorGainValue = 1.0;
var oscillatorDetuneValue = 0;
var FOURIER_SIZE = 4096;
var SAWTOOTHBOOST = 0.40;
// These are the arrays of nodes - the "columns" across the frequency band "rows"
var modFilterBands = null; // tuned bandpass filters
var modFilterPostGains = null; // post-filter gains.
var heterodynes = null; // gain nodes used to multiply bandpass X sine
var powers = null; // gain nodes used to multiply prev out by itself
var lpFilters = null; // tuned LP filters to remove doubled copy of product
var lpFilterPostGains = null; // gain nodes for tuning input to waveshapers
var carrierBands = null; // tuned bandpass filters, same as modFilterBands but in carrier chain
var carrierFilterPostGains = null; // post-bandpass gain adjustment
var carrierBandGains = null; // these are the "control gains" driven by the lpFilters
var vocoderBands;
var numVocoderBands;
var hpFilterGain = null;
var outputGain;
function Vocoder () { function Vocoder () {
Tone.Effect.call(this); Tone.Effect.call(this);
outputGain = new Tone.Gain(); this.FILTER_QUALITY = 6; // The Q value for the carrier and modulator filters
this.generateVocoderBands(55, 7040, 28); this.modulatorInput = new Tone.Gain();
this.carrierInput = new Tone.Gain();
this.outputGain = new Tone.Gain();
this.oscillatorNode;
this.vocoderBands = this.generateVocoderBands(55, 7040, 10);
this.initBandpassFilters(); this.initBandpassFilters();
this.createCarrier(); this.createCarrier();
this.effectSend.connect(modulatorInput); this.effectSend.connect(this.modulatorInput);
outputGain.connect(this.effectReturn); this.outputGain.connect(this.effectReturn);
} }
Tone.extend(Vocoder, Tone.Effect); Tone.extend(Vocoder, Tone.Effect);
Vocoder.prototype.setCarrierOscFrequency = function (freq) {
this.oscillatorNode.frequency.rampTo(freq, 0.05);
};
// this function will algorithmically re-calculate vocoder bands, distributing evenly // this function will algorithmically re-calculate vocoder bands, distributing evenly
// from startFreq to endFreq, splitting evenly (logarhythmically) into a given numBands. // from startFreq to endFreq, splitting evenly (logarhythmically) into a given numBands.
// The function places this info into the vocoderBands and numVocoderBands variables. // The function places this info into the vocoderBands and numVocoderBands variables.
@ -73,7 +35,7 @@ Vocoder.prototype.generateVocoderBands = function (startFreq, endFreq, numBands)
var centsPerBand = totalRangeInCents / numBands; var centsPerBand = totalRangeInCents / numBands;
var scale = Math.pow( 2, centsPerBand / 1200 ); // This is the scaling for successive bands var scale = Math.pow( 2, centsPerBand / 1200 ); // This is the scaling for successive bands
vocoderBands = []; var vocoderBands = [];
var currentFreq = startFreq; var currentFreq = startFreq;
for (var i=0; i<numBands; i++) { for (var i=0; i<numBands; i++) {
@ -83,41 +45,20 @@ Vocoder.prototype.generateVocoderBands = function (startFreq, endFreq, numBands)
currentFreq = currentFreq * scale; currentFreq = currentFreq * scale;
} }
numVocoderBands = numBands; return vocoderBands;
}; };
Vocoder.prototype.initBandpassFilters = function () { Vocoder.prototype.initBandpassFilters = function () {
// When this function is called, the carrierNode and modulatorAnalyser
// may not already be created. Create placeholder nodes for them.
modulatorInput = Tone.context.createGain();
carrierInput = Tone.context.createGain();
if (modFilterBands == null) var modFilterBands = new Array(); // tuned bandpass filters
modFilterBands = new Array(); var modFilterPostGains = new Array(); // post-filter gains.
var heterodynes = new Array(); // gain nodes used to multiply bandpass X sine
if (modFilterPostGains == null) var powers = new Array(); // gain nodes used to multiply prev out by itself
modFilterPostGains = new Array(); var lpFilters = new Array(); // tuned lowpass filters to remove doubled copy of product
var lpFilterPostGains = new Array(); // gain nodes for tuning input to waveshapers
if (heterodynes == null) var carrierBands = new Array(); // tuned bandpass filters, same as modFilterBands but in carrier chain
heterodynes = new Array(); var carrierFilterPostGains = new Array(); // post-bandpass gain adjustment
var carrierBandGains = new Array(); // these are the "control gains" driven by the lpFilters
if (powers == null)
powers = new Array();
if (lpFilters == null)
lpFilters = new Array();
if (lpFilterPostGains == null)
lpFilterPostGains = new Array();
if (carrierBands == null)
carrierBands = new Array();
if (carrierFilterPostGains == null)
carrierFilterPostGains = new Array();
if (carrierBandGains == null)
carrierBandGains = new Array();
var waveShaperCurve = new Float32Array(65536); var waveShaperCurve = new Float32Array(65536);
// Populate with a "curve" that does an abs() // Populate with a "curve" that does an abs()
@ -126,24 +67,22 @@ Vocoder.prototype.initBandpassFilters = function() {
for (var i = 0; i < n2; ++i) { for (var i = 0; i < n2; ++i) {
var x = i / n2; var x = i / n2;
waveShaperCurve[n2 + i] = x; waveShaperCurve[n2 + i] = x;
waveShaperCurve[n2 - i - 1] = x; waveShaperCurve[n2 - i - 1] = x;
} }
// Set up a high-pass filter to add back in the fricatives, etc. // Set up a high-pass filter to add back in the fricatives, etc.
// (this isn't used by default in the "production" version, as I hid the slider)
var hpFilter = Tone.context.createBiquadFilter(); var hpFilter = Tone.context.createBiquadFilter();
hpFilter.type = "highpass"; hpFilter.type = 'highpass';
hpFilter.frequency.value = 8000; // or use vocoderBands[numVocoderBands-1].frequency; hpFilter.frequency.value = 8000;
hpFilter.Q.value = 1; // no peaking hpFilter.Q.value = 1; // no peaking
modulatorInput.connect( hpFilter); this.modulatorInput.connect( hpFilter);
hpFilterGain = Tone.context.createGain(); var hpFilterGain = Tone.context.createGain();
hpFilterGain.gain.value = 0.0; hpFilterGain.gain.value = 1.0;
hpFilter.connect(hpFilterGain); hpFilter.connect(hpFilterGain);
hpFilterGain.connect( outputGain ); hpFilterGain.connect(this.outputGain);
//clear the arrays //clear the arrays
modFilterBands.length = 0; modFilterBands.length = 0;
@ -157,26 +96,27 @@ Vocoder.prototype.initBandpassFilters = function() {
carrierBandGains.length = 0; carrierBandGains.length = 0;
var rectifierCurve = new Float32Array(65536); var rectifierCurve = new Float32Array(65536);
for (var i=-32768; i<32768; i++) for (i=-32768; i<32768; i++) {
rectifierCurve[i+32768] = ((i>0)?i:-i)/32768; rectifierCurve[i+32768] = ((i>0)?i:-i)/32768;
}
for (var i=0; i<numVocoderBands; i++) { for (i=0; i<this.vocoderBands.length; i++) {
// CREATE THE MODULATOR CHAIN // CREATE THE MODULATOR CHAIN
// create the bandpass filter in the modulator chain // create the bandpass filter in the modulator chain
var modulatorFilter = Tone.context.createBiquadFilter(); var modulatorFilter = Tone.context.createBiquadFilter();
modulatorFilter.type = "bandpass"; // Bandpass filter modulatorFilter.type = 'bandpass'; // Bandpass filter
modulatorFilter.frequency.value = vocoderBands[i].frequency; modulatorFilter.frequency.value = this.vocoderBands[i].frequency;
modulatorFilter.Q.value = FILTER_QUALITY; // initial quality modulatorFilter.Q.value = this.FILTER_QUALITY; // initial quality
modulatorInput.connect(modulatorFilter); this.modulatorInput.connect(modulatorFilter);
modFilterBands.push(modulatorFilter); modFilterBands.push(modulatorFilter);
// Now, create a second bandpass filter tuned to the same frequency - // Now, create a second bandpass filter tuned to the same frequency -
// this turns our second-order filter into a 4th-order filter, // this turns our second-order filter into a 4th-order filter,
// which has a steeper rolloff/octave // which has a steeper rolloff/octave
var secondModulatorFilter = Tone.context.createBiquadFilter(); var secondModulatorFilter = Tone.context.createBiquadFilter();
secondModulatorFilter.type = "bandpass"; // Bandpass filter secondModulatorFilter.type = 'bandpass'; // Bandpass filter
secondModulatorFilter.frequency.value = vocoderBands[i].frequency; secondModulatorFilter.frequency.value = this.vocoderBands[i].frequency;
secondModulatorFilter.Q.value = FILTER_QUALITY; // initial quality secondModulatorFilter.Q.value = this.FILTER_QUALITY; // initial quality
modulatorFilter.chainedFilter = secondModulatorFilter; modulatorFilter.chainedFilter = secondModulatorFilter;
modulatorFilter.connect(secondModulatorFilter); modulatorFilter.connect(secondModulatorFilter);
@ -188,7 +128,7 @@ Vocoder.prototype.initBandpassFilters = function() {
// Create the sine oscillator for the heterodyne // Create the sine oscillator for the heterodyne
var heterodyneOscillator = Tone.context.createOscillator(); var heterodyneOscillator = Tone.context.createOscillator();
heterodyneOscillator.frequency.value = vocoderBands[i].frequency; heterodyneOscillator.frequency.value = this.vocoderBands[i].frequency;
heterodyneOscillator.start(0); heterodyneOscillator.start(0);
@ -229,17 +169,17 @@ Vocoder.prototype.initBandpassFilters = function() {
// Create the bandpass filter in the carrier chain // Create the bandpass filter in the carrier chain
var carrierFilter = Tone.context.createBiquadFilter(); var carrierFilter = Tone.context.createBiquadFilter();
carrierFilter.type = "bandpass"; carrierFilter.type = 'bandpass';
carrierFilter.frequency.value = vocoderBands[i].frequency; carrierFilter.frequency.value = this.vocoderBands[i].frequency;
carrierFilter.Q.value = FILTER_QUALITY; carrierFilter.Q.value = this.FILTER_QUALITY;
carrierBands.push(carrierFilter); carrierBands.push(carrierFilter);
carrierInput.connect(carrierFilter); this.carrierInput.connect(carrierFilter);
// We want our carrier filters to be 4th-order filter too. // We want our carrier filters to be 4th-order filter too.
var secondCarrierFilter = Tone.context.createBiquadFilter(); var secondCarrierFilter = Tone.context.createBiquadFilter();
secondCarrierFilter.type = "bandpass"; // Bandpass filter secondCarrierFilter.type = 'bandpass'; // Bandpass filter
secondCarrierFilter.frequency.value = vocoderBands[i].frequency; secondCarrierFilter.frequency.value = this.vocoderBands[i].frequency;
secondCarrierFilter.Q.value = FILTER_QUALITY; // initial quality secondCarrierFilter.Q.value = this.FILTER_QUALITY; // initial quality
carrierFilter.chainedFilter = secondCarrierFilter; carrierFilter.chainedFilter = secondCarrierFilter;
carrierFilter.connect(secondCarrierFilter); carrierFilter.connect(secondCarrierFilter);
@ -255,18 +195,17 @@ Vocoder.prototype.initBandpassFilters = function() {
bandGain.gain.value = 0.0; // audio-rate inputs are summed with initial intrinsic value bandGain.gain.value = 0.0; // audio-rate inputs are summed with initial intrinsic value
waveshaper.connect(bandGain.gain); // connect the lp controller waveshaper.connect(bandGain.gain); // connect the lp controller
bandGain.connect(outputGain); bandGain.connect(this.outputGain);
} }
}; };
Vocoder.prototype.createCarrier = function () { Vocoder.prototype.createCarrier = function () {
oscillatorNode = new Tone.Oscillator(110, 'sawtooth8').start(); this.oscillatorNode = new Tone.Oscillator('C3', 'sawtooth').start();
oscillatorNode.connect(carrierInput); this.oscillatorNode.connect(this.carrierInput);
noiseNode = new Tone.Noise('white').start(); var noiseNode = new Tone.Noise('white').start();
noiseGain = new Tone.Gain(noiseGainValue); noiseNode.volume.value = -12;
noiseNode.connect(noiseGain); noiseNode.connect(this.carrierInput);
noiseGain.connect(carrierInput); };
}
module.exports = Vocoder; module.exports = Vocoder;