tomwalters@0
|
1 function [outputs, state1, state2] = PZBankStep2(inputs, pfreqs, pdamps, ...
|
tomwalters@0
|
2 mindamp, maxdamp, xmin, xmax, rmin, rmax, za0, za1, za2, state1, state2, ...
|
tomwalters@0
|
3 showconstellation, showtransfuns)
|
tomwalters@0
|
4 % function [outputs, state1, state2] = PZBankStep2(inputs, pfreqs, pdamps, ...
|
tomwalters@0
|
5 % mindamp, maxdamp, xmin, xmax, rmin, rmax, za0, za1, za2, state1, state2, ...
|
tomwalters@0
|
6 % showconstellation, showtransfuns)
|
tomwalters@0
|
7 % one time step of Pole-Zero-FilterBank, using row vectors of parameters
|
tomwalters@0
|
8 % inputs should contain shifted outputs from last time with new scalar
|
tomwalters@0
|
9 % waveform input on the front: inputs = [newin, outputs(1:N-1)];
|
tomwalters@0
|
10 % version 2 uses pole x and radius interpolation to adjust dampling
|
tomwalters@0
|
11 % the min and max are interpolation reference points, not limits to enforce
|
tomwalters@0
|
12 % and it should all work for multiple channels in parallel if the
|
tomwalters@0
|
13 % parameter vectors are all appropriately duplicated as well
|
tomwalters@0
|
14
|
tomwalters@0
|
15 if nargin < 15
|
tomwalters@0
|
16 showconstellation = 0; % don't by default; value is used as fig num.
|
tomwalters@0
|
17 end
|
tomwalters@0
|
18
|
tomwalters@0
|
19 if nargin < 16
|
tomwalters@0
|
20 showtransfuns = 0; % don't by default; value is used as fig num.
|
tomwalters@0
|
21 end
|
tomwalters@0
|
22
|
tomwalters@0
|
23 [nstages, nchans] = size(pfreqs); % number of filter channels and stereo channels
|
tomwalters@0
|
24
|
tomwalters@0
|
25 damprate = 1/(maxdamp - mindamp); % to save a bunch of divides
|
tomwalters@0
|
26
|
tomwalters@0
|
27 % limit to keep the poles reasonably stable:
|
tomwalters@0
|
28 interpfactor = (pdamps - mindamp)*damprate;
|
tomwalters@0
|
29 % interpfactor = min(1.5, interpfactor); % seems to keep it stable
|
tomwalters@0
|
30
|
tomwalters@0
|
31 x = xmin + (xmax - xmin).*interpfactor;
|
tomwalters@0
|
32 r = rmin + (rmax - rmin).*interpfactor;
|
tomwalters@0
|
33
|
tomwalters@0
|
34 %optional improvement to constellation adds a bit to r:
|
tomwalters@0
|
35 fd = pfreqs.*pdamps;
|
tomwalters@0
|
36 r = r + 0.25*fd.*min(0.05, fd); % quadratic for small values, then linear
|
tomwalters@0
|
37
|
tomwalters@0
|
38 zb1 = -2*x;
|
tomwalters@0
|
39 zb2 = r.*r;
|
tomwalters@0
|
40
|
tomwalters@0
|
41 bExtraDelay = 1; % boolean to control whether to do allow extra sample of filter delay
|
tomwalters@0
|
42
|
tomwalters@0
|
43 if bExtraDelay
|
tomwalters@0
|
44 % canonic poles but with input provided where unity DC gain is assured
|
tomwalters@0
|
45 % (mean value of state is always equal to mean value of input)
|
tomwalters@0
|
46 newstate = inputs - (state1 - inputs).*zb1 - (state2 - inputs).*zb2;
|
tomwalters@0
|
47
|
tomwalters@0
|
48 % canonic zeros part as before:
|
tomwalters@0
|
49
|
tomwalters@0
|
50 outputs = za0 .* newstate + za1 .* state1 + za2 .* state2 ;
|
tomwalters@0
|
51 outputs = outputs - 0.0001*outputs.^3; % cubic compression nonlinearity
|
tomwalters@0
|
52
|
tomwalters@0
|
53 state2 = state1;
|
tomwalters@0
|
54 state1 = newstate;
|
tomwalters@0
|
55 else
|
tomwalters@0
|
56 input = inputs(1,:); % first stage input is top input; ignore the rest
|
tomwalters@0
|
57 for stage = 1:nstages
|
tomwalters@0
|
58 newstate = input - (state1(stage,:) - input).*zb1(stage) - (state2(stage,:) - input).*zb2(stage);
|
tomwalters@0
|
59 % output of stage immediately becomes input for next stage, if needed:
|
tomwalters@0
|
60 input = za0(stage) .* newstate + za1(stage) .* state1(stage,:) + za2(stage) .* state2(stage,:) ;
|
tomwalters@0
|
61 input = input - 0.0001*input.^3; % cubic compression nonlinearity
|
tomwalters@0
|
62 outputs(stage,:) = input;
|
tomwalters@0
|
63 state2(stage,:) = state1(stage,:);
|
tomwalters@0
|
64 state1(stage,:) = newstate;
|
tomwalters@0
|
65 end
|
tomwalters@0
|
66 end
|
tomwalters@0
|
67
|
tomwalters@0
|
68
|
tomwalters@0
|
69 if showconstellation
|
tomwalters@0
|
70 figure(showconstellation);
|
tomwalters@0
|
71 % keyboard
|
tomwalters@0
|
72 hold off
|
tomwalters@0
|
73 % I have exact x and r, just need y
|
tomwalters@0
|
74 py = (r.*r - x.*x).^0.5;
|
tomwalters@0
|
75 % let it error out if we get a complex y.
|
tomwalters@0
|
76 plot(x,py,'x');
|
tomwalters@0
|
77 hold on
|
tomwalters@0
|
78 zr = (za2./za0).^0.5;
|
tomwalters@0
|
79 zx = -0.5*(za1./za0);
|
tomwalters@0
|
80 zy = (zr.*zr - zx.*zx).^0.5;
|
tomwalters@0
|
81 % zy(zy<0) = 0;
|
tomwalters@0
|
82 % zy = zy.^0.5;
|
tomwalters@0
|
83 plot(zx, zy, 'o');
|
tomwalters@0
|
84
|
tomwalters@0
|
85 drawnow
|
tomwalters@0
|
86 end
|
tomwalters@0
|
87
|
tomwalters@0
|
88 if showtransfuns % 1D indexing does only 1 channel for now
|
tomwalters@0
|
89 fbasis = pi*2.^((-129:0)' /12); %% 120 semitones, 10 octaves, leading up to pi rad/samp
|
tomwalters@0
|
90 z = exp(i*fbasis);
|
tomwalters@0
|
91 z2 = z.*z;
|
tomwalters@0
|
92 nch = size(pfreqs,1);
|
tomwalters@0
|
93 nf = length(fbasis);
|
tomwalters@0
|
94 chanxfns = zeros(nf, nch);
|
tomwalters@0
|
95 cascxfns = ones(nf, nch);
|
tomwalters@0
|
96 for ch = 1:length(pfreqs)
|
tomwalters@0
|
97 chanxfns(:,ch) = abs((1+zb1(ch)+zb2(ch)).*(za0(ch)+za1(ch).*z+za2(ch).*z2)./(1+zb1(ch).*z+zb2(ch).*z2));
|
tomwalters@0
|
98 cascxfns(:,ch) = cascxfns(:,max(1,ch-1)) .* chanxfns(:,ch);
|
tomwalters@0
|
99 end
|
tomwalters@0
|
100
|
tomwalters@0
|
101 figure(showtransfuns)
|
tomwalters@0
|
102 hold off
|
tomwalters@0
|
103 loglog(fbasis, chanxfns);
|
tomwalters@0
|
104 axis([min(fbasis), max(fbasis), 0.1, 10]);
|
tomwalters@0
|
105
|
tomwalters@0
|
106 figure(showtransfuns+1)
|
tomwalters@0
|
107 hold off
|
tomwalters@0
|
108 loglog(fbasis, cascxfns);
|
tomwalters@0
|
109 axis([min(fbasis), max(fbasis), 0.02, 20000]);
|
tomwalters@0
|
110 end
|
tomwalters@0
|
111
|
tomwalters@0
|
112
|
tomwalters@0
|
113 return;
|
tomwalters@0
|
114
|