|
| 1 | +function varargout = istft(Y,varargin) |
| 2 | +% librosa.istft Inverse Short-time Fourier transform. |
| 3 | +% |
| 4 | +% This function matches the istft function from Librosa (tested for |
| 5 | +% version 0.9.2). Parameter defaults are identical to the Librosa |
| 6 | +% function. |
| 7 | +% |
| 8 | +% X = librosa.istft(Y) returns the inverse short-time Fourier transform |
| 9 | +% (istft) of Y. |
| 10 | +% |
| 11 | +% X = librosa.istft(S, FFTLength=NFFT) specifies the FFT length used to |
| 12 | +% calculate the stft. |
| 13 | +% |
| 14 | +% X = librosa.istft(S, Window=win) specifies the window used to compute |
| 15 | +% the stft. |
| 16 | +% |
| 17 | +% X = librosa.istft(S, HopLength=H) specifies the hop length. |
| 18 | +% |
| 19 | +% X = librosa.istft(S, Center=center) specifies if the signal was |
| 20 | +% centered. |
| 21 | +% |
| 22 | +% S = librosa.istft(X, GenerateMATLABCode=true) generates and opens an |
| 23 | +% untitled file containing code that implements the code of librosa.istft |
| 24 | +% using the MATLAB function istft. |
| 25 | +% |
| 26 | +% % EXAMPLE: |
| 27 | +% % Compute the istft of a real signal using the overlap-add method. |
| 28 | +% fs = 10240; |
| 29 | +% t = 0:1/fs:0.5-1/fs; |
| 30 | +% x = 5*sin(2*pi*t*10); |
| 31 | +% win = hamming(512,'periodic'); |
| 32 | +% S = librosa.stft(x,'Window',win,'HopLength',numel(win)-384,... |
| 33 | +% 'FFTLength',1024); |
| 34 | +% X = librosa.istft(S,'Window',win,'HopLength',numel(win)-384,... |
| 35 | +% 'FFTLength',1024); |
| 36 | +% |
| 37 | +% % Plot original and resynthesized signals. |
| 38 | +% plot(1:numel(x),x,1:size(X,1),X,'-.') |
| 39 | +% axis tight |
| 40 | +% xlabel('Time bins') |
| 41 | +% ylabel('Amplitude (V)') |
| 42 | +% title('Original and Reconstructed Signal') |
| 43 | +% legend('Original','Reconstructed') |
| 44 | + |
| 45 | +% Copyright 2022 The MathWorks, Inc. |
| 46 | + |
| 47 | +%% Validate input signal |
| 48 | +validateattributes(Y,{'single','double'},... |
| 49 | + {'nonempty','3d'}, ... |
| 50 | + 'librosa.istft','Y') |
| 51 | + |
| 52 | +%% Parse function parameters |
| 53 | +p = inputParser; |
| 54 | +addRequired(p,'Y'); |
| 55 | + |
| 56 | +validFFTLength = @(x) isnumeric(x) && isscalar(x) && (x > 0) && floor(x)==x; |
| 57 | +addParameter(p,'FFTLength',2048,validFFTLength); |
| 58 | + |
| 59 | +validHopLength = @(x) isnumeric(x) && isscalar(x) && (x > 0) && floor(x)==x; |
| 60 | +addParameter(p,'HopLength',2048,validHopLength); |
| 61 | + |
| 62 | +validWindowLength = @(x) isnumeric(x) && isscalar(x) && (x > 0) && floor(x)==x; |
| 63 | +addParameter(p,'WindowLength',2048,validWindowLength); |
| 64 | + |
| 65 | +validWindow = @(x) ischar(x) || isstring(x) || isvector(x) && isreal(x) &&isfloat(x); |
| 66 | +addParameter(p,'Window',hann(2048,'periodic'),validWindow); |
| 67 | + |
| 68 | +validCenter = @(x)isscalar(x) && (isnumeric(x)||islogical(x)); |
| 69 | +addParameter(p,'Center',true,validCenter); |
| 70 | + |
| 71 | +validLength = @(x) isnumeric(x) && isscalar(x) && (x > 0) && floor(x)==x; |
| 72 | +addParameter(p,'Length',true,validLength); |
| 73 | + |
| 74 | +validCodegen = @(x)isscalar(x) && (isnumeric(x)||islogical(x)); |
| 75 | +addParameter(p,'GenerateMATLABCode',false,validCodegen); |
| 76 | + |
| 77 | +parse(p,Y,varargin{:}); |
| 78 | + |
| 79 | +FFTLength = p.Results.FFTLength; |
| 80 | +center = p.Results.Center; |
| 81 | + |
| 82 | +% Reconcile Window and WindowLength specifications, similar to Librosa |
| 83 | +% function |
| 84 | +if ismember('WindowLength',p.UsingDefaults) |
| 85 | + if ismember('Window',p.UsingDefaults) |
| 86 | + winlen = FFTLength; |
| 87 | + else |
| 88 | + win = p.Results.Window; |
| 89 | + if ischar(win) || isstring(win) |
| 90 | + winlen = FFTLength; |
| 91 | + else |
| 92 | + winlen = numel(win); |
| 93 | + end |
| 94 | + end |
| 95 | +else |
| 96 | + winlen = p.Results.WindowLength; |
| 97 | +end |
| 98 | + |
| 99 | +if ismember('Window',p.UsingDefaults) |
| 100 | + win = hann(winlen,'periodic'); |
| 101 | +else |
| 102 | + win = p.Results.Window; |
| 103 | + if ischar(win) || isstring(win) |
| 104 | + win = sprintf('%s(%d)',win,winlen); |
| 105 | + win = eval(win); |
| 106 | + end |
| 107 | +end |
| 108 | + |
| 109 | +if (numel(win) ~= winlen) |
| 110 | + error('Window size mismatch') |
| 111 | +end |
| 112 | + |
| 113 | +if ismember('HopLength',p.UsingDefaults) |
| 114 | + hopLength = floor(numel(win)/4); |
| 115 | +else |
| 116 | + hopLength = p.Results.HopLength; |
| 117 | +end |
| 118 | + |
| 119 | +lengthSpecified = ~ismember('Length',p.UsingDefaults); |
| 120 | +len = p.Results.Length; |
| 121 | + |
| 122 | +if numel(win)<FFTLength |
| 123 | + L = FFTLength-numel(win); |
| 124 | + L2 = floor(L/2); |
| 125 | + win = win(:); |
| 126 | + win = [zeros(L2,1); win; zeros(FFTLength-L2-numel(win),1)]; |
| 127 | +end |
| 128 | + |
| 129 | +if p.Results.GenerateMATLABCode |
| 130 | + strWriter = StringWriter; |
| 131 | +else |
| 132 | + strWriter = librosa.utils.StringWriter; |
| 133 | +end |
| 134 | + |
| 135 | +if lengthSpecified |
| 136 | + strWriter.addcr('%s\n%% Adjust length.','%%'); |
| 137 | + if center |
| 138 | + padded_length = len + FFTLength; |
| 139 | + strWriter.addcr('padLength = %d+%d;',len,FFTLength); |
| 140 | + else |
| 141 | + padded_length = len; |
| 142 | + strWriter.addcr('padLength = %d;',len); |
| 143 | + end |
| 144 | + n_frames = min(size(Y,2),ceil(padded_length/hopLength)); |
| 145 | + Y = Y(:,1:n_frames,:); |
| 146 | + strWriter.addcr('numFrames = min(size(Y,2),ceil(padLength/%d));',hopLength); |
| 147 | + strWriter.addcr('Y = Y(:,1:numFrames,:)'); |
| 148 | +end |
| 149 | + |
| 150 | +y = istft(Y,Window=win,... |
| 151 | + OverlapLength=numel(win)-hopLength,... |
| 152 | + FFTLength=FFTLength,... |
| 153 | + FrequencyRange="onesided"); |
| 154 | + |
| 155 | +strWriter.addcr('%s\n%% Compute ISTFT.','%%'); |
| 156 | +strWriter.addcr('y = istft(Y, Window=%s,...',mat2str(win(:),32)); |
| 157 | +strWriter.addcr('OverlapLength=%d,...',numel(win)-hopLength); |
| 158 | +strWriter.addcr('FFTLength=%d,...',FFTLength); |
| 159 | +strWriter.addcr('FrequencyRange="onesided");'); |
| 160 | + |
| 161 | +if ~lengthSpecified |
| 162 | + if center |
| 163 | + strWriter.addcr('%s\n%% STFT was centered.','%%'); |
| 164 | + L = floor(FFTLength/2); |
| 165 | + y = y(L+1:size(y,1)-L,:); |
| 166 | + strWriter.addcr('L = floor(%d/2);',FFTLength); |
| 167 | + strWriter.addcr('y = y(L+1:size(y,1)-L,:);',FFTLength); |
| 168 | + end |
| 169 | +else |
| 170 | + if center |
| 171 | + strWriter.addcr('%s\n%% STFT was centered.','%%'); |
| 172 | + L = floor(FFTLength/2); |
| 173 | + strWriter.addcr('L = floor(%d/2);',FFTLength); |
| 174 | + y = y(L+1:L+len,:); |
| 175 | + strWriter.addcr('y = y(L+1:L+%d,:);',len); |
| 176 | + else |
| 177 | + y = y(1:len,:); |
| 178 | + strWriter.addcr('y = y(1:%d,:);',len); |
| 179 | + end |
| 180 | +end |
| 181 | + |
| 182 | +varargout{1} = y; |
| 183 | +varargout{2} = strWriter.char; |
| 184 | + |
| 185 | +generateMATLABCode = p.Results.GenerateMATLABCode; |
| 186 | +if generateMATLABCode |
| 187 | + footer = sprintf('%% _Generated by MATLAB (R) and Audio Toolbox on %s_', string(datetime("now"))); |
| 188 | + strWriter.addcr('\n%s\n%s','%%',footer); |
| 189 | + matlab.internal.liveeditor.openAsLiveCode(strWriter.char) |
| 190 | +end |
0 commit comments