sono
Version:
A simple yet powerful JavaScript library for working with Web Audio
202 lines (161 loc) • 4.96 kB
JavaScript
import AbstractEffect from './abstract-effect';
import sono from '../core/sono';
import isSafeNumber from '../core/utils/isSafeNumber';
function safeOption(...args) {
let value = null;
for (let i = 0; i < args.length; i++) {
if (isSafeNumber(args[i])) {
value = args[i];
break;
}
}
return value;
}
// https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
// For lowpass and highpass Q indicates how peaked the frequency is around the cutoff.
// The greater the value is, the greater is the peak
const minFrequency = 40;
const maxFrequency = sono.context.sampleRate / 2;
function getFrequency(value) {
// Logarithm (base 2) to compute how many octaves fall in the range.
const numberOfOctaves = Math.log(maxFrequency / minFrequency) / Math.LN2;
// Compute a multiplier from 0 to 1 based on an exponential scale.
const multiplier = Math.pow(2, numberOfOctaves * (value - 1.0));
// Get back to the frequency value between min and max.
return maxFrequency * multiplier;
}
class Filter extends AbstractEffect {
constructor({
type = 'lowpass',
frequency = 1000,
detune = 0,
q = 0,
gain = 1,
peak = 0,
boost = 0,
width = 100,
sharpness = 0,
wet = 1,
dry = 0
} = {}) {
super(sono.context.createBiquadFilter());
this._node.type = type;
this.wet = wet;
this.dry = dry;
this.update({frequency, gain, detune, q, peak, boost, width, sharpness});
}
update(options) {
this.setSafeParamValue(this._node.frequency, options.frequency);
this.setSafeParamValue(this._node.gain, safeOption(options.boost, options.gain));
this.setSafeParamValue(this._node.detune, options.detune);
const q = safeOption(options.peak, options.width, options.sharpness, options.q);
this.setSafeParamValue(this._node.Q, q);
}
setByPercent({percent = 0.5}) {
this.update({
frequency: getFrequency(percent)
});
}
get type() {
return this._node.type;
}
set type(value) {
this._node.type = value;
}
get frequency() {
return this._node.frequency.value;
}
set frequency(value) {
this.setSafeParamValue(this._node.frequency, value);
}
get q() {
return this._node.Q.value;
}
set q(value) {
this.setSafeParamValue(this._node.Q, value);
}
get Q() {
return this.q;
}
set Q(value) {
this.q = value;
}
get peak() {
return this.q;
}
set peak(value) {
this.q = value;
}
get width() {
return this._node.frequency.value / this._node.Q.value;
}
set width(value) {
if (value <= 0) {
this.q = 0;
return;
}
this.q = this._node.frequency.value / value;
}
get sharpness() {
return this.q;
}
set sharpness(value) {
this.q = value;
}
get boost() {
return this._node.gain.value;
}
set boost(value) {
this.setSafeParamValue(this._node.gain, value);
}
get gain() {
return this.boost;
}
set gain(value) {
this.boost = value;
}
get detune() {
return this._node.detune.value;
}
set detune(value) {
this.setSafeParamValue(this._node.detune, value);
}
get maxFrequency() {
return sono.context.sampleRate / 2;
}
}
const lowpass = sono.register('lowpass', ({frequency, peak, q} = {}) => {
return new Filter({type: 'lowpass', frequency, peak, q});
});
const highpass = sono.register('highpass', ({frequency, peak, q} = {}) => {
return new Filter({type: 'highpass', frequency, peak, q});
});
const lowshelf = sono.register('lowshelf', ({frequency, boost, gain} = {}) => {
return new Filter({type: 'lowshelf', frequency, boost, gain, q: 0});
});
const highshelf = sono.register('highshelf', ({frequency, boost, gain} = {}) => {
return new Filter({type: 'highshelf', frequency, boost, gain, q: 0});
});
const peaking = sono.register('peaking', ({frequency, width, boost, gain, q} = {}) => {
return new Filter({type: 'peaking', frequency, width, boost, gain, q});
});
const bandpass = sono.register('bandpass', ({frequency, width, q} = {}) => {
return new Filter({type: 'bandpass', frequency, width, q});
});
const notch = sono.register('notch', ({frequency, width, gain, q} = {}) => {
return new Filter({type: 'notch', frequency, width, gain, q});
});
const allpass = sono.register('allpass', ({frequency, sharpness, q} = {}) => {
return new Filter({type: 'allpass', frequency, sharpness, q});
});
export default sono.register('filter', opts => new Filter(opts));
export {
lowpass,
highpass,
bandpass,
lowshelf,
highshelf,
peaking,
notch,
allpass
};