Reputation: 123
I'm trying to implement some filters using Web Audio.
I have the below set-up and only the lowpass filter works, but even then I can't seem to get it to stop.
//Creating filters, setting their types and setting up booleans for later use.
//Lowpass Filter Setup
lowpass = context.createBiquadFilter();
lp_bool=false;
lowpass.type="lowpass";
lowpass.type=LOWPASS;
//Highpass Filter Setup
highpass = context.createBiquadFilter();
highpass.type="highpass";
highpass.type=HIGHPASS;
hp_bool=false;
//Bandpass Filter Setup
bandpass = context.createBiquadFilter();
bandpass.type="bandpass";
bandpass.type=BANDPASS;
bp_bool=false;
//Lowshelf Filter Setup
lowshelf = context.createBiquadFilter();
lowshelf.type="lowshelf";
lowshelf.type=LOWSHELF;
ls_bool=false;
/*
lowshelf.frequency.value = 440;
lowshelf.gain.value = 0;*/
//Highshelf Filter Setup
highshelf = context.createBiquadFilter();
highshelf.type="highshelf";
highshelf.type=HIGHSHELF;
hs_bool=false;/*
highshelf.frequency.value = 440;
highshelf.gain.value = 0;*/
//Peaking Filter Setup
peaking = context.createBiquadFilter();
peaking.type="peaking";
peaking.type=PEAKING;
pk_bool=false;/*
peaking.frequency.value = 440;
peaking.Q.value = 0;
peaking.gain.value = 0;*/
//Notch Filter Setup
notch = context.createBiquadFilter();
notch.type="notch";
notch.type=NOTCH;
nh_bool=false;/*
notch.frequency.value = 440;
notch.Q.value = 0;*/
//Allpass Filter Setup
allpass = context.createBiquadFilter();
allpass.type="allpass";
allpass.type=ALLPASS;
ap_bool=false;/*
allpass.frequency.value = 440;
allpass.Q.value = 0;*/
};
Toggle Function:
function toggle_filter(filter_name,filter_bool) {
masterVolume.disconnect(0);
// Check if we want to enable the filter.
if (filter_bool==false) {
// Connect through the filter.
masterVolume.connect(filter_name);
filter_name.connect(context.destination);
filter_bool=true;
} else if(filter_bool==true){
filter_name.disconnect(0);
// Otherwise, connect directly.
masterVolume.connect(context.destination);
filter_bool=false;
}
};
Called from buttons:
<div id="filter-container">
<a onclick="toggle_filter(lowpass,lp_bool);" id="filter-button">Lowpass</a>
<a onclick="toggle_filter(highpass,hp_bool);" id="filter-button">Highpass</a>
<a onclick="toggle_filter(bandpass,bp_bool);" id="filter-button">Bandpass</a>
<a onclick="toggle_filter(lowshelf,ls_bool);" id="filter-button">Lowshelf</a>
<a onclick="toggle_filter(highshelf,hs_bool);" id="filter-button">Highshelf</a>
<a onclick="toggle_filter(peaking,pk_bool);" id="filter-button">Peaking</a>
<a onclick="toggle_filter(notch,nh_bool);" id="filter-button">Notch</a>
<a onclick="toggle_filter(allpass,ap_bool);" id="filter-button">Allpass</a>
<div>
Can anyone point me in the direction of where I'm going wrong?
Upvotes: 1
Views: 607
Reputation: 56945
Firstly, you can't have more than one unique id in the DOM. Use class=""
if you want multiple nodes to share an identifier.
Secondly, immediate re-assignments generally don't make sense.
allpass.type="allpass";
allpass.type=ALLPASS;
immediately overwrites the first value set with something else. It's unclear how the variable ALLPASS
was defined in your code, but remove one of these lines -- it's either redundant at best or incorrect at worst (probably the latter).
Thirdly, there's a lot of repeated code. Use an array of filter types, along with knobs for Q, frequency, gain, etc (if desired). The sort of coding that copy-pastes the code over and over is error-prone, unnecessarily verbose, hard to maintain, and if there were hundreds of filter types, virtually impossible to write by hand.
Here's a basic proof of concept to work from:
const makeOsc = ({type, freq}) => {
const oscillator = audioCtx.createOscillator();
oscillator.type = type;
oscillator.frequency.setValueAtTime(freq, audioCtx.currentTime);
return oscillator;
};
const makeFilter = ({type, freq, q, gain}) => {
const filter = audioCtx.createBiquadFilter();
filter.type = type;
filter.frequency.value = freq;
filter.Q.value = q;
filter.gain.value = gain;
return filter;
};
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const filters = [
"lowpass", "highpass", "bandpass", "lowshelf",
"highshelf", "peaking", "notch", "allpass",
];
const filterTest = (() => {
let osc;
let filter;
const start = filterType => {
if (osc) {
stop();
}
osc = makeOsc({type: "sawtooth", freq: 220});
filter = makeFilter({
type: filterType,
freq: 200,
q: 3,
gain: 0
});
osc.connect(filter);
filter.connect(audioCtx.destination);
osc.start();
};
const stop = () => {
if (osc) {
osc.stop();
osc.disconnect();
filter.disconnect();
osc = null;
}
};
const playing = () => !!osc;
return {start, stop, playing};
})();
let filterType = filters[0];
document.querySelector(".filter-type")
.innerHTML = filters.map(e => `<option>${e}</option>`)
;
document.querySelector(".start")
.addEventListener("click", e => filterTest.start(filterType))
;
document.querySelector(".stop")
.addEventListener("click", e => filterTest.stop())
;
document.querySelector(".filter-type")
.addEventListener("change", e => {
const {target: sel} = e;
filterType = sel.options[sel.selectedIndex].value;
if (filterTest.playing()) {
filterTest.start(filterType);
}
});
;
<h1>warning: loud noise</h1>
<select class="filter-type"></select>
<button class="start">start</button>
<button class="stop">stop</button>
Upvotes: 0
Reputation: 13908
You're setting the type to an unknown value after properly setting it to a strung every time. That ends up resetting it to the default - lowpass. Cut the lines that set .type=HIPASS, etc. (Or move them before the corresponding string set.)
Upvotes: 4