Old 01-12-2021, 06:43 PM   #1
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default JSFX Autocorellation

*EDIT* This is pretty much working now, making this the everything autocorellation thread!

Hi everyone, new to the JS forums but been messing about in JSFX for a good while now and am becoming comfortable with it. I am currently trying to implement an algorithm that accumulates total energy across a certain timespan. To do this efficiently, it needs to add the latest sample, and subtract that sample's value back out later using a delay line.

In trying to get this working, I am seeing some drifty numerical wackiness, which I am blaming on the inaccuracies that result from adding tiny floating point numbers to the rather large accumulated one.

As far as I can tell, JS uses exclusively 64-bit floats for everything. Is there some way I can force it to a use a certain fixed precision for this?

Last edited by noouch; 01-14-2021 at 12:37 AM.
noouch is offline   Reply With Quote
Old 01-13-2021, 12:36 AM   #2
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,688
Default

What do you mean by "fixed precision" ?
64 bit float format provides a "fixed precision" of about 48 bits. That is some 10e-14. I suppose that there are not that many relevant algorithms that need more. Do check your algorithm on that behalf. Maybe some math can modify it to be less prone to the effects you see.

To get a better precision some very hard software means need to be applied, as the computer hardware can't do this.

-Michael

Last edited by mschnell; 01-13-2021 at 08:37 AM.
mschnell is offline   Reply With Quote
Old 01-13-2021, 06:22 AM   #3
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Sounds like some kind of moving average? Shouldn't need huge precision, altho' a "simple moving average" can be a bit wacky all on its own. If the input is peaky.
__________________
it's meant to sound like that...
jrk is offline   Reply With Quote
Old 01-13-2021, 07:34 AM   #4
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

I'm gonna be "that guy" (again)...what kind of "certain timespan" are you thinking of? What's your aim with this?

Have you considered the (cheap to compute) exponential moving average?
(2x multiply and 1 addition per sample)
__________________
it's meant to sound like that...

Last edited by jrk; 01-13-2021 at 08:57 AM.
jrk is offline   Reply With Quote
Old 01-13-2021, 01:43 PM   #5
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default

I'm trying to implement autocorrelation as outlined in the Autotune patent, which is done with four multiply-adds per lag per sample.

Basically it involves keeping a series of moving averages across lengths ranging from a couple up to 880 samples. It's an awesomely elegant approach, but for perfect accuracy it requires that the number added is EXACTLY the number subtracted 880 samples later.

I tried filtering out the drift with a DC offset filter, and briefly tried something like an exponential moving average, but wasn't able to get any usable results from either. As far as I can tell, this approach requires equal-weight averages, and doesn't respond well to drift. The numbers not being subtracted back out is clearly visible when I plot the values

Of course my code could be wrong as well, it almost looks like it's barely subtracting the values out at all. Maybe I'm chasing a red herring here and the issue is something else.

Last edited by noouch; 01-13-2021 at 02:01 PM.
noouch is offline   Reply With Quote
Old 01-13-2021, 03:25 PM   #6
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Oh, well, I've never done anything like that... I gather fft is a (computationally heavy?) of getting autocorrelation.

Have you seen JS: FFT Peak-Following Filter?

As far as a simple moving average goes, I've got something like this, which was for a jsfx compressor that I never finished.

the circular buffer (array) remembers scaled values. It has LENGTH slots.

Code:
@sample 
new_value = abs(spl0);


sample_count += 1;
idx = sample_count % LENGTH;

avg -= array[idx];
avg += new_value / LENGTH;

array[idx] = new_value / LENGTH;
__________________
it's meant to sound like that...

Last edited by jrk; 01-13-2021 at 03:41 PM.
jrk is offline   Reply With Quote
Old 01-13-2021, 04:06 PM   #7
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default

Yeah that's pretty much what I'm doing, but I'm beginning to suspect the problem is something else, like not indexing the array properly or something.

The cool thing about doing autocorellation in the time domain is that, on top of it being fast to compute, tracking is pretty much instantaneous, down to a half-cycle or so. It's that accurate and precise tracking that enables the pitch shifting portion to be dead-simple and avoid getting into stuff like PSOLA etc.
noouch is offline   Reply With Quote
Old 01-13-2021, 09:42 PM   #8
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default

HECK YEAH IT WORKS!

At some point it occurred to me that I may be off by one or something silly like that in my array indexing, so on a whim I increased my delay buffer size 50x, which reduced my error by 50x. Lesson learned: superstitiously add 1 to however many indices I think an array needs.

The results are magical:

noouch is offline   Reply With Quote
Old 01-14-2021, 12:47 AM   #9
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default

Implemented the detection test also outlined in the patent. Every once in a while it glitches, but 99.9% of the time it really sticks like glue!



Right now I'm downsampling the audio to 1/8 for efficiency, thinking it might be time to try it on the full-res signal for perfect tracking.

Last edited by noouch; 01-14-2021 at 12:53 AM.
noouch is offline   Reply With Quote
Old 01-14-2021, 12:51 AM   #10
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Quote:
Originally Posted by noouch View Post
HECK YEAH IT WORKS!

superstitiously add 1 to however many indices I think an array needs.

Ah, the off-by-one error. It's a classic.

I hope you release this when it's done, I'd love to see it.
__________________
it's meant to sound like that...
jrk is offline   Reply With Quote
Old 01-14-2021, 12:01 PM   #11
Ozman
Human being with feelings
 
Join Date: Feb 2015
Posts: 753
Default

NI Form uses PSOLA.
Great for some things, but really alters some sounds.
Ozman is offline   Reply With Quote
Old 01-14-2021, 12:41 PM   #12
noouch
Human being with feelings
 
Join Date: Aug 2008
Posts: 37
Default

Quote:
Originally Posted by Ozman View Post
NI Form uses PSOLA.
Great for some things, but really alters some sounds.
So the thing about PSOLA is that it smudges and colors the sound a lot. The AT patent says that the "overlap" part is not necessary; just advance the delay read head if we're flat, and retard it if we're sharp. And if we run out of room? We know exactly how long one cycle is, so just jump back by that many samples. No multiply-adds, no spectral voodoo magic, dead simple. Definitely a hell of a lot simpler than the "phase vocoder" approach I sometimes see being associated with autotune.
noouch is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 05:16 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.