-
Notifications
You must be signed in to change notification settings - Fork 166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add NoiseGenerator Node #2416
Comments
I agree, I consider this lack an important shortcoming of the spec. |
I don't have any real objections to a white noise generator. |
Are we okay with the disparity from different vendors? If not, this should be defined clearly in the spec with formula or algorithm. I believe there are several ways of creating noise (some are complex), but I am not sure what needs to be specified: how do we define a 'spec-compliant' noise generator? SNR? Distribution? Also if we are too strict about the noise generation process, I can already imagine the situation like: 'the noise generation in the spec is boring, I will just do it in my AudioWorker'. In my view, it goes both ways - would love to hear what others think. |
AFAIK white noise is just a sequence of random samples. Different browsers will have different algorithms for random number generation, but unless they are flawed (see http://hackaday.com/2015/12/28/v8-javascript-fixes-horrible-random-number-generator/), the difference should not be audible. Other than that, of course there should be no reuse of previous sequences of random samples: each new sample should be freshly generated by the RNG. For example, here is how I currently do noise on a ScriptProcessorNode: processAudio(evt) {
for (let channel = 0; channel < evt.outputBuffer.numberOfChannels; channel++) {
const out = evt.outputBuffer.getChannelData(channel);
for (let sample = 0; sample < out.length; sample++)
out[sample] = this.playing ? this.gain * (Math.random() * 2 - 1) : 0;
}
} By the way, if you see something wrong, please let me know. |
To me white noise has always been random samples, as lcrespom shows. Questions that come to my mind:
And while we're dreaming, a constant source node would be kind of nice to have, even though it's pretty trivial do to, but perhaps a bit heavy-weight to use an AudioBufferSource node to do it. |
White noise would be a series of random samples, vendors using their browser implementations standard RNG is probably fine now that v8 has fixed that huge issue. Probably shouldn't call a node 'NoiseGenerator' if it can only do one type of noise though. It'd be cool to have the full colour spectrum to choose from, but then we're getting into the "is this really necessary" territory. Playing "angel's advocate", the algorithms to generate the other kinds of noise are very straightforward, all of the noises in the "technical definitions" section of that article can be scaled with bitwise multiplication in the frequency domain, and it'd be useful to have functions for generating Ndb/octave decay and equal loudness curves. |
(not to mention all of the wonderful uses of noise as an AudioParam) |
Yeap. I would say if we decide to make this happen, we need to cover as
|
@hughrawlinson noise as an AudioParam should allow for Sample & Hold, so the user can specify the duration of each random number. That is how old synths do their noise LFO wave. |
About white noise, I think the first thing need to be decided is Gaussian or not. These are not so different audibly, but have different loudness (if same peak amplitude), and have different behavior especially when used as S&H source. Because Gaussian is more match to natural phenomena, white noise in analog synths are Gaussian. it can be generated by a box-muller's method or some approximation. IMO (as a user), not need the exactly same number sequence but need exactly same distribution(sigma). |
On Thu, Jan 21, 2016 at 11:53 AM, Hugh Rawlinson notifications@github.com
Not exactly sure what "bitwise multiplication in the frequency domain"
Ray |
Note that it's important for noise generators to NOT have the same sequence On Fri, Jan 22, 2016 at 9:20 AM, rtoy notifications@github.com wrote:
|
Since WebAudio provides both biquad and IIR filters, the noise generator doesn't need to provide all the different kinds of colored noise. The user can do the appropriate filtering, so the noise generator only needs to provide white noise (with some appropriate sample distribution). |
The pink noise is a bit trouble because that needs a -3dB/Oct filter. The easiest way is FIR filter using convolver. |
I think this is a good reason just to spec a white noise generator and let the user color it however he wants to color it. |
I believe we should be able to create a 3dB/Oct IIR filter using the new IIRFilterNode. |
Yeap. That's what Ray was talking about. Still, I think the variable sample
|
Sounds great, |
Why do you need three IIRFilterNodes? One should be enough. |
Thank you. I have misunderstood. The introduced document use summing three 1st order IIR but we can do that with one high-order IIRFilterNode, right? |
Yup.
This would be a single 3rd order IIRFilter. |
What I would love to see is:
The coloring is a bit tricky to be specified except for widely-accepted noise types and also it easily can be done with IIR or convolver. |
This is being moved to V.next - although the group can see the benefit of this and it would be a welcome feature, it can be solved with the audio worker for V1 and effort shoudl really be concentrated there rather on new nodes. |
This is where we would benefit from encapsulation/layering. I could wrap a Gaussian noise generator and a particular filter, and expose that as one composite "pink noise" node. |
F2F resolution:
|
For LabSound, (a fork of webkit's WebAudio for use outside of browsers, http://labsound.io) - we implemented a simple NoiseNode in our extended node API. https://github.com/LabSound/LabSound/blob/master/include/LabSound/extended/NoiseNode.h We used the white/brown/pink generator from here, http://noisehack.com/generate-noise-web-audio-api/ as it met our needs, and is very fast to execute in a callback. |
Rough proposal:
The proposed RNG to use is the minimal C (reference) implementation: https://github.com/imneme/pcg-c-basic. This is small and fast and passes all the tests for randomness. It is specifically not crypto safe. If the seed is not given, the browser initializes it as desired, with the only requirement is that it is not a constant. (Or maybe we should specify a default seed?) For a given seed and sequenceNumber, the every browser must produce exactly the same sequence of numbers for a uniform source. For Gaussian, browsers may very depending on the algorithm used to generate the Gaussian. |
Hmm. Need to describe the algorithm for going from a 32-bit random integer to a single-precision float. That's not given in the references above. |
Previously in https://github.com/WebAudio/web-audio-api-v2/issues/8#issuecomment-519621343, the node had
This allowed you to examine the internal state of the generator. You could get the internal state, but it wasn't useful because we didn't provide a method for you to update the internal state of a generator. So I removed it. This means you couldn't inspect a noise node and create a new node that would start off with exactly the same values as the original node. But that wasn't really feasible anyway unless you stopped the context to get a stable value of the state and initialized the new node with that state. (But you couldn't create the node with that state; you only have the seed which is used with the sequence number to create the state.) Is that important to anyone? And then, do you want to node to do S/H of the values? That's not currently part of the proposed spec. We can add that. |
@guest271314 Your example in https://github.com/WebAudio/web-audio-api-v2/issues/8#issuecomment-710193331 doesn't generate white noise AFAICT. Looks like it randomly selects one of the oscillator types and then a random frequency. That's not white noise, which is what we want here. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
White noise is a random process with a constant power spectral density. |
This comment has been minimized.
This comment has been minimized.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Oh, I didn't know Javascript has BigInt now. And Chrome Beta and Firefox Developer support it. This would make for a nicer API. But it looks like WebIDL doesn't currently support BigInt, so perhaps we're stuck with using arrays to specify the seed. |
Anyway, here is a proposal assuming we had BigInt:
|
Some naive questions trying to help out on the BigInt side. I tried to answer these by reading upthread but I couldn't find them easily, probably because this is mostly domain experts talking and goes above my head :).
To be clear, I am completely ready to believe this is best done with 64-bit ints, and am excited about BigInt getting its first web platform use case. I just want to make sure we have all our reasoning lined up, so that we can set a nice precedent for the future. Code to reinterpret a 64-bit float as a 64-bit intconst buffer = new ArrayBuffer(8);
const intView = new BigInt64Array(buffer);
const floatView = new Float64Array(buffer);
floatView[0] = Math.PI;
console.log(intView[0]); |
This comment has been minimized.
This comment has been minimized.
The algorithms used by the pcg generator specify a 64-bit seed. Using only 32 bits would restrict the the set of possible sequences, or make the sequences less random. I don't know how to analyze such things. (Emails to the author have been unanswered.) 53 bits might be enough, but again I don't know. (We previously allowed you to examine the state of the generator of 64 bits, and all of those are needed exactly as is.) Yes, using a double and treating it as a 64-bit integer could work too. But there's a huge range of values that are NaNs that would be hard to get. To get the full range, you'd basically do the opposite of your code to reinterpret doubles to 64-bit ints. This would be a rather unnatural interface. For BigInts, we'd probably just take the low 64 bits to get the seed we need. BigInts provide a reasonably natural interface that reflects the pcg describes. Without BigInts, I think the best interface would be an array of 2 32-bit integers (or any other integer array that has 64 bits total). In conclusion, BigInts provide a natural interface, but it's not strictly required. An array of integers works fine. Using fewer than 64 bits has unknown effects on the quality of the generated output. |
This comment has been minimized.
This comment has been minimized.
Since whatwg/webidl#525 has been merged, perhaps we should use BigInt's for the interface. It may take some time before browsers get around to supporting this WebIDL feature though. Not sure how we want to deal with that. |
Teleconf: Generally agreed not use bigints in the interface; an array is good enough. We can add it later if desired. |
F2F meeting: Agreed that the API is correct except BigInt should not be used. Michel Buffa will look at some Faust code and possibly propose some additional noise types if they are recognized as good methods for generating such noise. |
Here's the updated API using arrays:
The RNG to use is the minimal C (reference) implementation: https://github.com/imneme/pcg-c-basic. This is small and fast and passes all the tests for randomness. It is specifically not crypto safe.
The 64-bit seed,
That is, the first element of
The array
If
Conversely, two For any given seed and sequence number, every UA must produce exactly the sequence of numbers when the type is "uniform". For "gaussian", this is not required; UAs are free to choose any appropriate algorithm to generate Gaussian noise. |
current possible choice may be:
I think it is a bit cumbersome relative to other basic waveform.
hopefully, white / pink switchable is great.
The text was updated successfully, but these errors were encountered: