annotate main/signal/resample.m @ 0:6b33357c7561 octave-forge

Initial revision
author pkienzle
date Wed, 10 Oct 2001 19:54:49 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
1 ## Copyright (C) 2000 Paul Kienzle
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
2 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
3 ## This program is free software; you can redistribute it and/or modify
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
4 ## it under the terms of the GNU General Public License as published by
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
5 ## the Free Software Foundation; either version 2 of the License, or
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
6 ## (at your option) any later version.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
7 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
8 ## This program is distributed in the hope that it will be useful,
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
11 ## GNU General Public License for more details.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
12 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
13 ## You should have received a copy of the GNU General Public License
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
14 ## along with this program; if not, write to the Free Software
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
15 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
16
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
17 ## usage: y=resample(x,p,q,d)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
18 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
19 ## Change the sample rate of x by a factor of p/q. Note that p and q do
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
20 ## not need to be integers since this routine does not use a polyphase
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
21 ## rate change algorithm, but instead uses bandlimited interpolation,
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
22 ## wherein the continous time signal is estimated by summing the sinc
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
23 ## functions of the nearest neighbouring points up to distance d.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
24 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
25 ## This is discussed in:
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
26 ## J. O. Smith and P. Gossett (1984). A flexible sampling-rate
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
27 ## conversion method. In ICASSP-84, Volume II, pp. 19.4.1-19.4.2.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
28 ## New York: IEEE Press.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
29 ## See the authors page at: http://www-ccrma.stanford.edu/~jos/resample/
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
30 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
31 ## Note that the resampling is not yet very fast or very good, but it is
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
32 ## very flexible.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
33 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
34 ## Example
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
35 ## ## Speech example
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
36 ## [x, fs] = auload(file_in_loadpath("sample.wav"));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
37 ## sound(resample(x,16000,fs), 16000); # resample at 16 kHz
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
38 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
39 ## ## Example from interp1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
40 ## xf=0:0.05:10.95; yf = sin(2*pi*xf/5);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
41 ## xp=0:10; yp = sin(2*pi*xp/5);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
42 ## r = resample(yp,xp(2),xf(2));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
43 ## plot(xf,yf,';original;',xf,r,';resample;',xp,yp,'*;;');
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
44 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
45 ## Note that resample computes all samples up to but not including time
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
46 ## n+1. If you are increasing the sample rate, this means that it will
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
47 ## generate samples beyond the end of the time range of the original
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
48 ## signal. That is why xf must goes all the way to 10.95 in the example.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
49
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
50 ## TODO: Fix so that audible clicking goes away.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
51 ## TODO: Change to a faster algorithm.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
52 ## TODO: Test on a chirp signal.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
53
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
54 function y=resample(x,p,q,order,beta)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
55 if (nargin < 2 || nargin > 5)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
56 usage("y=resample(x,p,q,order)");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
57 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
58
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
59 if (nargin < 3), q=1; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
60 if (nargin < 4), order = 5; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
61
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
62 ## ## chain to decimate/interpolate if appropriate
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
63 ## if p==1 && q==fix(q)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
64 ## y=decimate(x,q); order?
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
65 ## return;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
66 ## elseif q==1 && p==fix(p)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
67 ## y=interp(x,q); order?
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
68 ## return;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
69 ## endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
70
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
71 transpose = rows(x)==1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
72 if transpose, x = x.'; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
73
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
74 ## if rate reduction, apply antialiasing filter first
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
75 r=p/q;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
76 if (r < 1)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
77 b = fir1(2*order+1, r);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
78 x = fftfilt(b, x);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
79 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
80
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
81 ## Determine the new sampling times, and their distance to the old
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
82 ## ones. Note that the new series should be the maximum that can
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
83 ## be contained in the old series without going over the time
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
84 ## allotted to the old series. In short, you have to go a little
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
85 ## beyond the last sample of the old series if your new sampling
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
86 ## rate is higher.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
87 t=[1:1/r:length(x)+1-1/r]'; # the sampling points of the new series
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
88 idx = fix(t); # the nearest old point
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
89 t = t-idx; # distance to the nearest old point
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
90
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
91 ## generate the new series by summing the sinc functions of the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
92 ## nearest neighbour points implicit in the continuous time
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
93 ## expansion of the old series. This new series is truncated
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
94 ## to +/- order nearest neighbours. For convenience, the original
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
95 ## series is zero-padded before and after, implicitly setting the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
96 ## neighbours at the start of the signal to zero.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
97 x = [zeros(order,columns(x)) ; x ; zeros(order,columns(x))];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
98 y = zeros(length(idx),columns(x)); # the new series
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
99 for i=-order:order
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
100 w = sinc(t-i).*(0.5+0.5*cos(pi*(t-i)/(order+0.5))); # hanning window
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
101 y=y + x(idx+i+order,:).*w(:,ones(size(x,2),1));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
102 endfor
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
103
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
104 if transpose, y=y.'; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
105 endfunction
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
106
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
107 %!demo
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
108 %! xf=0:0.05:10.95; yf = sin(2*pi*xf/5);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
109 %! xp=0:10; yp = sin(2*pi*xp/5);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
110 %! r = resample(yp,xp(2),xf(2));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
111 %! oneplot();
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
112 %! title("confirm that the resampled function matches the original");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
113 %! plot(xf,yf,';original;',...
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
114 %! xf,r(1:length(xf)),';resample;',...
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
115 %! xp,yp,'*;;');
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
116 %! title("");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
117 %! [x, fs] = auload(file_in_loadpath("sample.wav"));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
118 %! sound(resample(x,16000,fs), 16000);