Delay memory interpolation (again)

Algorithm development and general DSP issues

Moderator: frank

Post Reply
knutolai
Posts: 86
Joined: Wed Nov 23, 2016 9:43 am
Location: Bergen, Norway

Delay memory interpolation (again)

Post by knutolai »

I'm back at it attempting to increase the audio fidelity for non-ramp based delay interpolation (ADDR_PTR / RMPA). So far all my attempts seem to be in vain and I'm stuck wondering what exactly makes the SIN/RAMP LFO generated data sound so good and left wondering if there's more going on under the hood than is apparent from the documentation.

On the face of it the only major difference is the amount of interpolation positions available (interpolation resolution). If attempting to create a vibrato effect through the ADDR_PTR/RMPA approach this would obviously become a problem as the low interpolation resolution distorts the modulation waveform. However for pitch shifting effects where the incrementation is constant I can't see how a lower interpolation resolution would have any other effects than to limit the amount of pitch shift settings available. (E.g. a linear counter increment of -256 creates an octave up pitch shift while an increment of 0 creates no pitch shift. Between the two settings there is a resolution of 255 other pitch shifts available.).

Some questions:

1. Is there a difference in the output data's bit resolution when reading with the RMPA vs CHO RDA instructions?
2. Is the ramp interpolation (fractional address data) linear or does it follow some other curve that decreases artifacts?
3. Is there some kind of reconstruction filtering happening behind the scenes with the CHO RDA instruction?

For anyone unclear on how non-ramp based pitch shifting is performed here is a quick sketch:

Code: Select all

equ	scaler	reg0	; increment scaler POT
equ	counter	reg1	; pitch shift counter 

; increment scaler #################

or	$7fffff		; 1
rdax	POT0, -2		; range [1 to -1]
skp	NEG, 1		; if GEZ : 
sof	0.5, 0.		; x 0.5
wrax	scaler, 0		; range [0.5 to 0 to -1]

; positive counter with bipolar incrementation ##########

or	256		; base increment
mulx	scaler		; x [0.5 to 0 to -1]
or	$800000		; shift increment to negative range
rdax	counter, 1	; add counter
and	$7fffff		; shift sum to positive range
wrax	counter, 0	; store counter, clr

; Addressing to fetch output data ##########

ldax	counter		; fetch address data
wrax	ADDR_PTR, 0	; 
rmpa	1		; 
wrax	DACL, 0		; 

; buffer looping ######################	

rda	32767, 1	; buffer looping
mulx	POT1		; 
rdax	ADCL, 1		; 
wra	0, 0		; 

; end
Note that it's also possible to do manual interpolation. This costs much more program space and increases the interpolation resolution to 10bits (pot resolution). However from my tests this does not seem to have any positive impact on audio fidelity.
frank
Posts: 1281
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Delay memory interpolation (again)

Post by frank »

knutolai wrote: Mon May 26, 2025 3:50 am Some questions:

1. Is there a difference in the output data's bit resolution when reading with the RMPA vs CHO RDA instructions?
2. Is the ramp interpolation (fractional address data) linear or does it follow some other curve that decreases artifacts?
3. Is there some kind of reconstruction filtering happening behind the scenes with the CHO RDA instruction?
1. No difference, since both are reading from the same memory they get the same value
2. Linear
3. No behind the scenes operations.

I have not looked deeply into your code so I may be missing your intention but the line:

Code: Select all

or	$800000		; shift increment to negative range
confuses me as just setting the MSB does not negate a value, you need to 2's comp it. For example if the value was 0x0000 setting the MSB makes it 0x8000 which is not "negative zero" but a maximum negative number. While tricks like setting/clearing the MSB can "shift" an unsigned number 180 degrees the math in the FV-1 is basically signed and saturated so it may not be creating the value your expect.
Frank Thomson
Experimental Noize
knutolai
Posts: 86
Joined: Wed Nov 23, 2016 9:43 am
Location: Bergen, Norway

Re: Delay memory interpolation (again)

Post by knutolai »

The instruction is there to allow bipolar incrementation ("if GEZ : ACC = ACC-1) basically performing a rollover. I'm aware the fv1 uses 2s compliment for negative numbers but I don't see how that conflicts with this implementation.

That being said the general method suffers from the same artifacts regardless of which counter rollover technique I use. If there indeed isn't anything special with the CHO RDA approach how would you code a pitch shifter for the ADDR_PTR/RMPA approach that doesn't suffer from artifacts? Do you agree with my argument regarding the pitch shifters?
frank
Posts: 1281
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Delay memory interpolation (again)

Post by frank »

OK, I get the ramp now as it is limited range so I can see how it works.

Honestly, I wouldn't bother programming an ADDR_PTR/RMPA approach, if I needed more pitch shifters or ramps I would move to FXCore where it is easier to program such things. I am assuming a program that needed the additional ramps also required additional controls which FXCore also provides.

There is nothing special in FV-1 SIN/ramp interpolation section, it is straight linear interpolation between samples then cross fade between pointers for a pitch shift. AN-0001 shows exactly what is going on with them, There is no resolution difference as the same multiplier/adder/ALU is used in the chip for interpolation as with all other instructions. The address generation has a separate adder so it can calculate an address in parallel to the instruction and same for the SIN and ramp generators but that is just for wave generation. Have you sent the ramps and cross fade wave out the DACs to see if they are correct? I recall years ago someone doing a similar thing and it turned out they had the phase of the cross fade inverted for each ramp.
Frank Thomson
Experimental Noize
knutolai
Posts: 86
Joined: Wed Nov 23, 2016 9:43 am
Location: Bergen, Norway

Re: Delay memory interpolation (again)

Post by knutolai »

It's not that I need more ramps it's that I find the RMP0/1 cumbersome to work with especially due to the specific buffer size options.

If I could get the ADDR_PTR/RMPA approach working it's a much more flexible solution in my opinion. I very much think it is worthwhile as I have hundreds of FV1 chips on hand that I want to put to use.

The program i provided cycles through the whole buffer and does not have any envelope for the pitch shifting. Obviously there will be a 'click when the ramp resets but other than that it should "behave". If you listen to the program you will hear this 'click' but you will also hear continuous artifacts as part of the audio stream.

I'd really appreciate getting to the bottom of what's going wrong here.
frank
Posts: 1281
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Delay memory interpolation (again)

Post by frank »

I have not had the chance to test the code, will try to but looking at it there is no interpolation. Without interpolation it will sound bad, for down shifting it will repeat samples. On up it will skip samples. It will only sound right at +/- full octaves without interpolation.

Post the entire program with ramps/interpolation/cross fading.
Frank Thomson
Experimental Noize
knutolai
Posts: 86
Joined: Wed Nov 23, 2016 9:43 am
Location: Bergen, Norway

Re: Delay memory interpolation (again)

Post by knutolai »

For some reason I've had the impression that an 8bit-resolution interpolator was baked into the ADDR_PTR / RMPA function. Seeing as there are 32768 buffer positions but the value inputted to the ADDR_PTR register has 32768*256 available values. I could have swore I read this but now re-reading through the documentation I can't find anything. Ops!

So there's no interpolation inherent to this approach? Is the resolution of the ADDR_PTR register 15bit?
frank
Posts: 1281
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Delay memory interpolation (again)

Post by frank »

Correct, there is no interpolation built into the ADDR_PTR/RMPA. FXCore has a built in INTERP instruction for reading from the delay line but not FV-1.

Yes, 15-bit addressing/resolution. If memory serves the 15 bits after the MSB are used as the MSB might be being used as a sign bit by the user when calculating the address.
Frank Thomson
Experimental Noize
knutolai
Posts: 86
Joined: Wed Nov 23, 2016 9:43 am
Location: Bergen, Norway

Re: Delay memory interpolation (again)

Post by knutolai »

Oh my. Thank you for this! Finally got this working. Here's a working code for anyone interested. You could probably filter the increment scaler pot for a smoother travel.

Code: Select all

equ	scaler	reg0	; increment scaler POT
equ	counter	reg1	; pitch shift counter 
equ	addr1	reg2	; interpolation address 1
equ	addr2	reg3	; ... 2
equ	data1	reg4	; interpolation data 1
equ	data2	reg5	; ... 2
equ	base	reg6	; 256 (same as increment resolution)
equ	inter	reg7	; interpolation crossfade scaler

; Base increment ##################

or	256		; store 256 (base increment) to reg
wrax	base, 0		; store, clr

; positive counter with positive incrementation ##########

or	512		; base increment
mulx	POT0		; x [0 to 1]
or	$800000		; shift increment to negative range
rdax	counter, 1	; add counter
and	$7fffff		; shift sum to positive range
wrax	counter, 0	; store counter, clr

; Set addresses ##########

ldax	counter		; set addresses to interpolate between
and	$7FFF00		; clear 8 LSBs
wrax	addr1, 1		; set first address
rdax	base, 1		; + 256
wrax	addr2, 0		; set second address, clr

; Set interpolation gain ############

ldax	counter		; read counter val
and	$FF		; clear everything but the 8 LSBs

sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 4 bit shifts ...

sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 8 bit shifts ...

sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 12 bit shifts...

sof	-2, 0		; 
sof	-2, 0		; 
sof	-2, 0		; 
sof	-1, 0		; 15 bit shifts + re-inversion

wrax	inter, 0		; store, clr

; Fetch data to interpolate between ########

ldax	addr1		; read addr
wrax	ADDR_PTR, 0	; set addr
rmpa	1		; read data
wrax	data1, 0		; store, clr

ldax	addr2		; ...
wrax	ADDR_PTR, 0	; ...
rmpa	1		; ...
wrax	data2, 0		; ...

; Data interpolation and output ###########

ldax	data2		; data crossmixer
rdax	data1, -1	; 
mulx	inter		; interpolation crossfader
rdax	data1, 1		; 

wrax	DACL, 0		; output, clr

; buffer looping ######################	

rda	32767, 1	; buffer looping
mulx	POT1		; 
rdax	ADCL, 1		; 
wra	0, 0		; 

; end ---
Post Reply