# Calculating correct slope for pitch shifting given starting resonance frequency and ending frequency

How can I calculate the correct slope for variable fac (which controls how much a signal is gradually pitch shifted), if I wanted to end at a certain frequency? An example would be if the original vocal signal had a starting maximum resonance frequency of 326.8hz and I would like it to gradually increase to 402.3hz how would I go about calculating variable fac? It was suggested it may depend on the difference of frequency (delta-y), and length of the signal (delta-x). But I'm not sure what formula changes I would need to make to get this to work. Thanks goes to Sheljohn for the code and the suggestions. The original question can be found at Incrementally / gradually change pitch of signal over time.

The code block I'm having issues with is below:

%%%-------Begin Snippet of Code that I'm having problem with calculating correct slope
fac=.02; % slope factor for the pitch offset (trying to calculate this so signal will end at given frequency)

x = x(:); %signal
n = numel(x); % number of timepoints
m = mean(x); % average of the signal
k = transpose(0:n-1);

h = hilbert( x - m ); % analytic signal
e = abs(h); % envelope
p = angle(h) + fac*pi*k.^2/(fs); % phase + linearly increasing offset
y = m - imag(hilbert( e .* sin(p) )); % inverse-transform
%%%------End Code that I'm having problem with calculating slope


I've also included some working test code below:
Please note that the signals that will be used are not single frequencies so a simple sweep or chirp command will not work since I will be importing vocal audio files. Original Question: Incrementally / gradually change pitch of signal over time. The code example is to show if I change the variable len_of_sig to anything other than 1 the starting frequency is no longer correct. see plots

clear, clc,clf

pkg load signal %used to get hilbert to work

%---Begin Create signal / re-import signal
fs=8000
len_of_sig=1; %length of signal in seconds
t=linspace(0,2*pi,fs*len_of_sig);
orig_sig1=.8*sin(100*t);
wavwrite([orig_sig1(:)] ,fs,16,strcat('/tmp/0_sig.wav'));  % export file

orig_total_samples=length(x); %make this the same length as signal wave
t_import=linspace(0,2*pi*(orig_total_samples/fs),orig_total_samples);
%---End Create signal / re-import signal

%%%-------Begin Code that I'm having problem with calculating slope
fac=.02; %a slope factor for the pitch offset, typically 0.02

x = x(:); %signal
n = numel(x); % number of timepoints
m = mean(x); % average of the signal
k = transpose(0:n-1);

h = hilbert( x - m ); % analytic signal
e = abs(h); % envelope
p = angle(h) + fac*pi*k.^2/(fs); % phase + linearly increasing offset
y = m - imag(hilbert( e .* sin(p) )); % inverse-transform
%%%------End Code that I'm having problem with calculating slope

%%%---Begin Code used to Plot frequency vs time in seconds
z = hilbert(y);
instfreq = fs/(2*pi)*diff(unwrap(angle(z))); %orginal
t_new=t_import/(2*pi); %converts it to seconds

xlabel('Time')
ylabel('Hz')
grid on
title('Instantaneous Frequency')

plot(t_new(2:end),instfreq);
instfreq(1)
instfreq(end)
%%%---End Code used to Plot frequency vs time in seconds


Correct starting frequency when signal is 100hz and variable len_of_sig=1

Incorrect starting frequency when signal is 100hz and variable len_of_sig=2

So the questions I have are:

1) How can I calculate the correct slope for gradually pitch shifting a signal using variable fac, if I wanted the vocal signal to end at a certain frequency? Original Question: Incrementally / gradually change pitch of signal over time.

2) How can I change the variable len_of_sig to anything other than 1 (second) and not have it effect the starting frequency? (I believe if the slope calculation is corrected this may also be corrected)

Some suggestions Sheljohn gave were that calculating the correct slope may depend on the difference of frequency (delta-y), and length of the signal (delta-x).

PS: I'm using Octave 4.0 which is similar to Matlab

• In musical signal processing, the varying-sine model is $$x(t) = a(t) e^{i \phi(t)}, \qquad p(t) = 12\log_2 f(t) = \log_2(\frac{\phi'(t)}{2\pi})$$ The discrete analog is $$x(n) = a(n) e^{i \phi(n)}, \qquad p(n) = 12\log_2 f(n) = \log_2(\frac{\phi(n+1)-\phi(n)}{2\pi F_s})$$ Where $a$ is the (complex and band-limited) amplitude and $p$ is the pitch in semi-tones (with bounded variations). – reuns Jun 28 '17 at 16:13

I have no problem with it, I think you might have missed something in some of your conversions. As I mentioned in my comment on SO, setting the slope factor simply depends on the number of points in your signal, and the difference of frequency.

For example, you can shift the oscillatory frequency of a signal with $n$ timepoints by $\Delta f$ Hz by setting $\mathrm{fac} = \Delta f\ /\ n$. So for a signal of length 1 sec, sampled at 8000 Hz (ie 8001 points), shifting the frequency by 100 Hz can be done by setting $\mathrm{fac} = 100 / 8001 = 0.0125$. Try it out :)

function fac = foo(len,f_start,f_end)
%
% fac = foo(len,f_start,f_end)
%
% example:
%   len=1, f_start=100, f_end=200
%

%---Begin Create signal / re-import signal
fs = 8000;
t = 0:(1/fs):len;
x = sin(2*pi* f_start *t);
%---End Create signal / re-import signal

%%%-------Begin Code that I'm having problem with calculating slope
x = x(:); %signal
n = numel(x) % number of timepoints
m = mean(x); % average of the signal
k = transpose(0:n-1);

fac = (f_end-f_start) / n

h = hilbert( x - m ); % analytic signal
e = abs(h); % envelope
p = angle(h) + fac*pi*k.^2/(fs); % phase + linearly increasing offset
y = m - imag(hilbert( e .* sin(p) )); % inverse-transform
%%%------End Code that I'm having problem with calculating slope

%%%---Begin Code used to Plot frequency vs time in seconds
z = hilbert(y);