summaryrefslogtreecommitdiff
path: root/2.3-1/toyApplication/tols.m
diff options
context:
space:
mode:
Diffstat (limited to '2.3-1/toyApplication/tols.m')
-rw-r--r--2.3-1/toyApplication/tols.m160
1 files changed, 160 insertions, 0 deletions
diff --git a/2.3-1/toyApplication/tols.m b/2.3-1/toyApplication/tols.m
new file mode 100644
index 00000000..2275e436
--- /dev/null
+++ b/2.3-1/toyApplication/tols.m
@@ -0,0 +1,160 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [y, fullframes, loops] = tols(x, h, L)
+% perform time-partitioned overlap save algorithm
+% x -- signal (vector)
+% h -- impulse response (vector)
+% L -- fft size (frame length for impulse response segmentation is L/2)
+% y -- convolution result
+% fullframes -- number of full signal frames processed
+% loops -- number of total loops
+%
+% @author gregor heinrich :: arbylon
+% @date Nov./Dec. 2006
+
+
+
+% fft size for signal and stepping
+% (only for notation)
+K = L / 2;
+% (only for notation; is always = K)
+S = L - K;
+
+% segment impulse response
+[HH, R] = segmentir(h, K);
+
+% original length of x (without zero-padding the first frame)
+lenx = length(x);
+
+% zero-padding of first frame ("saved zeroth frame")
+x = [zeros(K,1); x];
+fprintf('padding %i zeros in front of x\n', K);
+
+y = [];
+
+% window of input signal frame spectra
+% @real-time: can be implemented as circular buffer
+XX = zeros(L, R);
+
+% number of full frames from the input
+% @real-time: unknown
+fullframes = floor((length(x)-L)/S) + 1;
+fprintf('expect %i full input frames and %i IR frames.\n', fullframes, R);
+
+% signal frames available (including partial ones)
+hassignal = 1;
+% more tail frames needed to complete convolution
+hastail = 1;
+i = 0;
+
+% @real-time: we don't know when the signal ends, thus we don't use the
+% fullframes variable in a for loop
+while hassignal || hastail
+ icirc = mod(i, R) + 1;
+ % index into x where xx starts and ends (includes zero-padding)
+ xxstart = i * S + 1;
+ xxend = i * S + L;
+ if xxend <= length(x)
+ % complete signal frame
+ xx = x(xxstart : xxend);
+ % fprintf(' - signal over full frame\n');
+ elseif xxstart <= length(x)
+ % incomplete signal frame -> must be zero-padded
+ % @real-time: signal ending is started
+ xx = x(xxstart : end);
+ zpad = xxend - length(x);
+ xx = [xx; zeros(zpad, 1)];
+ fprintf(' - loop %i: signal incomplete, padding %i zeroes\n', i+1, zpad);
+ else
+ % @real-time: there are no samples from the input left; signal
+ % ending is finished; convolution ending is started
+ if hassignal
+ hassignal = 0;
+ % xframes should be exactly = fullframes
+ xframes = i - 1;
+ fprintf(' - loop %i: signal finished, processing tail only.\n', i + 1);
+ end
+ end
+
+ % drop oldest frame and add new one
+ % @real-time: can be implemented using a circular buffer
+ if (i >= R)
+ rend = R;
+ else
+ % before all ir frames are filled
+ rend = i + 1;
+ end
+ if hassignal
+ % more signal samples available
+ X = fft(xx, L);
+ % for debugging with 1:n: X = round(ifft(X));
+ XX(:, icirc) = X;
+ rstart = 1;
+ else
+ % @real-time: during convolution ending
+ rstart = i - xframes + 1;
+ end
+
+ % total length of y
+ ylen = lenx + length(h) - 1;
+ % end of output larger than expected result?
+ yyend = S*(i+1);
+ if yyend > ylen
+ hassignal = 0;
+ hastail = 0;
+ loops = i;
+ end
+
+ % add most recent frame to convolution result
+ if hastail == 1
+ yylen = S;
+ y = [y; zeros(S,1)];
+ else
+ yylen = S - (yyend - ylen);
+ y = [y; zeros(yylen,1)];
+ loops = i;
+ end
+
+ % @real-time: loops over r can be done in parallel, also between
+ % subsequent loops over i
+ for r=rstart:rend
+ rcirc = mod(i - (r - 1), R) + 1;
+ % calculate partial convolution
+ Y = XX(:,rcirc) .* HH(:,r);
+ yy = ifft(Y, L);
+ % select last L-K points
+ yy = yy(S+1:L);
+ % add contribution of signal and ir with r frames offset
+ y(end-yylen+1:end) = y(end-yylen+1:end) + yy(1:yylen);
+ end
+ i = i+1;
+
+end % while
+fprintf(' - total loops: %i\n', i);
+% TODO: make this independent of xlen
+%y = y(1:ylen);
+endfunction % convolve
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [HH, R] = segmentir(h, K)
+% segment impulse response into columns, the last
+% frame/column is zero-padded as needed.
+% HH -- matrix of impulse response frames
+% R -- number of IR frames (=columns of HH)
+ L = 2 * K;
+ fullframes = ceil(length(h)/K) - 1;
+ for i=1:fullframes
+ % column-wise IR frames
+ hh(:,i) = h(K*(i-1)+1 : K*i);
+ end
+ if mod(length(h), K) ~= 0
+ % zero-pad last ir frame
+ hlast = h((fullframes*K+1):length(h));
+ hlast = [hlast ; zeros(K - length(hlast),1)];
+ hh(:,fullframes+1) = hlast;
+ end
+ % column ffts
+ HH = fft(hh, L);
+ % for debugging 1:n: HH = round(ifft(HH));
+ R = size(HH,2);
+endfunction % segmentir
+