-
Notifications
You must be signed in to change notification settings - Fork 1
/
synthphtrax.m
138 lines (111 loc) · 3.86 KB
/
synthphtrax.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
128
129
130
131
132
133
134
135
136
137
138
function [X,ph,pp] = synthphtrax(F, M, P, SR, SUBF, DUR)
% X = synthphtrax(F, M, P, SR, SUBF, DUR) Reconstruct from tracks incl phase.
% Each row of F, M and P contains a series of frequency, magnitude
% and phase samples for a particular track. These will be reconstructed
% and summed 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. If DUR is nonzero, X will be padded or truncated
% to correspond to just this much time.
% [email protected] 1994aug20, 1996aug22
if(nargin<6)
DUR = 0;
end
rows = size(F,1);
cols = size(F,2);
cols = size(F,2);
opsamps = round(DUR*SR);
if(DUR == 0)
opsamps = ((cols-1)*SUBF);
end
X = zeros(1, opsamps);
% Time step
dt = SUBF/SR;
% quadratic or cubic interpolation
iorder = 3;
for row = 1:rows
mm = M(row,:);
ff = F(row,:);
pp = P(row,:);
% Where mm = 0, ff is undefined. But interp will care, so set them.
% First, 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)));
pp(find(isnan(pp))) = zeros(1, sum(isnan(pp)));
% For speed, chop off regions of initial and final zero magnitude -
% but want to include one zero from each end if they are there
nzv = find(ff);
firstcol = min(nzv);
lastcol = max(nzv);
zz = [max(1, firstcol-1):min(cols,lastcol+1)];
mm = mm(zz);
ff = ff(zz);
pp = pp(zz);
nzcols = length(zz);
% Find onsets - points where mm goes from zero (or NaN) to nzero
mz = (ff==0);
mask = mz & (0==[mz(2:nzcols),1]);
% Set frequencies at bins before onsets to match bin at onset
ff = ff.*(1-mask) + mask.*[ff(2:nzcols),0];
% Wind phase back to exactly match that freq
pp = pp.*(1-mask) + mask.*[pp(2:nzcols)-ff(2:nzcols)*dt*2*pi,0];
% Do offsets too
mask = mz & (0==[1,mz(1:(nzcols-1))]);
ff = ff.*(1-mask) + mask.*[0,ff(1:(nzcols-1))];
pp = pp.*(1-mask) + mask.*[0,pp(1:(nzcols-1))+ff(1:(nzcols-1))*dt*2*pi];
% Ok. Can interpolate now
% This is actually the slow part
ph = zeros(1,1+(nzcols-1)*SUBF);
for col = 1:(nzcols-1)
% time index
tt = [0:(SUBF-1)]/SUBF*dt;
dp = pp(col+1) - pp(col);
ww = 2*pi*ff(col+[0 1]);
% How many cycles at given frq?
ncycu = ((ww(1) + ww(2)) * dt/2 - dp)/(2*pi);
ncyc = round( ncycu );
dp = dp + 2*pi*ncyc;
if iorder == 2
% Re-estimate final frq to match final phase
ww(2) = 2/dt * dp - ww(1);
% .. and recover quadratic phase coefficient
a = (ww(2) - ww(1))/(2*dt);
% Hence phase is...
ph((col-1)*SUBF + [1:SUBF]) = pp(col) + ww(1)*tt + a*(tt.^2);
else
% iorder = 3
a2 = 3/(dt*dt)*(dp - dt/3*(2*ww(1)+ww(2)));
a3 = 1/(3*dt*dt)*(ww(2)-ww(1)-2*a2*dt);
ph((col-1)*SUBF + [1:SUBF]) = pp(col) + ww(1)*tt + a2*(tt.^2) + a3*(tt.^3);
end
end
% Last value in phase function directly from input
ph((nzcols-1)*SUBF + 1) = pp(nzcols);
% Simple linear interpolation of magnitudes
mmi = slinterp(mm, SUBF);
% run the oscillator and apply the magnitude envelope
xx = mmi.*cos(ph);
% overlap-add it in to the correct place in the array
base = 1+SUBF*(zz(1)-1);
sizex = prod(size(xx))-1;
xx = xx(1:sizex);
ww = (base-1)+[1:sizex];
X(ww) = X(ww) + xx;
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
% [email protected] 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));