Isolate ultrasounds with Web Audio API - javascript

There is any algorithm that I can use with Web Audio Api to isolate ultrasounds?
I've tried 'highpass' filters but I need to isolate sounds that are ONLY ultrasounds (horizontal lines) and ignore noises that are also sounding at lower audible frequencies (vertical lines).
var highpass = audioContext.createBiquadFilter();
highpass.type = 'highpass';
highpass.frequency.value = 17500;
highpass.gain.value = -1
Here's a test with a nice snippet from http://rtoy.github.io/webaudio-hacks/more/filter-design/filter-design.html of how the spectrum of audible noise interferes with filtered ultrasound: (there are 2 canvas, one without the filter and one with the filter https://jsfiddle.net/6gnyhvrk/3
Without filters:
With 17.500 highpass filter:

A highpass filter is what you want, but there are a few things to consider. First, the audio context has to have a high enough sample rate. Second, you have to decide what "ultrasound" means. Many people can hear frequencies above 15 kHz (as in your example). A single highpass filter may not have a sharp enough cutoff for you so you'll need to have a more complicated filter setup.

Related

In the Web Audio API, is there a way to set a maximum volume?

I know you can boost or reduce volume with gain. I was wondering if there was a way (perhaps via a node) to cap the maximum volume of the output - not reducing any audio below that max value. It is acceptable if there is distortion for audio that gets capped like this.
An alternative that might be simpler is to use a WaveShaperNode. I think a curve equal to [-1, 0, 1] will do what you want, clamping values to +/-1. If you don't oversample, there won't be any additional delay.
Note that I'm pretty sure all browsers implement this kind of clamping before sending audio to the speakers.
This is not possible with any of the built-in AudioNodes. But it can be achieved with a custom AudioWorklet. I recently published a package which does exactly that. It's called limiter-audio-worklet.
It exports two functions:
import { addLimiterAudioWorkletModule, createLimiterAudioWorkletNode } from 'limiter-audio-worklet';
The first function can be used to add the AudioWorklet to a particular AudioContext.
await addLimiterAudioWorkletModule((url) => {
audioContext.audioWorklet.addModule(url);
});
Once that is done the actual AudioWorkletNode can be created like this:
const limiterAudioWorkletNode = createLimiterAudioWorkletNode(
AudioWorkletNode,
audioContext,
{ attack: 0 }
);
If you set the attack two zero you get the desired effect. Everything above +1/-1 gets clamped. If you increase the attack it will transition smoother using a look ahead. This will introduce a small delay (of the same size) but sounds much nicer.
Of course it's also necessary to connect the previously created limiterAudioWorkletNode close to the end of your audio graph.
yourLastAudioNode
.connect(limiterAudioWorkletNode)
.connect(audioContext.destination);

Next steps to do with the mfccs, in voice recognition web based

I am working on urdu (language spoken in pakistan, india, bangladesh) voice recognition to translate urdu speech into urdu words. So far i did nothing but just have found meyda javascript library for extracting mfccs from data frames. Some document says that for ASR there needs first 12 or 13 mfccs out of 26. During the test, i have separate 46 phonemes(/b/, /g/, /d/ ...) in a folder in wav extension. After running meyda proccess on one of the phoneme, it creates 4 to 5 frames per phoneme, where each frame contain the mfccs each of first 12 values. Due to less than 10 reputation, post images are disabled. but you can the image on the following link. The image contain 7 frames of phoneme /b/. each frame includes 13 mfccs. The Red long vertical line value is 438, others or 48, 38 etc.
http://realnfo.com/images/b.png
My question is that whether i need to save these frames(mfccs) in the database as predefined phoneme for /b/ and the same i do for all the other phonemes and then tie the microphone, meyda will extract the mfccs per frame, and i will programmed the javascript that the extracted frame mfcc will be matched with the predefined frames mfccs by using Dynamic Time Warping. And at the end will get the smallest distance for specific phoneme.
The proffesional way after mfccs are HMM and GMM but i dont know how to deal with. i studied so many documents about HMM and GMM but waste.
co-author of Meyda here.
That seems like a pretty difficult use case. If you already know how to split the buffers up into phonemes, you can run the MFCC extraction on those buffers, and use k Nearest Neighbour (or some better classification algorithm) for what I would imagine would be reasonable success rate.
A rough sketch:
const Meyda = require('meyda');
// I can't find a real KNN library because npm is down.
// I'm just using this as a placeholder for a real one.
const knn = require('knn');
// dataset should be a collection of labelled mfcc sets
const nearestPhoneme = knn(dataset);
const buffer = [...]; // a buffer containing a phoneme
let nearestPhonemes = []; // an array to store your phoneme matches
for(let i = 0; i < buffer.length; i += Meyda.bufferSize) {
nearestPhonemes.push(nearestPhoneme(Meyda.extract('mfcc', buffer)));
}
After this for loop, nearestPhonemes contains an array of the best guesses for phonemes for each frame of the audio. You could then pick the most commonly occurring phoneme in that array (the mode). I would also imagine that averaging the mfccs across the whole frame may yield a more robust result. It's certainly something you'll have to play around with and experiment with to find the most optimal solution.
Hope that helps! If you open source your code, I would love to see it.

Web Audio API - Removing filter

I'm building a visualiser with multiple graphic modes. For a few of them I need to calculate the beat of the track being played, and as I understand I then need to apply a lowpass filter like the following, to enhance frequencies that are most probable to hold drum sounds:
var filter = context.createBiquadFilter();
source.connect(filter);
filter.connect(context.destination);
filter.type = 'lowpass';
But what if I want to turn the filter off? Do I have to re-connect the source every time I need to remove the filter? Would this have any negative effect on performance?
Related question: how much performance loss would I experience if I have two two sources, from the same audio source, and apply the filter to one of them?
how much performance loss would I experience if I have two two sources, from the same audio source, and apply the filter to one of them
You can connect a single audio node to multiple destinations, thus you never need a duplicate source just to spread-connect it. If you need filtered and raw audio simultaneously, you can just setup your connections accordingly:
var filter = context.createBiquadFilter();
source.connect(filter);
source.connect(context.destination);
filter.connect(context.destination);
filter.type = "lowpass";
Anyways, setting the type property of a FilterNode to "allpass" will effectively disable all filtering, without having to reconnect:
filter.type = "allpass"
According to article WebAudio intro | html5rocks, I would have to toggle the filter on and off, by disconnecting the source and itself like so:
this.source.disconnect(0);
this.filter.disconnect(0);
// Check if we want to enable the filter.
if (filterShouldBeEnabled) {
// Connect through the filter.
this.source.connect(this.filter);
this.filter.connect(context.destination);
} else {
// Otherwise, connect directly.
this.source.connect(context.destination);
}

Generate a non-sinusoidal tone

Is it possible to generate a tone based on a specific formula? I've tried googling it, but the only things I could find were about normal sine waves, such as this other SO question. So I was wondering if it is possible to generate tones based on other kinds of formulas?
On that other SO question, I did find a link to this demo page, but it seems like that page just downloads sound files and uses them to just alter the pitch of the sounds.
I've already tried combining sine waves by using multiple oscillators, based on this answer, which works just as expected:
window.ctx = new webkitAudioContext();
window.osc = [];
function startTones() {
osc[0] = ctx.createOscillator(),
osc[1] = ctx.createOscillator()
osc[0].frequency.value = 120;
osc[1].frequency.value = 240;
osc[0].connect(ctx.destination);
osc[1].connect(ctx.destination);
osc[0].start(0);
osc[1].start(0);
}
function stopTones() {
osc[0].stop(0);
osc[1].stop(0);
}
<button onclick="startTones();">Start</button>
<button onclick="stopTones();">Stop</button>
So now I was wondering, is it possible to make a wave that's not based on adding sine waves like this, such as a sawtooth wave (x - floor(x)), or a multiplication of sine waves (sin(PI*440*x)*sin(PI*220*x))?
PS: I'm okay with not supporting some browsers - as long as it still works in at least one (although more is better).
All (periodic) waves can be expressed as the addition of sine waves, and WebAudio has a function for synthesising a wave form based on a harmonic series, context.createPeriodicWave(real, imag).
The successive elements of the supplied real and imag input arrays specify the relative amplitude and phase of each harmonic.
Should you want to create a wave procedurally, then in theory you could populate an array with the desired waveform, take the FFT of that, and then pass the resulting FFT components to the above function.
(WebAudio happens to support the sawtooth waveform natively, BTW)

Multi-tempo/meter js DAW

Has anyone implemented a javascript audio DAW with multiple tempo and meter change capabilities like most of the desktop daws (pro tools, sonar, and the like)? As far as I can tell, claw, openDAW, and web audio editor don't do this. Drawing a grid meter, converting between samples and MBT time, and rendering waveforms is easy when the tempo and meter do not change during the project, but when they do it gets quite a bit more complicated. I'm looking for any information on how to accomplish something like this. I'm aware that the source for Audacity is available, but I'd love to not have to dig through an enormous pile of code in a language I'm not an expert in to figure this out.
web-based DAW solutions exists.web-based DAW's are seen as SaaS(Software as a Service) applications.
They are lightweight and contain basic fundamental DAW features.
For designing rich client applications(RCA) you should take a look at GWT and Vaadin.
I recommend GWT because it is mature and has reusable components and its also AJAX driven.
Also here at musicradar site they have listed nine different browser based audio workstations.you can also refer to popcorn maker which is entirely javascript code.You can get some inspiration from there to get started.
You're missing the last step, which will make it easier.
All measures are relative to fractions of minutes, based on the time-signature and tempo.
The math gets a little more complex, now that you can't just plot 4/4 or 6/8 across the board and be done with it, but what you're looking at is running an actual time-line (whether drawn onscreen or not), and then figuring out where each measure starts and ends, based on either the running sum of a track's current length (in minutes/seconds), or based on the left-most take's x-coordinate (starting point) + duration...
or based on the running total of each measure's length in seconds, up to the current beat you care about.
var measure = { beats : 4, denomination : 4, tempo : 80 };
Given those three data-points, you should be able to say:
var measure_length = SECONDS_PER_MINUTE / measure.tempo * measure.beats;
Of course, that's currently in seconds. To get it in ms, you'd just use MS_PER_MINUTE, or whichever other ratio of minutes you'd want to measure by.
current_position + measure_length === start_of_next_measure;
You've now separated out each dimension required to allow you to calculate each measure on the fly.
Positioning each measure on the track, to match up with where it belongs on the timeline is as simple as keeping a running tally of where X is (the left edge of the measure) in ms (really in screen-space and project-coordinates, but ms can work fine for now).
var current_position = 0,
current_tempo = 120,
current_beats = 4,
current_denomination = 4,
measures = [ ];
measures.forEach(function (measure) {
if (measure.tempo !== current_tempo) {
/* draw tempo-change, set current_tempo */
/* draw time-signature */
}
if (measure.beats !== current_beats ||
measure.denomination !== current_denomination) {
/* set changes, draw time-signature */
}
draw_measure(measure, current_position);
current_position = MS_PER_MINUTE / measure.beats * measure.tempo;
});
Drawing samples just requires figuring out where you're starting from, and then sticking to some resolution (MS/MS*4/Seconds).
The added benefit of separating out the calculation of the time is that you can change the resolution of your rendering on the fly, by changing which time-scale you're comparing against (ms/sec/min/etc), so long as you re-render the whole thing, after scaling.
The rabbit hole goes deeper (for instance, actual audio tracks don't really care about measures/beats, though quantization-processes do), so to write a non-destructive, non-linear DAW, you can just set start-time and duration properties on views into your audio-buffer (or views into view-buffers of your audio buffer).
Those views would be the non-destructive windows that you can resize and drag around your track.
Then there's just the logic of figuring out snaps -- what your screen-space is, versus project-space, and when you click on a track's clip, which measure, et cetera, you're in, to do audio-snapping on resize/move.
Of course, to do a 1:1 recreation of ProTools in JS in the browser would not fly (gigs of RAM for one browser tab won't do, media capture API is still insufficient for multi-tracking, disk-writes are much, much more difficult in browser than in C++, in your OS of choice, et cetera), but this should at least give you enough to run with.
Let me know if I'm missing something.

Categories

Resources