function X = synthtrax(F, M, SR, SUBF, DUR)
% X = synthtrax(F, M, SR, SUBF, DUR) Reconstruct a sound from track rep'n.
% Each row of F and M contains a series of frequency and magnitude
% samples for a particular track. These will be remodulated and
% overlaid into the output sound X which will run at sample rate SR,
% although the columns in F and M are subsampled from that rate by
% a factor SUBF (default 128). If DUR is nonzero, X will be padded or
% truncated to correspond to just this much time.
% dpwe@icsi.berkeley.edu 1994aug20, 1996aug22
if(nargin<4)
SUBF = 128;
end
if(nargin<5)
DUR = 0;
end
rows = size(F,1);
cols = size(F,2);
opsamps = round(DUR*SR);
if(DUR == 0)
opsamps = 1 + ((cols-1)*SUBF);
end
X = zeros(1, opsamps);
for row = 1:rows
% fprintf(1, 'row %d.. \n', row);
mm = M(row,:);
ff = F(row,:);
% Where mm = 0, ff is undefined. But interp will care, so find points
% and set.
% First, find onsets - points where mm goes from zero (or NaN) to nzero
% Before that, even, set all nan values of mm to zero
mm(find(isnan(mm))) = zeros(1, sum(isnan(mm)));
ff(find(isnan(ff))) = zeros(1, sum(isnan(ff)));
nzv = find(mm);
firstcol = min(nzv);
lastcol = max(nzv);
% for speed, chop off regions of initial and final zero magnitude -
% but want to include one zero from each end if they are there
zz = [max(1, firstcol-1):min(cols,lastcol+1)];
if length(zz) > 0
mm = mm(zz);
ff = ff(zz);
nzcols = prod(size(zz));
mz = (mm==0);
mask = mz & (0==[mz(2:nzcols),1]);
ff = ff.*(1-mask) + mask.*[ff(2:nzcols),0];
% Do offsets too
mask = mz & (0==[1,mz(1:(nzcols-1))]);
ff = ff.*(1-mask) + mask.*[0,ff(1:(nzcols-1))];
% Ok. Can interpolate now
% This is actually the slow part
% % these parameters to interp make it do linear interpolation
% ff = interp(ff, SUBF, 1, 0.001);
% mm = interp(mm, SUBF, 1, 0.001);
% % chop off past-the-end vals from interp
% ff = ff(1:((nzcols-1)*SUBF)+1);
% mm = mm(1:((nzcols-1)*SUBF)+1);
% slinterp does linear interpolation, doesn't extrapolate, 4x faster
ff = slinterp(ff, SUBF);
mm = slinterp(mm, SUBF);
% convert frequency to phase values
pp = cumsum(2*pi*ff/SR);
% run the oscillator and apply the magnitude envelope
xx = mm.*cos(pp);
% add it in to the correct place in the array
base = 1+SUBF*(zz(1)-1);
sizex = prod(size(xx));
ww = (base-1)+[1:sizex];
X(ww) = X(ww) + xx;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Helper function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Y = slinterp(X,F)
% Y = slinterp(X,F) Simple linear-interpolate X by a factor F
% Y will have ((size(X)-1)*F)+1 points i.e. no extrapolation
% dpwe@icsi.berkeley.edu fast, narrow version for SWS
% Do it by rows
sx = prod(size(X));
% Ravel X to a row
X = X(1:sx);
X1 = [X(2:sx),0];
XX = zeros(F, sx);
for i=0:(F-1)
XX((i+1),:) = ((F-i)/F)*X + (i/F)*X1;
end
% Ravel columns of X for output, discard extrapolation at end
Y = XX(1:((sx-1)*F+1));