Google

main
dspblog
cyclic_signals
FFT_interpolation
FFT_interpolation_how_does_it_work
FFT_smoothness_cyclic
discrete_time_reconstruction
discrete_time_reconstruction2
Nyquist_on_the_edge
FFT_delay_special_case
Fourier_reconstruction
pulse_and_Nyquist
FFT_complexError
matlabOctave
matlab_upsampling
matlab_downsampling
FFT_delay
FFT_filter_example
FFT_interpolation_example
FFT_bin_frequencies
fit_signal
FFT_peaksearch_audio_example
matlab_binary_readwrite
Octavesvg
C
FFTW_example
looprecord
SNR
SNR3
SNR_example_96kAudio
SNR_FFT_correlation_example
lua
luagpib
luasplit
luadump
mnoofltk
wxLuaDll
wxLua_loadAsDll
wxLua_HelloWorld
wxLua_simpleButton
wxLua_resourceManagement
wxLua_XMLparser
DSP
IQ_LO
IQ_LO_2
optimum_receiver
DSP_basics
sampleRateChange_terms
dirac_pulse
freqresp_s
zfilter_example
freqresp_z
freqresp_z_sign
misc
zero_forcing_equalizer_example
nonminphase_inverse
periodic_spectrum
lagrange_multipliers
Entropy
RC_chopper
TRex450_setup
EP100
EP100SE
EP100Gremlins
essential_spares
tail_rotor
motoradjustment
blade_balancing
blade_repair
GAUI_SAE12A
Walkera43


valid html (click to verify)



prevupnextdisable ads

FFT interpolation example

Summary

A Matlab / Octave example that uses FFT interpolation to stretch the length of a stereo audio signal

Introduction

The example program loads an audio file. It uses FFT interpolation to increase the number of samples by a factor of 2^{\frac{1}{12}}. This results in a downwards pitch shift by one semitone.

Example application

Download
Please note, that a complex-valued FFT is used for real-valued signals (hint: One could use the imaginary part to process two independent channels at the same time).
Below the source code:

FFT_interpolation_example.m

close all; clear all;
% Load audio file
[y, fs, bits]=wavread('in.wav');
% nChan is 2 for a stereo file: Independent left / right channel
[n, nChan]=size(y);

yOut=[];
for index=1:nChan
  % extract the channel as row vector
  yc=transpose(y(:, index));
    
  % Interpolate: Lower pitch by one semitone
  yc=mn_FFT_interpolation(yc, 'factor', power(2, 1/12));
  
  % overwrite original data
  % real() is needed to remove imaginary part caused by finite numerical precision
  yOut(:, index)=transpose(real(yc));
end

% In extreme cases, ringing might raise peaks. 
% Therefore, normalize to 1
peak=max(max(abs(yOut)));
yOut=yOut*1/peak;

% write output file
wavwrite('out.wav', yOut, fs, bits);

mn_FFT_interpolation.m

function data=mn_FFT_interpolation(data, varargin)

% ****************************************************************
% param check I
% ****************************************************************
if mod(length(varargin), 2) > 0
  error('wrong number of arguments (need option, value pairs)');
end
[nRow, nCol]=size(data);
if nRow ~= 1 
  error('data must be row vector');
end

% ****************************************************************
% default values
% ****************************************************************
nPad=-1; % invalid

% ****************************************************************
% parameter handling
% ****************************************************************
for argindex=1:2:length(varargin)
  arg=varargin{argindex};
  param=varargin{argindex+1};
  switch(arg)
   case 'factor'
    nPad=floor((param-1)*nCol+0.5);
   case 'nSamplesAdded'
    nPad=nCol+param;
   case 'nSamplesTotal'
    nPad=param-nCol;
   otherwise
    error(['invalid parameter at position ', mat2str(argindex)]);
  end % switch
end % for argindex

% ****************************************************************
% param check II
% ****************************************************************
if nPad < 0
  error('invalid / incomplete parameters');
end

if nPad == 0
  return % nothing to do
end
  
realValued=isreal(data);

% ****************************************************************
% to frequency domain
% ****************************************************************
data=fft(data);

% ****************************************************************
% Zero-pad frequency domain data
% ****************************************************************
if mod(nCol, 2)==1
  % ****************************************************************
  % odd length
  % ****************************************************************
  lside=data(1:(nCol+1)/2); 
  rside=data((nCol+1)/2+1:nCol);
  data=[...
      lside, ... % positive frequencies
      zeros(1, nPad), ... % zero padding
      rside ... % negative frequencies
       ];
else
  % ****************************************************************
  % even length
  % The center bin needs to be split in two 
  % since it contains sum of exp(-i pi k) and exp(i pi k) terms
  % ****************************************************************  
  lside=data(1:nCol/2); 
  center=data(nCol/2+1);
  rside=data(nCol/2+2:nCol);
  data=[...
      lside, ... % positive frequencies
      center/2, ... % previous Nyquist frequency (positive half),
      zeros(1, nPad-1), ... % zero padding
      center/2, ... % previous Nyquist frequency (negative half),
      rside ... %negative frequencies
      ];
end

% ****************************************************************
% to time domain
% scale, so that average amplitude remains as it was
% ****************************************************************
f=(nPad+nCol)/nCol;
data=ifft(f*data);

% ****************************************************************
% Chop off imaginary part, if the input data was real-valued
% ****************************************************************
if realValued > 0
  data=real(data);
end


prevupnextdisable ads

© Markus Nentwig 2007-2008
The content of this page is provided without any warranty and may not be reproduced without permission.

Comments? Questions?

Please send me a mail! mnentwig@elisanet.fi