303 lines
7.4 KiB
JavaScript
Raw Normal View History

2015-08-17 10:25:09 +02:00
////////////
////////////////////////////
////////////
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
function Modulator(waveform, freq, gain) {
// actual modulating freq
this.osc = audioCtx.createOscillator();
this.osc.type = waveform;
this.osc.frequency.value = freq;
// not sure about this -- but the gain is what modulates
this.gain = audioCtx.createGain();
this.gain.gain.value = gain;
// connect
this.osc.connect(this.gain);
}
function Carrier(waveform, freq) {
this.osc = audioCtx.createOscillator();
this.osc.type = waveform;
this.osc.frequency.value = freq;
this.gain = audioCtx.createGain();
this.osc.connect(this.gain);
}
function FMSynth(waveform_c, freq_c, waveform_m, freq_m, gain_m) {
this.carrier = new Carrier(waveform_c, freq_c);
this.modulator = new Modulator(waveform_m, freq_m, gain_m);
this.bitcrusher_filter = new BitCrusherFilter();
this.modulator.gain.connect(this.carrier.osc.frequency);
this.carrier.gain.connect(audioCtx.destination);
this.started = false;
this.start = function() {
if(!this.started) {
2015-08-17 10:26:17 +02:00
this.carrier.osc.start(0);
this.modulator.osc.start(0);
2015-08-17 10:25:09 +02:00
this.started = true;
} else {
this.carrier.gain.gain.value = 1.0;
}
}
this.stop = function() {
this.carrier.gain.gain.value = 0.0;
}
this.modulator_freq_incr = function(incr) {
this.modulator.osc.frequency.value = this.modulator.osc.frequency.value + incr;
}
this.modulator_freq = function(freq) {
this.modulator.osc.frequency.value = freq;
}
this.add_filter = function (filter) {
this.filter = filter;
this.carrier.osc.disconnect(this.carrier.gain);
this.carrier.osc.connect(this.filter);
this.filter.connect(this.carrier.gain);
}
}
function SimpleOscillator(waveform, freq) {
this.oscillator = new Carrier(waveform, freq);
this.oscillator.gain.connect(audioCtx.destination);
this.started = false;
this.start = function() {
if(!this.started) {
2015-08-17 10:26:17 +02:00
this.oscillator.osc.start(0);
2015-08-17 10:25:09 +02:00
this.started = true;
} else {
this.oscillator.gain.gain.value = 1.0;
}
}
this.stop = function() {
this.oscillator.gain.gain.value = 0.0;
}
this.modulator_freq_incr = function(incr) {
this.oscillator.osc.frequency.value = this.modulator.osc.frequency.value + incr;
}
this.modulator_freq = function(freq) {
this.oscillator.osc.frequency.value = freq;
}
this.add_filter = function (filter) {
this.filter = filter;
this.oscillator.osc.disconnect(this.oscillator.gain);
this.oscillator.osc.connect(this.filter);
this.filter.connect(this.oscillator.gain);
}
}
function WhiteNoiseGenerator() {
// generates 2 sec noise buffer
var bufferSize = audioCtx.sampleRate * 2;
var noiseBuffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
var out = noiseBuffer.getChannelData(0);
for(var i = 0; i < bufferSize; i++) {
out[i] = Math.random() * 2 - 1;
}
this.whitenoise = audioCtx.createBufferSource();
this.whitenoise.buffer = noiseBuffer;
this.whitenoise.loop = true;
this.gain = audioCtx.createGain();
this.whitenoise.connect(this.gain);
this.gain.connect(audioCtx.destination);
this.started = false;
this.start = function() {
if(!this.started)
this.whitenoise.start(0);
this.started = true;
}
this.stop = function() {
this.gain.gain.value = 0.0;
this.started = false;
}
this.modulator_gain_incr = function(incr) {
this.gain.gain.value = this.gain.gain.value + incr;
}
this.modulator_gain = function(gain) {
this.gain.gain.value = gain;
}
this.add_filter = function(filter) {
this.filter = filter;
this.whitenoise.disconnect(this.gain);
this.whitenoise.connect(this.filter);
this.filter.connect(this.gain);
}
}
function PinkNoiseGenerator() {
var bufferSize = 4096;
this.pinknoise = audioCtx.createScriptProcessor(bufferSize, 1, 1);
var b0, b1, b2, b3, b4, b5, b6;
b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;
this.pinknoise.onaudioprocess = function(e) {
var out = e.outputBuffer.getChannelData(0);
for(var i = 0; i < bufferSize; i++) {
var white = Math.random() * 2 - 1;
b0 = 0.99886 * b0 + white * 0.0555179;
b1 = 0.99332 * b1 + white * 0.0750759;
b2 = 0.96900 * b2 + white * 0.1538520;
b3 = 0.86650 * b3 + white * 0.3104856;
b4 = 0.55000 * b4 + white * 0.5329522;
b5 = -0.7616 * b5 - white * 0.0168980;
out[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
out[i] *= 0.11; // (roughly) compensate for gain
b6 = white * 0.115926;
}
};
this.gain = audioCtx.createGain();
this.pinknoise.connect(this.gain);
this.gain.connect(audioCtx.destination);
this.started = false;
this.start = function() {
}
this.stop = function() {
this.gain.gain.value = 0.0;
this.started = false;
}
this.modulator_gain_incr = function(incr) {
this.gain.gain.value = this.gain.gain.value + incr;
}
this.modulator_gain = function(gain) {
this.gain.gain.value = gain;
}
this.add_filter = function(filter) {
this.filter = filter;
this.pinknoise.disconnect(this.gain);
this.pinknoise.connect(this.filter);
this.filter.connect(this.gain);
}
}
//////////// Filters
function BitCrusherFilter() {
var bufferSize = 4096;
var node = audioCtx.createScriptProcessor(bufferSize, 1, 1);
node.bits = 14; // between 1 and 16
node.normfreq = 0.1; // between 0.0 and 1.0
var step = Math.pow(1/2, node.bits);
var phaser = 0;
var last = 0;
node.onaudioprocess = function(e) {
var input = e.inputBuffer.getChannelData(0);
var output = e.outputBuffer.getChannelData(0);
for (var i = 0; i < bufferSize; i++) {
phaser += node.normfreq;
if (phaser >= 1.0) {
phaser -= 1.0;
last = step * Math.floor(input[i] / step + 0.5);
}
output[i] = last;
}
};
return node;
}
function LowPassFilter() {
var bufferSize = 4096;
var node = audioCtx.createScriptProcessor(bufferSize, 1, 1);
var prev = 0;
node.onaudioprocess = function(e) {
var input = e.inputBuffer.getChannelData(0);
var out = e.outputBuffer.getChannelData(0);
for (var i = 0; i < bufferSize; i++) {
out[i] = (input[i] + prev) / 2.0;
prev = out[i];
}
};
return node;
}
//////////// Convolvers
function NoiseConvolver() {
var convolver = audioCtx.createConvolver();
var noiseBuffer = audioCtx.createBuffer(2, 0.5 * audioCtx.sampleRate, audioCtx.sampleRate);
var left = noiseBuffer.getChannelData(0);
var rigth = noiseBuffer.getChannelData(1);
for(var i = 0; i < noiseBuffer.length; i++) {
left[i] = Math.random() * 2 - 1;
rigth[i] = Math.random() * 2 - 1;
}
convolver.buffer = noiseBuffer;
return convolver;
}
//////////// WaveShapers
function DistortionShaper(distortion_val) {
this.waveshaper = audioCtx.createWaveShaper();
this.makeDistortionCurve = function(amount) {
var k = typeof amount === 'number' ? amount : 50,
n_samples = 44100,
curve = new Float32Array(n_samples),
deg = Math.PI / 180,
i = 0,
x;
for ( ; i < n_samples; ++i ) {
x = i * 2 / n_samples - 1;
curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
}
return curve;
}
this.distortion = function(amount) {
this.waveshaper.curve = this.makeDistortionCurve(amount);
}
this.waveshaper.curve = this.makeDistortionCurve(distortion_val);
return this.waveshaper;
}