katkost@1
|
1 function [y,yh,ys] = spsmodel(x,fs,w,N,t,maxnS,stocf)
|
katkost@1
|
2 %=> analysis/synthesis of a sound using the sinusoidal harmonic model
|
katkost@1
|
3 % x: input sound, fs: sampling rate, w: analysis window (odd size),
|
katkost@1
|
4 % N: FFT size (minimum 512), t: threshold in negative dB,
|
katkost@1
|
5 % maxnS: maximum number of sinusoids,
|
katkost@1
|
6 % stocf: decimation factor of mag spectrum for stochastic analysis
|
katkost@1
|
7 % y: output sound, yh: harmonic component, ys: stochastic component
|
katkost@1
|
8 M = length(w); % analysis window size
|
katkost@1
|
9 Ns = 1024; % FFT size for synthesis
|
katkost@1
|
10 H = 256; % hop size for analysis and synthesis
|
katkost@1
|
11 N2 = N/2+1; % half-size of spectrum
|
katkost@1
|
12 soundlength = length(x); % length of input sound array
|
katkost@1
|
13 hNs = Ns/2; % half synthesis window size
|
katkost@1
|
14 hM = (M-1)/2; % half analysis window size
|
katkost@1
|
15 pin = max(N2,1+hM) % initialize sound pointer to middle of analysis window
|
katkost@1
|
16 pend = soundlength-max(N2,hM); % last sample to start a frame
|
katkost@1
|
17 fftbuffer = zeros(N,1); % initialize buffer for FFT
|
katkost@1
|
18 yh = zeros(soundlength+Ns/2,1); % output sine component
|
katkost@1
|
19 ys = zeros(soundlength+Ns/2,1); % output residual component
|
katkost@1
|
20 w = w/sum(w); % normalize analysis window
|
katkost@1
|
21 sw = zeros(Ns,1);
|
katkost@1
|
22 ow = triang(2*H-1); % overlapping window
|
katkost@1
|
23 ovidx = Ns/2+1-H+1:Ns/2+H; % overlap indexes
|
katkost@1
|
24 sw(ovidx) = ow(1:2*H-1);
|
katkost@1
|
25 bh = blackmanharris(Ns); % synthesis window
|
katkost@1
|
26 bh = bh ./ sum(bh); % normalize synthesis window
|
katkost@1
|
27 wr = bh; % window for residual
|
katkost@1
|
28 sw(ovidx) = sw(ovidx) ./ bh(ovidx);
|
katkost@1
|
29 sws = H*hanning(Ns)/2; % synthesis window for stochastic
|
katkost@1
|
30 lastysloc = zeros(maxnS,1); % initialize synthesis harmonic locations
|
katkost@1
|
31 ysphase = 2*pi*rand(maxnS,1); % initialize synthesis harmonic phases
|
katkost@1
|
32 fridx = 0;
|
katkost@1
|
33
|
katkost@1
|
34
|
katkost@1
|
35
|
katkost@1
|
36
|
katkost@1
|
37
|
katkost@1
|
38 while pin<pend
|
katkost@1
|
39 %-----analysis-----%
|
katkost@1
|
40 xw = x(pin-hM:pin+hM).*w(1:M); % window the input sound
|
katkost@1
|
41 fftbuffer = fftbuffer*0; % reset buffer;
|
katkost@1
|
42 fftbuffer(1:(M+1)/2) = xw((M+1)/2:M); % zero-phase window in fftbuffer
|
katkost@1
|
43 fftbuffer(N-(M-1)/2+1:N) = xw(1:(M-1)/2);
|
katkost@1
|
44 X = fft(fftbuffer); % compute the FFT
|
katkost@1
|
45 mX = 20*log10(abs(X(1:N2))); % magnitude spectrum
|
katkost@1
|
46 pX = unwrap(angle(X(1:N/2+1))); % unwrapped phase spectrum
|
katkost@1
|
47 ploc = 1 + find((mX(2:N2-1)>t) .* (mX(2:N2-1)>mX(3:N2)) ...
|
katkost@1
|
48 .* (mX(2:N2-1)>mX(1:N2-2))); % find peaks
|
katkost@1
|
49 [ploc,pmag,pphase] = peakinterp(mX,pX,ploc); % refine peak values
|
katkost@1
|
50 % sort by magnitude
|
katkost@1
|
51 [smag,I] = sort(pmag(:),1,'descend');
|
katkost@1
|
52 nS = min(maxnS,length(find(smag>t)));
|
katkost@1
|
53 sloc = ploc(I(1:nS));
|
katkost@1
|
54 sphase = pphase(I(1:nS));
|
katkost@1
|
55 if (fridx==0)
|
katkost@1
|
56 % update last frame data for first frame
|
katkost@1
|
57 lastnS = nS;
|
katkost@1
|
58 lastsloc = sloc;
|
katkost@1
|
59 lastsmag = smag;
|
katkost@1
|
60 lastsphase = sphase;
|
katkost@1
|
61 end
|
katkost@1
|
62 % connect sinusoids to last frame lnS (lastsloc,lastsphase,lastsmag)
|
katkost@1
|
63 sloc(1:nS) = (sloc(1:nS)~=0).*((sloc(1:nS)-1)*Ns/N); % synth. locs
|
katkost@1
|
64 lastidx = zeros(1,nS);
|
katkost@1
|
65 for i=1:nS
|
katkost@1
|
66 [dev,idx] = min(abs(sloc(i) - lastsloc(1:lastnS)));
|
katkost@1
|
67 lastidx(i) = idx;
|
katkost@1
|
68 end
|
katkost@1
|
69 ri= pin-hNs; % input sound pointer for residual analysis
|
katkost@1
|
70 xr = x(ri:ri+Ns-1).*wr(1:Ns); % window the input sound
|
katkost@1
|
71 Xr = fft(fftshift(xr)); % compute FFT for residual analysis
|
katkost@1
|
72 Xh = genspecsines(sloc,smag,sphase,Ns); % generate sines
|
katkost@1
|
73 Xr = Xr-Xh; % get the residual complex spectrum
|
katkost@1
|
74 mXr = 20*log10(abs(Xr(1:Ns/2+1))); % magnitude spectrum of residual
|
katkost@1
|
75 mXsenv = decimate(max(-200,mXr),stocf); % decimate the magnitude spectrum
|
katkost@1
|
76 % and avoid -Inf
|
katkost@1
|
77 %-----synthesis data-----%
|
katkost@1
|
78 ysloc = sloc; % synthesis locations
|
katkost@1
|
79 ysmag = smag(1:nS); % synthesis magnitudes
|
katkost@1
|
80 mYsenv = mXsenv; % synthesis residual envelope
|
katkost@1
|
81
|
katkost@1
|
82
|
katkost@1
|
83 %-----transformations-----%
|
katkost@1
|
84
|
katkost@1
|
85 %-----time mapping-----%
|
katkost@1
|
86 outsoundlength = soundlength*2;
|
katkost@1
|
87 TM=[ 0 soundlength/fs; % input time (sec)
|
katkost@1
|
88 0 outsoundlength/fs ]; % output time (sec)
|
katkost@1
|
89
|
katkost@1
|
90 %%-----frequency stretch-----%
|
katkost@1
|
91 %fstretch = 1.1;
|
katkost@1
|
92 %ysloc = ysloc .* (fstretch.^[0:length(ysloc)-1]');
|
katkost@1
|
93
|
katkost@1
|
94 %-----synthesis-----%
|
katkost@1
|
95 if (fridx==0)
|
katkost@1
|
96 lastysphase = ysphase;
|
katkost@1
|
97 end
|
katkost@1
|
98 if (nS>lastnS)
|
katkost@1
|
99 lastysphase = [ lastysphase ; zeros(nS-lastnS,1) ];
|
katkost@1
|
100 lastysloc = [ lastysloc ; zeros(nS-lastnS,1) ];
|
katkost@1
|
101 end
|
katkost@1
|
102 ysphase = lastysphase(lastidx(1:nS)) + 2*pi*(lastysloc(lastidx(1:nS))+ysloc)/2/Ns*H; % propagate phases
|
katkost@1
|
103 lastysloc = ysloc;
|
katkost@1
|
104 lastysphase = ysphase;
|
katkost@1
|
105 lastnS = nS; % update last frame data
|
katkost@1
|
106 lastsloc = sloc; % update last frame data
|
katkost@1
|
107 lastsmag = smag; % update last frame data
|
katkost@1
|
108 lastsphase = sphase; % update last frame data
|
katkost@1
|
109 Yh = genspecsines(ysloc,ysmag,ysphase,Ns); % generate sines
|
katkost@1
|
110 mYs = interp(mYsenv,stocf); % interpolate to original size
|
katkost@1
|
111 roffset = ceil(stocf/2)-1; % interpolated array offset
|
katkost@1
|
112 mYs = [ mYs(1)*ones(roffset,1); mYs(1:Ns/2+1-roffset) ];
|
katkost@1
|
113 mYs = 10.^(mYs/20); % dB to linear magnitude
|
katkost@1
|
114 pYs = 2*pi*rand(Ns/2+1,1); % generate phase spectrum with random values
|
katkost@1
|
115 mYs1 = [mYs(1:Ns/2+1); mYs(Ns/2:-1:2)]; % create complete magnitude spectrum
|
katkost@1
|
116 pYs1 = [pYs(1:Ns/2+1); -1*pYs(Ns/2:-1:2)]; % create complete phase spectrum
|
katkost@1
|
117 Ys = mYs1.*cos(pYs1)+1i*mYs1.*sin(pYs1); % compute complex spectrum
|
katkost@1
|
118 yhw = fftshift(real(ifft(Yh))); % sines in time domain using inverse FFT
|
katkost@1
|
119 ysw = fftshift(real(ifft(Ys))); % stochastic in time domain using IFFT
|
katkost@1
|
120 yh(ri:ri+Ns-1) = yh(ri:ri+Ns-1)+yhw(1:Ns).*sw; % overlap-add for sines
|
katkost@1
|
121 ys(ri:ri+Ns-1) = ys(ri:ri+Ns-1)+ysw(1:Ns).*sws; % overlap-add for stochastic
|
katkost@1
|
122 pin = pin+H; % advance the sound pointer
|
katkost@1
|
123 fridx = fridx+1;
|
katkost@1
|
124 end
|
katkost@1
|
125 y= yh+ys; % sum sines and stochastic |