Latency "trick ?" in Pitch Transposition algo.

Algorithm development and general DSP issues

Moderator: frank

Post Reply
Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Latency "trick ?" in Pitch Transposition algo.

Post by Dedjazzgadgetz » Tue Dec 17, 2013 7:40 pm

Dear Frank :

I'm having one of those -"uh? say what ?" moments, again...

...quote from donstavely http://www.spinsemi.com/forum/viewtopic.php?p=1506#1506 :
-"Here is one quick and easy trick that reduces the pitch shift latency by 25%: If you look closely at the behavior of the crossfade generation associated with the ramp LFO's, you will see that their value is zero for the first and last 1/8th of the total delay length. So instead of writing your input signal to the head-end of the delay, you just write it 1/8 of the way in. Say for a 4096 word delay, instead of "wra DELAY" you just use "wra DELAY+512". Since the crossfade starts at word 512, you just saved 512 samples worth of unnecessary delay."

I fail to understand the wizardry! that forces the Ramp itself to arbitrarily jump-start from nowhere ?... in other words : what mechanism (hardware, i'm guessing ?) links a Ramp/crossfade-generation to a given memory allocation ? How does leaving-out the first 512 sample mem. slots blank (wra DELAY+512 in this example) makes the ramp (and it's associated crossfade) go :

"-'know what? I'm not gonna start at 0... I'll preset myself to 0,125. There. -HA!"

There's gotta be something more to it, right ?... a whole lot more !? (in addition to having to detect memory position 7/8, in order to JAM the Ramp to 0 -erh, I mean... 0.125 !? HELP ! )
Read all I thought was relevent so, please Don, anybody... feel free to pitch-in; it's drivin' me craaii-zy ! ) Thanks in advance !

Dedjazzgadgetz
(tryin', but not quite gett'n'it ...at all !)
Last edited by Dedjazzgadgetz on Tue Dec 17, 2013 9:55 pm, edited 2 times in total.

frank
Posts: 991
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank » Tue Dec 17, 2013 8:01 pm

I really can't go into all the hardware that makes the ramp, cross fade coefficient, etc. Lots of details in it, just accept that the system generates the proper ramps and cross fade coefficients.

Now donstavely is correct in that writing into the buffer could shorten the delay but it can cause an audible discontinuity. Ramps are used and crossed between the pointers to try to hide the discontinuity as the pointer wraps around the buffer, by writing higher into the buffer you are allowing old/wrong data to be used until the pointer hits the write point.
Frank Thomson
Experimental Noize

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Tue Dec 17, 2013 8:42 pm

frank wrote:I really can't go into all the hardware that makes the ramp, cross fade coefficient, etc. Lots of details in it, just accept that the system generates the proper ramps and cross fade coefficients.

-yeah, sure: from having built discrete counters & stuff (that's sooo long ago...), I totally get that, no prob.

Now donstavely is correct in that writing into the buffer could shorten the delay but it can cause an audible discontinuity. Ramps are used and crossed between the pointers to try to hide the discontinuity as the pointer wraps around the buffer, by writing higher into the buffer you are allowing old/wrong data to be used until the pointer hits the write point.

-Now, that's my point... this idea probably refers to his "pretty convoluted/burns pretty much all of the code space" octave up/down uber-program, using s/w-generated ramps for pitch & crossfade, I'm guessing... (oooh : I'd love Don to confirm this, so I can sleep tonight :wink: )
So, the short of it, you're saying : I can reset an internal Ramp (using JAM), but I can't tell it to "get ahead of itself" (arbitrarily start from a preset point in its cycle, namely 1/8 into it)... right ?

Dedjazzgadgetz
Last edited by Dedjazzgadgetz on Tue Dec 17, 2013 8:52 pm, edited 1 time in total.

frank
Posts: 991
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank » Tue Dec 17, 2013 8:49 pm

Correct, you cannot set the ramp to an arbitrary point. And, while thinking about it, the trick really won't work. Since the buffer is circular the length is fixed so where you write is not really going to effect the latency.
Frank Thomson
Experimental Noize

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Tue Dec 17, 2013 9:22 pm

Thanks Frank !

You've transmorgrified my "say what ?" moment into an : a-HA ! knew it orgasm...

Again, thanks for all the dedication you put into explaining stuff over, & over, & over...

Dedjazzgadgetz
(still, I'll grind over this... maybe I could... ? )

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Tue Dec 17, 2013 11:08 pm

Someone stop me, please ! Can't help myself... :oops:

-Would the Assembler categorically refuse to let me program a pitch transposer algo. with an internal "4096" Ramp (so far, so good), BUT processing a specified 3584-lenght memory (that's 7/8s) AND resetting (JAM-ing) the ramp upon detection of having reached said 7/8 lenght ?

Since we can't seem to be able to get rid of an internal ramp cycle's first 1/8, wouldn't this strategy work towards at least chopping-off that last 1/8 of dare-I-say "useless" crossfade coefficient (where Pointer1 crossfade lingers at 0/Pointer2 crossfade stalls at 1), thus making the latency 1/8 shorter, hopefully without (from what I can gather) any "disruption" artifacts ?

(it would lend the "warble" a different quality, for better or for worst, loose a little low freq. shifting... and what about the ramp never reaching "1" ie resetting at 0.875 ? That's just a mem. address "vector", right ?)

-or should I just -"for the love of god !" stop torturing those sweet, little innocent ones and zeros :twisted: & finally go to bed ?...

Dedjazzgadgetz
(obsessive/compulsive... yup, that's me allright !)

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Tue Dec 17, 2013 11:35 pm

I think Pointer2 would suffer some disruption... jumping instantly from 0.375 (upon JAM-ing) to 0.5

(unless... we give it a cho rda,x|x|x,-512 offset upon JAM, up until -say mid-mem. is reached... or the other way around : a +512 offset from mid-point 'til JAM ?)

DARN ! :shock:

Oh, well...
I tried.

Dedjazzgadgetz
(if anybody has a go: tell me how it sounds... still not set-up properly for programming :oops: )

frank
Posts: 991
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank » Wed Dec 18, 2013 12:21 pm

You're not going to gain anything doing this. Look at it logically, writing into the buffer deeper only changes the write point, it is a circular buffer and the pointers are moving through it so the length is the same. Trying to write deeper then JAM the ramp early is effectively using a shorter buffer, why not just use a shorter buffer like 2048 to start with? You are not gaining anything over the shorter buffer by using the longer buffer and doing the deep write/JAM.
Frank Thomson
Experimental Noize

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Wed Dec 18, 2013 1:01 pm

I know, I know ! :oops:

(But it was fun -in a perverse-kinda way- trying to "reverse-engineer" donstavely's idea -if it worked at all... even if a *wee bit* frustrating. AND it got me to think waaay "deeper" into the architecture/the logic behind the FV-1; and that's not wasted !)

As usual Frank, thanks for sharing some great insights !
Much obliged...

Dedjazzgadgetz
(your friendly, neighbourhood *nutcase*. -"Let go, man... let go". :shock: -I'm trying. )

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Wed Dec 18, 2013 1:21 pm

oh, say :

what's the "properly pitched" lower-bandwidth down to (ballpark figure) when an internal RMP (@32kHz) is set to

-512 ?
-1024 ?
-2048 ?

and finally

-4096 ?

(I figure they'll be "octaves" of each other, just not real-sure of a real-life value... wild guess here : 64Hz, 32Hz, 16Hz & 8Hz ? :? )
Last edited by Dedjazzgadgetz on Wed Dec 18, 2013 3:45 pm, edited 1 time in total.

frank
Posts: 991
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank » Wed Dec 18, 2013 3:16 pm

Those frequencies are about right, you want at least one full wave in the buffer or else it doesn't sound right. You could make the argument for a 1/2 wave but it would be 6db down from what it should be (I think, just off the top of my head).

So for a normally tuned guitar you could use 512 since the open E is about 82Hz but for a bass it is about 41Hz so you need at least 1024 and a piano typically goes down to 27Hz so you need at least 2048.
Frank Thomson
Experimental Noize

Dedjazzgadgetz
Posts: 22
Joined: Thu Dec 08, 2011 8:23 pm
Location: Montréal, Canada

Post by Dedjazzgadgetz » Wed Dec 18, 2013 3:43 pm

O.K. great !

(my math/reasoning's much better than I thought... 8) )

Thanks,

Dedjazzgadgetz
(now, off to the programming-cave... make some more Experimental Noize :wink: )

donstavely
Posts: 52
Joined: Thu Jan 07, 2010 1:29 pm
Location: Windsor, Colorado

Post by donstavely » Fri Jun 27, 2014 1:57 pm

frank wrote: Now donstavely is correct in that writing into the buffer could shorten the delay but it can cause an audible discontinuity. Ramps are used and crossed between the pointers to try to hide the discontinuity as the pointer wraps around the buffer, by writing higher into the buffer you are allowing old/wrong data to be used until the pointer hits the write point.
Frank, I just suggested this trick (of writing into the pitch-transpose buffer 1/8th of the way in) in a more recent post, but never replied to your comment in this one.

I am very confident that this trick works. It is totally glitchless, and reduces the average latency by 1/4 for free. The reason is that even though the crossfade pointers sweep through the entire buffer, the crossfade value is zero until the pointer get 1/8th of the way in. So whatever crap is on that region of memory is multiplied by zero (and added to the good data that comes from the middle section of the buffer read using the other pointer.)

So writing to the head of the buffer just means that the signal "ages" by 512 clocks for a 4096 buffer before it is ever used - adding an unnecessary 15.6ms to the latency.

I have thought this through carefully, as well as testing it pretty thoroughly. Please 'spain it to me if you still think I am wrong.

Don
Don Stavely

MacroMachines
Posts: 71
Joined: Fri Dec 12, 2014 9:45 pm
Location: Detroit,MI
Contact:

Post by MacroMachines » Wed Jul 06, 2016 12:17 pm

Id be curious to hear an example if you have one you are willing to show. Why not try an open compare/contrast
http://MacroMachines.net
Digital Control for your Analog Soul.

Post Reply