-
Notifications
You must be signed in to change notification settings - Fork 6
/
ISTFT.m
127 lines (116 loc) · 5.12 KB
/
ISTFT.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
function sig = ISTFT(specgram,shiftSize,analyWin,orgLen)
%
% Inverse short-time Fourier transform
% Synthesis window is calculated based on minimal distortion principle,
% which is described below:
% D. Griffin and J. Lim, "Signal estimation from modified short-time
% Fourier transform," IEEE Transactions on Acoustics, Speech, and Signal
% Processing, vol. 32, no. 2, pp. 236-243, 1984.
%
% Coded by D. Kitamura (d-kitamura@ieee.org)
%
% See also:
% http://d-kitamura.net
%
% [syntax]
% sig = ISTFT(specgram,shiftSize)
% sig = ISTFT(specgram,shiftSize,analyWin)
% sig = ISTFT(specgram,shiftSize,analyWin,orgLen)
%
% [inputs]
% specgram: STFT of input signal (frequency bins (fftSize/2+1) x time frames x channels)
% shiftSize: frame shift length
% analyWin: analysis window function used in STFT (fftSize x 1) or choose used analysis window function from below:
% 'hamming' : Hamming window (default)
% 'hann' : von Hann window
% 'rectangular': rectangular window
% 'blackman' : Blackman window
% 'sine' : sine window
% orgLen: length of original signal (before zero padding) (default: the same as that of output signal)
%
% [outputs]
% sig: time-domain waveform of input spectrogram (signal x channels)
%
% Arguments check and set default values
arguments
specgram (:,:,:) {mustBeNumeric}
shiftSize (1,1) double {mustBeInteger(shiftSize)}
analyWin
orgLen (1,1) double {mustBeInteger(orgLen)}
end
% Error check
[nFreq, nFrame, nCh] = size(specgram);
fftSize = (nFreq-1) * 2; % fft length used in STFT
if nCh > nFreq; error('Input spectrogram might be wrong. The size of it must be (freq x frame x ch).\n'); end
if isreal(specgram); error('Input spectrogram might be wrong. It does not complex-valued matrix.\n'); end
if mod(nFreq,2) == 0; error('The number of rows of sectrogram must be an odd number because it is (fftSize/2)+1.\n'); end
if mod(fftSize,shiftSize) ~= 0; error('fftSize must be dividable by shiftSize.\n'); end
if nargin < 3
analyWin = local_hamming(fftSize); % default window
else
if isnumeric(analyWin)
if size(analyWin, 1) ~= fftSize; error('The length of synthesis window must be the same as fftSize used in STFT.\n'); end
else
switch analyWin
case 'hamming'; analyWin = local_hamming(fftSize);
case 'hann'; analyWin = local_hann(fftSize);
case 'rectangular'; analyWin = local_rectangular(fftSize);
case 'blackman'; analyWin = local_blackman(fftSize);
case 'sine'; analyWin = local_sine(fftSize);
otherwise; error('Input window type is not supported. Type "help ISTFT" and check options.\n');
end
end
end
% Calculate optimal synthesis window based on minimal distortion principle
synthWin = local_optSynthWin(analyWin, shiftSize);
% Inverse STFT
tmpSig = zeros((nFrame-1)*shiftSize+fftSize, nCh); % memory allocation (zero-padded signal, length x nch)
specgram(1,:,:) = specgram(1,:,:)/2; % DC component
specgram(fftSize/2+1,:,:) = specgram(fftSize/2+1,:,:)/2; % Nyquist frequency component
for iCh = 1:nCh
shortTimeSig = real(ifft(specgram(:,:,iCh), fftSize) .* synthWin) * 2;
for iFrame = 1:nFrame % overlap add of short-time signals
startPoint = (iFrame-1)*shiftSize;
tmpSig(startPoint+1:startPoint+fftSize,iCh) = tmpSig(startPoint+1:startPoint+fftSize,iCh) + shortTimeSig(:,iFrame);
end
end
sig = tmpSig(fftSize-shiftSize+1:(nFrame-1)*shiftSize+fftSize, :); % discard padded zeros at beginning of signal, which are added in STFT
% Discarding padded zeros at the end of the signal
if exist('orgLen', 'var')
sig = sig(1:orgLen,:);
end
end
%% Local functions
function synthWin = local_optSynthWin(analyWin,shiftSize) % based on minimal distortion principle
fftSize = size(analyWin,1);
synthWin = zeros(fftSize,1);
for i = 1:shiftSize
amp = 0;
for j = 1:fftSize/shiftSize
amp = amp + analyWin(i+(j-1)*shiftSize,1)*analyWin(i+(j-1)*shiftSize,1);
end
for j = 1:fftSize/shiftSize
synthWin(i+(j-1)*shiftSize,1) = analyWin(i+(j-1)*shiftSize,1)/amp;
end
end
end
function win = local_hamming(fftSize)
t = linspace(0, 1, fftSize+1).'; % periodic (produce L+1 window and return L window)
win = 0.54*ones(fftSize,1) - 0.46*cos(2.0*pi*t(1:fftSize));
end
function win = local_hann(fftSize)
t = linspace(0, 1, fftSize+1).'; % periodic (produce L+1 window and return L window)
win = max(0.5*ones(fftSize,1) - 0.5*cos(2.0*pi*t(1:fftSize)),eps);
end
function win = local_rectangular(fftSize)
win = ones(fftSize,1);
end
function win = local_blackman(fftSize)
t = linspace(0, 1, fftSize+1).'; % periodic (produce L+1 window and return L window)
win = max(0.42*ones(fftSize,1) - 0.5*cos(2.0*pi*t(1:fftSize)) + 0.08*cos(4.0*pi*t(1:fftSize)),eps);
end
function win = local_sine(fftSize)
t = linspace(0, 1, fftSize+1).'; % periodic (produce L+1 window and return L window)
win = max(sin(pi*t(1:fftSize)),eps);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% EOF %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%