Incrementally / gradually change pitch of signal over time using octave / matlab code
Asked Answered
B

1

7

I can pitch shift an entire signal using resample and I have tried the phase vocoder code here.

I've also tried repmat and interpolation and I looked into fft and interp1

How can I incrementally / gradually change the pitch of a signal over time? I've included an example of the Original Signal and what I'm trying to get the Processed Signal to sound like (I created the processed signal using Audacity and using their effect Sliding time scale / pitch shift) But would like to create this signal in Octave 4.0. If you listen to the Processed Signal you can hear the pitch of the file gradually increasing but the file is the same length in (seconds) as the Original Signal file.

I'm using Octave 4.0 which is like Matlab

Here's The code which can change the pitch of the entire signal and keep the same length of the original signal in seconds, but I'm not sure how to have it gradually change the pitch of a signal over time. Thanks goes to rayryeng for getting me this far.

clear, clc
[ya, fs, nbitsraw] = wavread('/tmp/original_signal.wav');

num_per_sec=2.4; %// Define total number of times we see the signal

%// Get total number of integer times we see the signal
num_whole = floor(num_per_sec);

%// Replicate signal
yb=repmat(ya,num_whole,1);

%// Determine how many samples the partial signal consists of
portion = floor((num_per_sec - num_whole)*length(ya));

%// Sample from the original signal and stack this on top of replicated signal
yb = [yb; ya(1:portion)];

%interpolation
xxo=linspace(0,1,length(yb))'; 
xxi=linspace(0,1,length(ya))'; 
yi_t=interp1(xxo,yb,xxi,'linear');

wavwrite([yi_t'] ,fs,16,strcat('/tmp/processed_signal.wav'));  % export file
Bambino answered 22/6, 2017 at 11:45 Comment(2)
Since you seem to be interested in doing this for speech signals then you might want to look at analysis/resynthesis tools such as PSOLA. Tools such as this should give a much more natural pitch change. (Note that PSOLA is pretty long in the tooth - there may be better alternatives these days.)Oil
audacity usessbsms library for Subband Sinusoidal Modeling.If you want you can rewrite all in MATLAB/Octave or you can compile it and use it as a mex/octNihility
M
6

My answer doesn't give exactly the same result as the one you posted, but I think it's interesting and simple enough to give you the important concepts behind pitch stretching. I haven't found the method I'm proposing elsewhere on the web, but I can't imagine no one has thought of this before, so it might have a name.

The first thing to realise is that if you want to apply transformations to the pitch over time, and not just offset it over the entire timecourse, you need to work with pitch "features" that are defined at each time-point (eg time-frequency transforms), as opposed to ones that summarise the entire signal contents (eg Fourier).

It's important to realise this, because it becomes evident that we need to involve things like the instantaneous frequency of your signal, which is defined as the derivative of the Hilbert phase (typically taken as (1/2Pi) * dPhi/ dt to work in Hz instead of rad/s).

Assuming that we can transform the instantaneous frequency of a signal, we can then translate the idea of "increasing the pitch incrementally" formally into "adding a linearly increasing offset to the instantaneous frequency". And the good news is, that we can transform the instantaneous frequency of a signal quite easily using an analytic transform. Here is how:

function y = add_linear_pitch( x, fs, df )
%
% y = add_linear_pitch( x, fs, df )
%
% x, fs: audio signal (1-dimensional)
% df: the amplitude of frequency offset, in Hz
%
% See also: hilbert
%

    x = x(:);
    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) + df*pi*k.^2/fs/n; % phase + linearly increasing offset
    y = m - imag(hilbert( e .* sin(p) )); % inverse-transform

end

The only non-obvious thing in the previous code is that we need to integrate the "linearly increasing pitch offset" (or whatever transformation of the instantaneous frequency) before applying it to the phase, and multiply it by 2Pi (to work in radians). In our case, the integral of a linear function is simply a quadratic function, but you can play with more complicated things :)

Millwright answered 24/6, 2017 at 18:33 Comment(4)
This is really elegant is there any way to calculate the correct slope if I wanted to end at a certain frequency? An example would be if the original vocal signal had a maximum resonance frequency 326.8hz and I would like it to end at 402.3hz?Bambino
I think it's possible, it should just depend on the difference of frequency (delta-y), and length of the signal (delta-x). I am busy atm but I will think about it more and edit my post within a few days.Millwright
I posted this question in the math section is this formula useful? math.stackexchange.com/posts/comments/4816923?noredirect=1Bambino
@RickT Sorry for the delay. It is actually exactly what I mentioned in my previous comment; to shift the frequency of a signal of length N by F Hz, simply take fac = F/N.Millwright

© 2022 - 2024 — McMap. All rights reserved.