Reducing the tremolo artefact from pitch shifting

Algorithm development and general DSP issues

Moderator: frank

Post Reply
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

Will the following idea work?

Send signal to be shifted down two parallel paths.
Each path has a delay line (of length D) for pitch-shifting, but the ramp LFOs on those lines are offset in time by a suitable fraction of the line length (I am guessing D/4).
The idea being that peaks of the tremolo (or pitch warble) artefacts in one path coincide with troughs of the artefacts in the other line.

I am guessing its possible to use the JAM instruction to zero RMP1 when RMP0 reaches some particular level, and then set a flag indicating not to do that zero-ing again.

Has this been tried before?

If it's feasible then what condition should be checked in order to get D/4 offset. Can I assume that an increasing ramp will always go from 0 to 1, and a decreasing ramp will always got from 1 to 0. i.e. just check if RMP level is 0.25 (or 0.75) to trigger the JAM ?
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

It works !!! (EDIT: Well no it doesn't. See below).
I did an octave-up test and got big improvement, especially in the higher pitches,
when compared to case when the two lines have ramps with the same phase.

My ramp adjustment code assumes the ramps are decreasing (i.e. upward pitch shift),
so would need adjusting to handle the case when the ramps are increasing (i.e. down pitch shift).
Would be interested if it can be done with fewer instructions.

Code: Select all

MEM	tmp		1	; Temp memory for octave-up routines
MEM	octave1		4096	; Delay line for octave-up
MEM	octave2		4096	; Delay line for octave-up

EQU 	adjust_ramps	REG0	; Stop adjusting RMPs when this flag goes negative
EQU	lp_antialias	REG1	; Anti-alias LPF before octave up
EQU	octaveOut1	REG2
EQU	octaveOut2	REG3

;-------------- Initialize LFOs etc -------------------
SKP	RUN,end_init
WLDR	RMP0,16384,4096	; Ramp LFO for octave1
WLDR	RMP1,16384,4096	; Ramp LFO for octave2
JAM	RMP0			; Not sure resetting RMP0 is required
JAM	RMP1			; Not sure resetting RMP1 is required
CLR
WRAX	adjust_ramps,0		; Initialise the "adjust_ramps" flag
end_init:
;-------------------------------------------------

;--------------- Ramp adjustment ------------------
; After the first tick, both ramps should go high and
; then start to decrease towards 0.
; We'll keep resetting RMP1 so long as RMP0 is above 0.25

RDAX	adjust_ramps,1	; Read the "adjust_ramps" flag ...
SKP	neg,done		; ... if it's negative, then we're done adjusting the RMPs
RDAX	RMP0,1		; Read RMP0...
SKP	zro,done		; ... and if its zero then we must be at start up, so do nothing
SOF	0,-0.25		; else
SKP	gez,reset_rmp1	; ... if RMP0 >= 0.25, then reset RMP1
WRAX	adjust_ramps,1	; else set the "adjust_ramps" flag to negative
SKP	neg,done
reset_rmp1:
JAM	RMP1
CLR
done:
;-------------------------------------------------

;---------- Take average of L and R inputs -----------
RDAX	ADCL,0.5
RDAX	ADCR,0.5
;-------------------------------------------------

;--------- Anti-alias LPF before the octave up ---------
; We don't want doubling pitch to give a tone above 16kHz
RDFX	lp_antialias, 0.792; 	; 8192Hz ==> 1 - exp(-2*pi*8192/32768)
WRAX	lp_antialias, 1
WRA	octave1,1		; Write to octave1
WRA	octave2,0		; Write to octave2
;-------------------------------------------------

;------------- Octave up 1 ------------------------
CHO	RDA,RMP0,REG|COMPC,octave1
CHO	RDA,RMP0,,octave1+1
WRA	tmp,0
CHO	RDA,RMP0,RPTR2|COMPC,octave1
CHO	RDA,RMP0,RPTR2,octave1+1
CHO	SOF,RMP0,NA|COMPC,0
CHO	RDA,RMP0,NA,tmp
WRAX	octaveOut1,0
;-------------------------------------------------

;------------- Octave up 2 ------------------------
CHO	RDA,RMP1,REG|COMPC,octave2
CHO	RDA,RMP1,,octave2+1
WRA	tmp,0
CHO	RDA,RMP1,RPTR2|COMPC,octave2
CHO	RDA,RMP1,RPTR2,octave2+1
CHO	SOF,RMP1,NA|COMPC,0
CHO	RDA,RMP1,NA,tmp
WRAX	octaveOut2,0
;-------------------------------------------------

;--------------- Make output signal -----------------
RDAX	octaveOut1,0.5
RDAX	octaveOut2,0.5
WRAX	DACL,0
Last edited by DrAlx on Thu Mar 28, 2019 4:26 pm, edited 1 time in total.
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

The same trick doesn't seem to work for octave down though !!!
I found the octave down effect was weaker and lots of "unshifted" signal seemed to
get through to the output somehow, and this was often stronger than the octave down.

I don't know if this was a coding error and the ramps were not being offset correctly,
or if I am missing some fundamental point that would say this trick won't work for octave down.

Code included anyway for reference...

Code: Select all

MEM	tmp		1	; Temp memory for detune and octave-down routines
MEM	octave1		4096	; Delay line for octave-down
MEM	octave2		4096	; Delay line for octave-down

EQU 	adjust_ramps	REG0	; Stop adjusting RMPs when this flag goes >=0
EQU	octaveOut1	REG2
EQU	octaveOut2	REG3

;-------------- Initialize LFOs etc -------------------
SKP	RUN,end_init
WLDR	RMP0,-8192,4096		; Ramp LFO for octave1
WLDR	RMP1,-8192,4096		; Ramp LFO for octave2
JAM	RMP0			; Not sure resetting RMP0 is required
JAM	RMP1			; Not sure resetting RMP1 is required
SOF	0,-0.5
WRAX	adjust_ramps,0		; Initialise "adjust_ramps" flag to < 0
end_init:
;-------------------------------------------------

;--------------- Ramp adjustment ------------------
; We'll keep resetting RMP1 so long as RMP0 is below 0.25

RDAX	adjust_ramps,1	; Read the "adjust_ramps" flag ...
SKP	gez,done		; ... if >= 0, then we're done adjusting the RMPs
RDAX	RMP0,1		; Read RMP0...
SOF	0,-0.25		;
SKP	neg,reset_rmp1	; ... if RMP0 < 0.25, then reset RMP1
WRAX	adjust_ramps,1	; else set the "adjust_ramps" flag to >= 0
SKP	gez,done
reset_rmp1:
JAM	RMP1
CLR
done:
;-------------------------------------------------

;---------- Take average of L and R inputs -----------
RDAX	ADCL,0.5
RDAX	ADCR,0.5

WRA	octave1,1		; Write to octave1
WRA	octave2,0		; Write to octave2
;-------------------------------------------------

;------------- Octave down 1 ------------------------
CHO	RDA,RMP0,REG|COMPC,octave1
CHO	RDA,RMP0,,octave1+1
WRA	tmp,0
CHO	RDA,RMP0,RPTR2|COMPC,octave1
CHO	RDA,RMP0,RPTR2,octave1+1
CHO	SOF,RMP0,NA|COMPC,0
CHO	RDA,RMP0,NA,tmp
WRAX	octaveOut1,0
;-------------------------------------------------

;------------- Octave down 2 ------------------------
CHO	RDA,RMP1,REG|COMPC,octave2
CHO	RDA,RMP1,,octave2+1
WRA	tmp,0
CHO	RDA,RMP1,RPTR2|COMPC,octave2
CHO	RDA,RMP1,RPTR2,octave2+1
CHO	SOF,RMP1,NA|COMPC,0
CHO	RDA,RMP1,NA,tmp
WRAX	octaveOut2,0
;-------------------------------------------------

;--------------- Make output signal -----------------
RDAX	octaveOut1,0.5
RDAX	octaveOut2,0.5
WRAX	DACL,0
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

Actually just tested the octave up again (on my electric guitar instead of my acoustic) and the tremolo is still there, just double the rate.
Not sure why it seemed less noticeable originally.
I think staggering the ramps as I am doing means I'm effectively reading the signal twice along the delay line but not cross fading in any way.
Oh well. Was worth a shot.
Zerikin
Posts: 2
Joined: Mon Apr 16, 2018 10:00 am

Re: Reducing the tremolo artefact from pitch shifting

Post by Zerikin »

You can improve it by diffusion. Something like this diffuser from Dattorro.
;------ Diffuser
LDAX REG1
RDA 4255,-0.75
WRAP 4099,0.75
RDA 4373,-0.75
WRAP 4256,0.75
RDA 4791,-0.625
WRAP 4374,0.625
RDA 5097,-0.625
WRAP 4792,0.625
WRAX REG2,0.0000000000
igorp
Posts: 65
Joined: Tue May 19, 2015 6:10 am
Location: RU

Re: Reducing the tremolo artefact from pitch shifting

Post by igorp »

You may use compressor/normalizer to make audio more flat and write your own transposition snippet with custom fadein-fadeout on buffer boundaries. I tried once, 256 samples for both was enough.

FV-1 uses fixed x-fade coefficients, but, AL3201 (afair) had about 8 types with different angles.
If your x-fade would be short and sin based, i think, sound will be more pleasant.

After transposition, it's good way to use resonant filter, it smoothing tremolo too
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

I tried the diffusion but it didn't really help.
I am not sure how much benefit comes from using sine weighting instead of linear increasing/decreasing weights.
The mix ratios for the two read pointers will still cycle between (1 : 0), (0.5 : 0.5), (0, 1).
I am assuming those 3 mix ratios corresponded to the maximum and minimum points of the tremolo sound.
I'll see if I can get info on what the AL3201 does. Thanks.
igorp
Posts: 65
Joined: Tue May 19, 2015 6:10 am
Location: RU

Re: Reducing the tremolo artefact from pitch shifting

Post by igorp »

audio is logarithmic, so it need to square x-fade coefficients to make volume more natural.

wrap, as far as i understand, gets obertones or harmonics , but you need whole tone.

And only one way - make transpose function yourself, with x-fades, filters, etc
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Reducing the tremolo artefact from pitch shifting

Post by DrAlx »

Regarding square x-fade. Are you suggesting to make the two weighting functions intersect each other at a level not equal to 0.5 ?

I can understand that instead of averaging voltage levels (V) you may want to average power levels (V^2) instead.
That makes sense to me if the 2 signals are not correlated, but I don't see how it helps when the signals are highly corellated (e.g. when playing a single tone).

I'll give it a try anyway.

EDIT: Thinking about it more, for the case when the signal is a single tone, I don't see how any choice of weight function can remove the tremolo so long as the distance between the read pointers is fixed.
There will always be some point where the two weighting functions have equal value, and at that point we are adding two sine waves that have a phase difference between them. This is a flanger type effect (i.e. comb filter). For some input signal tones, the equal mixing will result in total cancellation of the two signals.
So as the mix ratio varies in time, we hear a sound with no comb filtering (i.e. signal comes mainly from one read pointer) changing to a sound with comb filtering (where there are equal contributions from both read pointers). The only way I can see of trying to remove that effect is by dynamically varying the separation between the read pointers according to the signal waveform, and I don't think the FV-1 is powerful enough to do that.
igorp
Posts: 65
Joined: Tue May 19, 2015 6:10 am
Location: RU

Re: Reducing the tremolo artefact from pitch shifting

Post by igorp »

you may simply smooth signal by resonant filter and reverb after octaver and compress signal before octaver.
with custom octaver with 256 words cross-fade window, I think, it can give significant result.
Post Reply