Separation of one sound signal into another

Short version

I need to split the audio signal into another (in amplitude). How could I accomplish this in a web audio API without using ScriptProcessorNode ? (with ScriptProcessorNode, the task is trivial, but it is completely unsuitable for production due to its inherent performance problems)

Long version

Consider two sound sources, two OscillatorNodes , for example, oscA and oscB :

 var oscA = audioCtx.createOscillator(); var oscB = audioCtx.createOscillator(); 

Now consider that these oscillators are LFOs, both with low (i.e., <20 Hz) frequencies, and with their signals, which are used to control one AudioParam destination , for example, the gain GainNode . Through various routing settings, we can define the mathematical operations between these two signals.

Adding

If oscA and oscB simultaneously connected to the target AudioParam, their outputs are added together:

 var dest = audioCtx.createGain(); oscA.connect(dest.gain); oscB.connect(dest.gain); 

Subtraction

If the oscB first redirected through another GainNode with a gain of -1 , which then connects to the target AudioParam, then the oscB effectively subtracted from the oscA , because we are effectively doing oscA + -oscB op. Using this trick, we can subtract one signal from another:

 var dest = audioCtx.createGain(); var inverter = audioCtx.createGain(); oscA.connect(dest.gain); oscB.connect(inverter); inverter.gain = -1; inverter.connect(dest.gain); 

Multiplication

Similarly, if the oscA output oscA connected to another GainNode, and the oscB output oscB connected to the AudioParam gain of this GainNode, then oscB multiplies the oscA signal:

 var dest = audioCtx.createGain(); var multiplier = audioCtx.createGain(); oscA.connect(multiplier); oscB.connect(multiplier.gain); multiplier.connect(dest.gain); 

Department (?)

Now I want the output of oscB to split the output of oscA . How to do this without using ScriptProcessorNode?


Edit

My previous, absolutely ridiculous attempts to solve this problem:

  • Using PannerNode to control the positionZ parameter, which gave a result that decreased with increasing signal B ( oscB ), but was completely turned off (for example, it gave 12/1 = 8.5 and 12/2 = 4.2 ) - now this value can be compensated using a GainNode with a gain set to 12 / 8.48528099060058593750 (approximation), but only supports values >=1
  • Using AnalyserNode to quickly select an audio signal and then use this value (LOL)

Edit 2

The reason ScriptProcessorNode is practically useless for applications more complex than the technology demo is as follows:

  • it performs sound processing in the main stream (!), and hard work in the user interface will lead to system malfunctions.
  • a single, dead simple ScriptProcessorNode will consume 5% of the processor power on a modern device, since it performs JavaScript processing and requires data transfer between the audio stream (or rendering stream) and the main stream (or user interface stream)
+7
javascript web-audio-api
source share
1 answer

It should be noted that ScriptProcessorNode deprecated .

If you need A/B , you will need 1/B , an inverted signal. You can use WaveShaperNode to do the inverse. For this node needs an array of corresponding values. Inversion means that -1 becomes -1, -0.5 is -2, etc.

Also, make sure you know about division by zero. You have to handle this. In the following code, I just take the next value after zero and double it.

 function makeInverseCurve( ) { var n_samples = 44100, curve = new Float32Array(n_samples), x; for (var i = 0 ; i < n_samples; i++ ) { x = i * 2 / n_samples - 1; // if x = 0, let reverse value be twice the previous curve[i] = (i * 2 == n_samples) ? n_samples : 1 / x; } return curve; }; 

The work of the script is here . If you remove .connect(distortion) from the audio chain, you will see a simple sine wave. Visualization code obtained from sonoport .

+1
source share

All Articles