|
- 7. Matlab code
-
- 7.1 Download
- 7.2 Installation
- 7.3 Execution
- 7.3.1 Launch Matlab
- 7.3.2 Change the current directory
- 7.3.3 Load a wave file into a vector
- 7.3.4 Shift the pitch
- 7.3.5 Listen to the result
- 7.4 Complete code
7. Matlab
7.1 Download
You can download the matlab code that implements the phase vocoder described in the previous sections.
7.2 Installation
In order to use this code, you need to unzip the following files in the folder of your choice:
- pitchShift.m
- createFrames.m
- fusionFrames.m
7.3 Execution
Here are the steps to shift the pitch of a wave file.
7.3.1 Launch Matlab
Well this one is kinda trivial ;)
7.3.2 Change the current directory
You need to set the current directory to the directory where you extracted the matlab files from the zip file above. You can do this with the following menu:
Figure 7.1: How to change the Matlab current directory
7.3.3 Load a wave file into a vector
The next step consists in loading the content of a wave file (*.wav) into Matlab. As far as I know, you cannot load directly from the mp3 format. If you want to use a mp3 file, you first need to convert it to the wave format and then load it with Matlab. To do so, you can type the following command in the Matlab command window.
| | | | |
| | | | |
| |
[x Fs] = wavread('C:\MySounds\yourwavefile.wav');
| | |
| | | | |
| | | | |
The audio signal is loaded in the vector named x and the sampling rate is loaded in the variable Fs (this can be useful if you ignore the sampling rate used for recording the sound initially). If you have a mono signal, x will be a matrix with a single column. However, if you have a stereo signal, x will be a matrix with two columns. You can either pitch shift each left and right channel individually or average them together and use the result as the input vector. You can use the following commands to reorganise your signals:
| | | | |
| | | | |
| |
leftChannel = x(:,1);
rightChannel = x(:,2);
averageBoth = (leftChannel + rightChannel) / 2;
| | |
| | | | |
| | | | |
7.3.4 Shift the pitch
You can then shift your signal by calling the pitchShift function. Here, you need to specify the vector which contains the signal to be shifted, the sampling rate, the frame size in samples and the hop size in samples.
We will assume that the samppling rate of the audio wave file was 48000 samples/sec, such that Fs = 48000. For this reason, as explained previously, we choose a frame size of 1024 samples for optimal results. Since we want an overlap of 75%, we set the hop size to 256. Finally, let's say we want to shift the pitch up by two steps. We want the resulting signal to be stored in a vector named y. We need to write the following command:
| | | | |
| | | | |
| |
y = pitchShift(x,1024,256,2);
| | |
| | | | |
| | | | |
7.3.5 Listen to the result
That's it! The signal is now pitch shifted. But it would be nice to listen to it. In order to do so, use the following command. By the way, always reduce the volume of your speaker when you perform some audio tests with Matlab. If for some reason the operation went wrong and the power of the resulting signal is two high, you could blast your ears (happened to me a few times... then I learned my lesson).
7.4 Complete code
Here is the content of the Matlab files, which you can download in section 7.1.
pitchShift.m
| | | | |
| | | | |
| |
function [outputVector] = pitchShift(inputVector, windowSize, hopSize, step)
winSize = windowSize;
hop = hopSize;
alpha = 2^(step/12);
hopOut = round(alpha*hop);
wn = hann(winSize*2+1);
wn = wn(2:2:end);
x = inputVector;
if size(x,1) < size(x,2)
    x = transpose(x);
end
x = [zeros(hop*3,1) ; x];
[y,numberFramesInput] = createFrames(x,hop,winSize);
numberFramesOutput = numberFramesInput;
outputy = zeros(numberFramesOutput,winSize);
phaseCumulative = 0;
previousPhase = 0;
for index=1:numberFramesInput
   
    currentFrame = y(index,:);
   
    currentFrameWindowed = currentFrame .* wn' / sqrt(((winSize/hop)/2));
   
    currentFrameWindowedFFT = fft(currentFrameWindowed);
   
    magFrame = abs(currentFrameWindowedFFT);
   
    phaseFrame = angle(currentFrameWindowedFFT);
   
    deltaPhi = phaseFrame - previousPhase;
    previousPhase = phaseFrame;
   
    deltaPhiPrime = deltaPhi - hop * 2*pi*(0:(winSize-1))/winSize;
   
    deltaPhiPrimeMod = mod(deltaPhiPrime+pi, 2*pi) - pi;
   
    trueFreq = 2*pi*(0:(winSize-1))/winSize + deltaPhiPrimeMod/hop;
   
    phaseCumulative = phaseCumulative + hopOut * trueFreq;
   
   
   
    outputMag = magFrame;
   
    outputFrame = real(ifft(outputMag .* exp(j*phaseCumulative)));
   
    outputy(index,:) = outputFrame .* wn' / sqrt(((winSize/hopOut)/2));
end
outputTimeStretched = fusionFrames(outputy,hopOut);
outputTime = interp1((0:(length(outputTimeStretched)-1)),outputTimeStretched,(0:alpha:(length(outputTimeStretched)-1)),'linear');
outputVector = outputTime;
return
| | |
| | | | |
| | | | |
createFrames.m
| | | | |
| | | | |
| |
function [vectorFrames,numberSlices] = createFrames(x,hop,windowSize)
numberSlices = floor((length(x)-windowSize)/hop);
x = x(1:(numberSlices*hop+windowSize));
vectorFrames = zeros(floor(length(x)/hop),windowSize);
for index = 1:numberSlices
    indexTimeStart = (index-1)*hop + 1;
    indexTimeEnd = (index-1)*hop + windowSize;
    vectorFrames(index,:) = x(indexTimeStart: indexTimeEnd);
end
return
| | |
| | | | |
| | | | |
fusionFrames.m
| | | | |
| | | | |
| |
function vectorTime = fusionFrames(framesMatrix, hop)
sizeMatrix = size(framesMatrix);
numberFrames = sizeMatrix(1);
sizeFrames = sizeMatrix(2);
vectorTime = zeros(numberFrames*hop-hop+sizeFrames,1);
timeIndex = 1;
for index=1:numberFrames
    vectorTime(timeIndex:timeIndex+sizeFrames-1) = vectorTime(timeIndex:timeIndex+sizeFrames-1) + framesMatrix(index,:)';
    timeIndex = timeIndex + hop;
end
return
| | |
| | | | |
| | | | |
| |
| |