Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply basic audio filter using JavaScript

I'm trying to get basic audio filters to work. I want to evaluate at least 3-4 examples.

Here is a JS code that I'm evaluating and trying to get working:

var QUAL_MUL = 30;

function FilterSample() {
  this.isPlaying = false;
  loadSounds(this, {buffer: 'techno.wav'});
};

FilterSample.prototype.play = function() {
  // Create the source.
  var source = context.createBufferSource();
  source.buffer = this.buffer;
  // Create the filter.
  var filter = context.createBiquadFilter();
  filter.type = filter.LOWPASS;
  filter.frequency.value = 5000;
  // Connect source to filter, filter to destination.
  source.connect(filter);
  filter.connect(context.destination);
  // Play!
  source.start(0);
  source.loop = true;
  // Save source and filterNode for later access.
  this.source = source;
  this.filter = filter;
};

FilterSample.prototype.stop = function() {
  this.source.stop(0);
};

FilterSample.prototype.toggle = function() {
  this.isPlaying ? this.stop() : this.play();
  this.isPlaying = !this.isPlaying;
};

FilterSample.prototype.changeFrequency = function(element) {
  // Clamp the frequency between the minimum value (40 Hz) and half of the
  // sampling rate.
  var minValue = 40;
  var maxValue = context.sampleRate / 2;
  // Logarithm (base 2) to compute how many octaves fall in the range.
  var numberOfOctaves = Math.log(maxValue / minValue) / Math.LN2;
  // Compute a multiplier from 0 to 1 based on an exponential scale.
  var multiplier = Math.pow(2, numberOfOctaves * (element.value - 1.0));
  // Get back to the frequency value between min and max.
  this.filter.frequency.value = maxValue * multiplier;
};

FilterSample.prototype.changeQuality = function(element) {
  this.filter.Q.value = element.value * QUAL_MUL;
};

FilterSample.prototype.toggleFilter = function(element) {
  this.source.disconnect(0);
  this.filter.disconnect(0);
  // Check if we want to enable the filter.
  if (element.checked) {
    // Connect through the filter.
    this.source.connect(this.filter);
    this.filter.connect(context.destination);
  } else {
    // Otherwise, connect directly.
    this.source.connect(context.destination);
  }
};

It would be very nice, if someone could explain or better provide a simple working example of applying filter using JS.

Thank you in advance.

like image 873
user3340575 Avatar asked Mar 06 '14 18:03

user3340575


1 Answers

(Demo here)

Lets start with creating a source (this is HTML, pretty straightforward)

<audio controls="" preload="" src="add/src/here" autoplay=""></audio>

you should insert an audio file url at add/src/here. For example put a file up on dropbox and add it there.

Now we want to create the audiocontext and hook up the <audio> tag to a webAudio node:

context = new AudioContext();
source = context.createMediaElementSource(document.getElementsByTagName('audio')[0]);

That is some basic audioAPI programming. Now we want to create a filter node, and connect the source to the filter, and then the filter to your speakers:

filter = context.createBiquadFilter();
source.connect(filter);
filter.connect(context.destination);

Now, you should chose what filter you want. You can find all filters here (basically all information about the biquadFilter). Notice there are 8 different filter types:

"lowpass", "highpass", "bandpass", "lowshelf", "highshelf", "peaking", "notch", "allpass"

You can set these one of these types by getting its numeric value. According to the list above, Lowpass is 0, highpass is 1 and so on. If you don't know it, simply call the function with the name in caps on the <#biquadFilter> object, like so: filter.LOWPASS. This returns 0. Now lets tell the filter that it should be a lowshelf. This is type 3:

filter.type = 3;

Edit: the standards for defining the type have changed a couple times, apparently you can now just use the string directly. https://www.w3.org/TR/webaudio/#the-biquadfilternode-interface

Now a lowshelf means: apply the given gain boost/decrease to all frequencies containing and below the given frequency. So if I give the filter a frequency of 95:

filter.frequency.value = 95;

The the filter adds the gain to all frequencies below 95. Also notice the .value. This is because there are more functions like filter.frequency.linearRampToValueAtTime(). These functions are handy if you want the frequency to ramp to a certain value, or set the value at a time. If you want more info on this, feel free to ask. I'd like to tell you about it as I know it cost's much time to research how it works. There is like no info on this, but at least I got it working.

Now we want to actually set the gain, this is also with a .value:

filter.gain.value = 30;

Not all filters require a gain. For example a lowpass means let all frequencies below the given frequency pass, and do not do anything special. The lowshelf does boost/attenuate, so you need to specify how much.

Some filters also require a Q value. This determines the peaking at the cutoff (where your frequency band ends). As I am not good in explaining this, I got this straight from w3.org:

Controls how peaked the response will be at the cutoff frequency. A large value makes the response more peaked. Please note that for this filter type, this value is not a traditional Q, but is a resonance value in decibels.

Now let's say we actually want to do something with the ramps. I want the frequency increase from 0 to 120 in 10 seconds. As this is still experimental, it doesn't quite work like you would expect. Lets first initialize setting the value using the time. We just set the frequency value to 0 at the current time:

filter.frequency.setValueAtTime(0.0, context.currentTime);

Now we want it to be at 120 after 10 seconds:

filter.frequency.linearRampToValueAtTime(120.0, context.currentTime+10);

It is pretty clear to hear the frequency increase. (But it doesn't really sound clear...). You can find a small demo of it here

It is also possible to do all the editing yourself using mathematical functions inside scriptprocessors, but that is just a pain to do as support for it is so experimental the chrome versions scriptprocessors work on are scarce.

I hope this helps you how filters work. Be adviced, using much filters makes your output sound weird. Adding a compressor on the end normalizes everything.

If you need to know anything else, feel free to ask.

like image 139
MarijnS95 Avatar answered Sep 24 '22 21:09

MarijnS95