Skip to content
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

Easy way to get single most recent sample #493

Closed
adelespinasse opened this issue Mar 11, 2015 · 4 comments
Closed

Easy way to get single most recent sample #493

adelespinasse opened this issue Mar 11, 2015 · 4 comments

Comments

@adelespinasse
Copy link

Now that AnalyserNode has getFloatTimeDomainData, it's pretty easy to grab samples from an audio connection when you need them for something like a VU meter or other visualization. But I think a very common need is to get just the single most recent sample value, and AnalyserNode still doesn't support that in the most convenient or efficient way.

The minimum value for fftSize, which also controls the size of time domain outputs, is 32. You can give getFloatTimeDomainData a smaller array to fill, in which case "excess elements will be dropped", but I assume that means the later samples are dropped and you only get the first N samples (though this isn't explicitly said). So if you want to be sure you're getting the single most recent available sample, you'd have to give it an array of size 32, and then pick out the last value. This means getFloatTimeDomainData is copying 32 values when only one is needed. (Unless it somehow manages to avoid copying, but this doesn't seem likely since the array is provided by the caller.)

I don't think it would make sense to allow fftSize to be 1. But on the other hand, it doesn't make much sense for fftSize to control the size of the output of getFloatTimeDomainData. One solution would be for getFloatTimeDomainData to ignore fftSize and just fill in the passed-in array of size N with the most recent N samples, whatever N is. This might not be backwards compatible, though.

Another solution would be for AnalyserNode to have a simple function that would return the most recent sample value.

Or there could just be a function on every node to return the most recent sample value of [a specified channel of] a specified output. Probably not worth it though, since it would complexify the AudioNode interface for relatively little-used functionality.

@cwilso
Copy link
Contributor

cwilso commented Mar 11, 2015

"The single most recent sample value" is not really an obviously rational concept in this context. Remember that web audio is happening on a separate thread; the samples need to be transferred over from a different thread (which has some latency and cost). In general, of course, you're not going to need EVERY sample this way - you either want to sample a very-low-frequency signal that isn't changing much (e.g. - the gain multipliers for each band in my vocoder's band display - https://webaudiodemos.appspot.com/Vocoder/index.html, hit play and watch the middle box on the right), in which case you don't want EVERY instantaneous value, you want them on a visual update refresh cycle - or you want to do some kind of instant value access to do something like clip detection. This latter should be done in an Audio Worker, not marshalled across to the main thread.

In short, I'll challenge the statement "I think a very common need is to get just the single most recent sample value" without some distinct use cases that should be solved this way. Synchronously obtaining that value is not possible (because it's across thread boundaries, it has to be asynchronously communicated), so it would need to be designed appropriately.

@adelespinasse
Copy link
Author

True, "most recent" isn't very clear. What I really mean is "the latest sample value that can be efficiently retrieved". That would probably be buf[127] of the most recently completed output block of whatever node is producing the input.

(Note that the spec for get*TimeDomainData says it returns "the current time-domain data", which is about as clear as saying "most recent".)

Insisting on the "latest" sample probably isn't a big win, since as you say the typical use case would be to grab one value of a slowly-changing signal on each visual update, and so being an additional 32 samples behind (or even 128) probably isn't a big deal. But it seems to me like it might as well be the latest sample. You want it to be a sample that will make it through the output buffer as soon as possible, in order to keep in sync with visual updates.

I'm not even sure any cross-thread synchronization would be necessary. (Not having looked at actual implementations... I should remedy that sometime.) Assuming each output of each node is written to the same 128-frame buffer every time the node runs, and assuming that buffer can be read from the UI thread, it could just grab buf[127]. That would usually be the most recent value; if the node is currently calculating its next block of output, it might not be the very latest, but it would be close. Unless the node uses its own output buffers as temporary scratch space; that would be a problem.

Anyway, I've spent more time typing this up than it was probably worth. It's definitely not high priority. Just a convenience/optimization feature request that I think many developers might find handy. Please don't let it slow down version 1.0 of the spec (any more than it has already... sorry).

@notthetup
Copy link
Contributor

I needed something similar to implement a 'play/pause' functionality in Sonoport's Sound Models.

My hack around it was to have a ScriptProcessor which records the value of the last sample it plays through. If you're not concerned with sample accuracy, then this scheme works well.

https://github.com/Sonoport/soundmodels/blob/master/src/lib/core/SPAudioBufferSourceNode.js#L362

I am, though, hoping that at some point, the BufferNode could expose a playbackPosition property.

https://github.com/WebAudio/web-audio-api/issues/296

@mdjp
Copy link
Member

mdjp commented Apr 16, 2015

This can be solved with the Audio Worker.

@mdjp mdjp closed this as completed Apr 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants