function [spec,f,t,sideinfo] = stft(x,parameter,sideinfo)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Name: stft
% Date: 12-2013
% Programmer: Jonathan Driedger
% http://www.audiolabs-erlangen.de/resources/MIR/TSMtoolbox/
%
% Computes the short-time Fourier transform (stft) of the input audio
% signal.
%
% Input: x single-channel signal.
% parameter.
% anaHop either the constant hop size of the analysis
% window or a vector of analysis positions in the
% input signal.
% win the analysis window used for windowing the
% input signal.
% zeroPad number of zeros that should be padded to the
% window to increase the fft size and therefore
% the frequency resolution.
% fsAudio the sampling rate of the input audio signal x.
% numOfFrames can be set to fix the number of spectra that
% should be computed.
% fftShift can be set to 1 to apply a circular shift of
% samples to each frame by half its length prior
% to the application of the fft.
%
% Output: spec complex spectrogram
% f vector of the center frequencies of all Fourier
% bins given in Hertz.
% t vector specifying the time instances in seconds
% where the respective Fourier spectra were
% computed.
% sideinfo.
% stft.anaHop
% stft.win
% stft.zeroPad
% stft.featureRate
% stft.originalLength
% stft.fsAudio
% stft.fftShift
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Reference:
% If you use the 'TSM toolbox' please refer to:
% [DM14] Jonathan Driedger, Meinard Mueller
% TSM Toolbox: MATLAB Implementations of Time-Scale Modification
% Algorithms
% Proceedings of the 17th International Conference on Digital Audio
% Effects, Erlangen, Germany, 2014.
%
% License:
% This file is part of 'TSM toolbox'.
%
% MIT License
%
% Copyright (c) 2021 Jonathan Driedger, Meinard Mueller, International Audio
% Laboratories Erlangen, Germany.
%
% We thank the German Research Foundation (DFG) for various research grants
% that allow us for conducting fundamental research in music processing.
% The International Audio Laboratories Erlangen are a joint institution of
% the Friedrich-Alexander-Universitaet Erlangen-Nuernberg (FAU) and
% Fraunhofer Institute for Integrated Circuits IIS.
%
% Permission is hereby granted, free of charge, to any person obtaining a
% copy of this software and associated documentation files (the
% "Software"), to deal in the Software without restriction, including
% without limitation the rights to use, copy, modify, merge, publish,
% distribute, sublicense, and/or sell copies of the Software, and to permit
% persons to whom the Software is furnished to do so, subject to the
% following conditions:
%
% The above copyright notice and this permission notice shall be included
% in all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
% IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
% CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
% TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
% SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% check parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<3
sideinfo=[];
end
if nargin<2
parameter=[];
end
if nargin<1
error('Please specify input data x.');
end
if ~isfield(parameter,'anaHop')
parameter.anaHop = 2048;
end
if ~isfield(parameter,'win')
parameter.win = win(4096,2); % hann window
end
if ~isfield(parameter,'zeroPad')
parameter.zeroPad = 0;
end
if ~isfield(parameter,'fsAudio')
parameter.fsAudio = 22050;
end
if ~isfield(parameter,'numOfFrames')
parameter.numOfFrames = -1;
end
if ~isfield(parameter,'fftShift')
parameter.fftShift = 0;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% some pre calculations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% zeropad the window
w = parameter.win;
w = w(:);
zp = parameter.zeroPad;
w = [zeros(floor(zp/2),1);w;zeros(floor(zp/2),1)];
winLen = length(w);
winLenHalf = round(winLen/2);
fsAudio = parameter.fsAudio;
signalLength = length(x);
anaHop = parameter.anaHop;
% Pad the audio to center the windows and to avoid problems at the end
maxAnaHop = max(anaHop);
xPadded = [zeros(winLenHalf,1);x;zeros(winLen+maxAnaHop,1)];
% in case anaHop is a scalar, sample the window positions evenly in the
% input signal
if isscalar(anaHop)
if parameter.numOfFrames >= 0
numOfFrames = parameter.numOfFrames;
else
numOfFrames = floor((length(xPadded) - winLen)/anaHop + 1);
end
winPos = (0:numOfFrames-1) * anaHop + 1;
else
if parameter.numOfFrames >= 0
numOfFrames = parameter.numOfFrames;
else
numOfFrames = length(anaHop);
end
winPos = anaHop(1:numOfFrames);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% spectrogram calculation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
spec = zeros(winLenHalf+1,numOfFrames);
for i = 1 : numOfFrames
xi = xPadded(winPos(i):winPos(i) + winLen - 1) .* w;
if parameter.fftShift == 1
xi = fftshift(xi);
end
Xi = fft(xi);
spec(:,i) = Xi(1:winLenHalf+1);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% axis calculation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
t = (winPos - 1) ./ fsAudio;
f = (0 : winLenHalf) * fsAudio / winLen;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% update sideinfo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sideinfo.stft.anaHop = parameter.anaHop;
sideinfo.stft.win = parameter.win;
sideinfo.stft.zeroPad = parameter.zeroPad;
if isscalar(anaHop)
sideinfo.stft.featureRate = fsAudio/anaHop;
else
sideinfo.stft.featureRate = 'variable';
end
sideinfo.stft.originalLength = signalLength;
sideinfo.stft.fsAudio = parameter.fsAudio;
sideinfo.stft.fftShift = parameter.fftShift;
end