samer@1
|
1 function s2=construct(sig)
|
samer@1
|
2
|
samer@1
|
3 fprintf('\nResampling %s to %g Hz...\n',tostring(sig.source),sig.rate);
|
samer@1
|
4 f1=rate(sig.source);
|
samer@1
|
5 f2=sig.rate;
|
samer@1
|
6 c=channels(sig);
|
samer@1
|
7
|
samer@1
|
8 [p,q]=rat(f2/f1,1e-12);
|
samer@1
|
9 sysobj=design(sig,p,q);
|
samer@1
|
10
|
samer@1
|
11
|
samer@1
|
12 delay=(length(sysobj.Numerator)-1)/2;
|
samer@1
|
13 outdelay = ceil(delay/q);
|
samer@1
|
14 indelay = ceil(delay/p);
|
samer@1
|
15 m=max(1,floor(sig.opts.bs/q)); % try to approximate requested input block size
|
samer@1
|
16 fprintf('Input/output delays are %d and %d.\n',indelay,outdelay);
|
samer@1
|
17 fprintf('Read block size is %d.\n\n',m*q);
|
samer@1
|
18
|
samer@1
|
19 s1=construct(sig.source & sigarray(zeros(channels(sig.source),indelay)));
|
samer@1
|
20 r1=s1.reader(m*q); % one and only input reader
|
samer@1
|
21 chunk=uint32(m*p); % filter output block size
|
samer@1
|
22 CHUNK=1:chunk;
|
samer@1
|
23 queue=[];
|
samer@1
|
24
|
samer@1
|
25 s2.start = s1.start;
|
samer@1
|
26 s2.stop = s1.stop;
|
samer@1
|
27 s2.dispose = @dispose;
|
samer@1
|
28 s2.reader = @reader;
|
samer@1
|
29
|
samer@1
|
30 % drop some samples to account for filter delay
|
samer@1
|
31 s2.start();
|
samer@1
|
32 sigreadn(s2,outdelay);
|
samer@1
|
33 s2.stop();
|
samer@1
|
34
|
samer@1
|
35 function dispose, s1.dispose(); release(sysobj); end
|
samer@1
|
36 function r2=reader(n)
|
samer@1
|
37 outbuf=zeros(c,n);
|
samer@1
|
38 r2=@next;
|
samer@1
|
39
|
samer@1
|
40 function [x,rem]=next
|
samer@1
|
41 % transfer up to n queued samples to outbuf
|
samer@1
|
42 pos=uint32(size(queue,2));
|
samer@1
|
43 if pos>=n % enough samples already waiting
|
samer@1
|
44 outbuf=queue(:,1:n);
|
samer@1
|
45 queue=queue(:,n+1:end);
|
samer@1
|
46 rem=0;
|
samer@1
|
47 else
|
samer@1
|
48 if pos==0, toread=n;
|
samer@1
|
49 else % use up queue
|
samer@1
|
50 outbuf(:,1:pos)=queue; queue=[];
|
samer@1
|
51 toread=n-pos;
|
samer@1
|
52 end
|
samer@1
|
53
|
samer@1
|
54 % transfer complete chunks
|
samer@1
|
55 while toread>=chunk
|
samer@1
|
56 [outbuf(:,pos+CHUNK),rem]=filter_next;
|
samer@1
|
57 toread=toread-chunk;
|
samer@1
|
58 pos=pos+chunk;
|
samer@1
|
59 if rem>0 % we ran out of samples
|
samer@1
|
60 rem=rem+toread; % account for rest of missing samples (not just this chunk)
|
samer@1
|
61 toread=0; % causes immediate exit after this
|
samer@1
|
62 end
|
samer@1
|
63 end
|
samer@1
|
64
|
samer@1
|
65 % transfer partial chunk if necessary
|
samer@1
|
66 if toread>0
|
samer@1
|
67 [y,rem]=filter_next;
|
samer@1
|
68 outbuf(:,pos+1:n)=y(:,1:toread);
|
samer@1
|
69 queue=y(:,toread+1:chunk-rem);
|
samer@1
|
70 rem=max(0,toread-(chunk-rem));
|
samer@1
|
71 end
|
samer@1
|
72 end
|
samer@1
|
73 x=outbuf;
|
samer@1
|
74 end
|
samer@1
|
75
|
samer@1
|
76 % returns the next block of m*p output samples
|
samer@1
|
77 function [x,rem]=filter_next
|
samer@1
|
78 [y,rem1]=r1();
|
samer@1
|
79 if rem1>0,
|
samer@1
|
80 y(:,end-rem1+1:end)=zeros(c,rem1); % pad with zeros
|
samer@1
|
81 rem=uint32(ceil(rem1*p/q)); % round down the number of valid samples
|
samer@1
|
82 else
|
samer@1
|
83 rem=rem1;
|
samer@1
|
84 end
|
samer@1
|
85 x=step(sysobj,y')';
|
samer@1
|
86 end
|
samer@1
|
87 end
|
samer@1
|
88 end
|