2 ** Copyright (C) 2010 Cockos Incorporated
11 #define min(x,y) ((x)<(y)?(x):(y))
15 #define PI 3.1415926535897932384626433832795
18 class WDL_Resampler::WDL_Resampler_IIRFilter
21 WDL_Resampler_IIRFilter()
26 ~WDL_Resampler_IIRFilter()
32 memset(m_hist
,0,sizeof(m_hist
));
35 void setParms(double fpos
, double Q
)
37 if (fabs(fpos
-m_fpos
)<0.000001) return;
40 double pos
= fpos
* PI
;
44 double alpha
=spos
/(2.0*Q
);
46 double sc
=1.0/( 1 + alpha
);
48 m_b2
= m_b0
= m_b1
*0.5;
49 m_a1
= -2 * cpos
* sc
;
54 void Apply(WDL_ResampleSample
*in1
, WDL_ResampleSample
*out1
, int ns
, int span
, int w
)
56 double b0
=m_b0
,b1
=m_b1
,b2
=m_b2
,a1
=m_a1
,a2
=m_a2
;
57 double *hist
=m_hist
[w
];
62 double out
= (double) ( in
*b0
+ hist
[0]*b1
+ hist
[1]*b2
- hist
[2]*a1
- hist
[3]*a2
);
63 hist
[1]=hist
[0]; hist
[0]=in
;
64 hist
[3]=hist
[2]; *out1
= hist
[2]=denormal_filter_double(out
);
73 double m_b0
,m_b1
,m_b2
;
74 double m_hist
[WDL_RESAMPLE_MAX_FILTERS
*WDL_RESAMPLE_MAX_NCH
][4];
78 void inline WDL_Resampler::SincSample(WDL_ResampleSample
*outptr
, WDL_ResampleSample
*inptr
, double fracpos
, int nch
, WDL_SincFilterSample
*filter
, int filtsz
)
80 int oversize
=m_lp_oversize
;
83 int ifpos
=(int)fracpos
;
84 filter
+= oversize
-1-ifpos
;
87 for (x
= 0; x
< nch
; x
++)
89 double sum
=0.0,sum2
=0.0;
90 WDL_SincFilterSample
*fptr
=filter
;
91 WDL_ResampleSample
*iptr
=inptr
+x
;
95 sum
+= fptr
[0]*iptr
[0];
96 sum2
+= fptr
[1]*iptr
[0];
100 outptr
[x
]=sum
*fracpos
+ sum2
*(1.0-fracpos
);
105 void inline WDL_Resampler::SincSample1(WDL_ResampleSample
*outptr
, WDL_ResampleSample
*inptr
, double fracpos
, WDL_SincFilterSample
*filter
, int filtsz
)
107 int oversize
=m_lp_oversize
;
109 int ifpos
=(int)fracpos
;
110 filter
+= oversize
-1-ifpos
;
113 double sum
=0.0,sum2
=0.0;
114 WDL_SincFilterSample
*fptr
=filter
;
115 WDL_ResampleSample
*iptr
=inptr
;
119 sum
+= fptr
[0]*iptr
[0];
120 sum2
+= fptr
[1]*iptr
[0];
124 outptr
[0]=sum
*fracpos
+sum2
*(1.0-fracpos
);
128 void inline WDL_Resampler::SincSample2(WDL_ResampleSample
*outptr
, WDL_ResampleSample
*inptr
, double fracpos
, WDL_SincFilterSample
*filter
, int filtsz
)
130 int oversize
=m_lp_oversize
;
132 int ifpos
=(int)fracpos
;
133 filter
+= oversize
-1-ifpos
;
140 WDL_SincFilterSample
*fptr
=filter
;
141 WDL_ResampleSample
*iptr
=inptr
;
145 sum
+= fptr
[0]*iptr
[0];
146 sum2
+= fptr
[0]*iptr
[1];
147 sumb
+= fptr
[1]*iptr
[0];
148 sum2b
+= fptr
[1]*iptr
[1];
149 sum
+= fptr
[oversize
]*iptr
[2];
150 sum2
+= fptr
[oversize
]*iptr
[3];
151 sumb
+= fptr
[oversize
+1]*iptr
[2];
152 sum2b
+= fptr
[oversize
+1]*iptr
[3];
156 outptr
[0]=sum
*fracpos
+ sumb
*(1.0-fracpos
);
157 outptr
[1]=sum2
*fracpos
+ sum2b
*(1.0-fracpos
);
163 WDL_Resampler::WDL_Resampler()
166 m_filterpos
=0.693f
; // .792 ?
175 m_filter_coeffs_size
=0;
185 WDL_Resampler::~WDL_Resampler()
190 void WDL_Resampler::Reset(double fracpos
)
195 m_samples_in_rsinbuf
=0;
196 if (m_iirfilter
) m_iirfilter
->Reset();
199 void WDL_Resampler::SetMode(bool interp
, int filtercnt
, bool sinc
, int sinc_size
, int sinc_interpsize
)
201 m_sincsize
= sinc
&& sinc_size
>= 4 ? sinc_size
> 8192 ? 8192 : sinc_size
: 0;
202 m_sincoversize
= m_sincsize
? (sinc_interpsize
<= 1 ? 1 : sinc_interpsize
>=4096 ? 4096 : sinc_interpsize
) : 1;
204 m_filtercnt
= m_sincsize
? 0 : (filtercnt
<=0?0 : filtercnt
>= WDL_RESAMPLE_MAX_FILTERS
? WDL_RESAMPLE_MAX_FILTERS
: filtercnt
);
205 m_interp
=interp
&& !m_sincsize
;
207 // sprintf(buf,"setting interp=%d, filtercnt=%d, sinc=%d,%d\n",m_interp,m_filtercnt,m_sincsize,m_sincoversize);
208 // OutputDebugString(buf);
212 m_filter_coeffs
.Resize(0);
213 m_filter_coeffs_size
=0;
222 void WDL_Resampler::SetRates(double rate_in
, double rate_out
)
224 if (rate_in
<1.0) rate_in
=1.0;
225 if (rate_out
<1.0) rate_out
=1.0;
226 if (rate_in
!= m_sratein
|| rate_out
!= m_srateout
)
230 m_ratio
=m_sratein
/ m_srateout
;
235 void WDL_Resampler::BuildLowPass(double filtpos
) // only called in sinc modes
237 int wantsize
=m_sincsize
;
238 int wantinterp
=m_sincoversize
;
240 if (m_filter_ratio
!=filtpos
||
241 m_filter_coeffs_size
!= wantsize
||
242 m_lp_oversize
!= wantinterp
)
244 m_lp_oversize
= wantinterp
;
245 m_filter_ratio
=filtpos
;
247 // build lowpass filter
248 int allocsize
= (wantsize
+1)*m_lp_oversize
;
249 WDL_SincFilterSample
*cfout
=m_filter_coeffs
.Resize(allocsize
);
250 if (m_filter_coeffs
.GetSize()==allocsize
)
252 m_filter_coeffs_size
=wantsize
;
254 int sz
=wantsize
*m_lp_oversize
;
256 double filtpower
=0.0;
257 double windowpos
= 0.0;
258 double dwindowpos
= 2.0 * PI
/(double)(sz
);
259 double dsincpos
= PI
/ m_lp_oversize
* filtpos
; // filtpos is outrate/inrate, i.e. 0.5 is going to half rate
260 double sincpos
= dsincpos
* (double)(-hsz
);
263 for (x
= -hsz
; x
< hsz
+m_lp_oversize
; x
++)
265 double val
= 0.35875 - 0.48829 * cos(windowpos
) + 0.14128 * cos(2*windowpos
) - 0.01168 * cos(6*windowpos
); // blackman-harris
266 if (x
) val
*= sin(sincpos
) / sincpos
;
268 windowpos
+=dwindowpos
;
271 cfout
[hsz
+x
] = (WDL_SincFilterSample
)val
;
272 if (x
< hsz
) filtpower
+= val
;
274 filtpower
= m_lp_oversize
/filtpower
;
275 for (x
= 0; x
< sz
+m_lp_oversize
; x
++)
277 cfout
[x
] = (WDL_SincFilterSample
) (cfout
[x
]*filtpower
);
280 else m_filter_coeffs_size
=0;
285 double WDL_Resampler::GetCurrentLatency()
287 double v
=((double)m_samples_in_rsinbuf
-m_filtlatency
)/m_sratein
;
293 int WDL_Resampler::ResamplePrepare(int out_samples
, int nch
, WDL_ResampleSample
**inbuffer
)
295 if (nch
> WDL_RESAMPLE_MAX_NCH
|| nch
< 1) return 0;
298 if (m_sincsize
>1) fsize
= m_sincsize
;
301 if (hfs
>1 && m_samples_in_rsinbuf
<hfs
-1)
303 m_filtlatency
+=hfs
-1 - m_samples_in_rsinbuf
;
305 m_samples_in_rsinbuf
=hfs
-1;
307 if (m_samples_in_rsinbuf
>0)
309 WDL_ResampleSample
*p
= m_rsinbuf
.Resize(m_samples_in_rsinbuf
*nch
,false);
310 memset(p
,0,sizeof(WDL_ResampleSample
)*m_rsinbuf
.GetSize());
316 if (!m_feedmode
) sreq
= (int)(m_ratio
* out_samples
) + 4 + fsize
- m_samples_in_rsinbuf
;
317 else sreq
= out_samples
;
322 m_rsinbuf
.Resize((m_samples_in_rsinbuf
+sreq
)*nch
,false);
324 int sz
= m_rsinbuf
.GetSize()/(nch
?nch
:1) - m_samples_in_rsinbuf
;
330 goto again
; // try again with half the size
332 // todo: notify of error?
336 *inbuffer
= m_rsinbuf
.Get() + m_samples_in_rsinbuf
*nch
;
338 m_last_requested
=sreq
;
344 int WDL_Resampler::ResampleOut(WDL_ResampleSample
*out
, int nsamples_in
, int nsamples_out
, int nch
)
346 if (nch
> WDL_RESAMPLE_MAX_NCH
|| nch
< 1) return 0;
350 if (m_ratio
> 1.0 && nsamples_in
> 0) // filter input
352 if (!m_iirfilter
) m_iirfilter
= new WDL_Resampler_IIRFilter
;
355 m_iirfilter
->setParms((1.0/m_ratio
)*m_filterpos
,m_filterq
);
357 WDL_ResampleSample
*buf
=(WDL_ResampleSample
*)m_rsinbuf
.Get() + m_samples_in_rsinbuf
*nch
;
360 for (x
=0; x
< nch
; x
++)
361 for (a
= 0; a
< n
; a
++)
362 m_iirfilter
->Apply(buf
+x
,buf
+x
,nsamples_in
,nch
,offs
++);
366 m_samples_in_rsinbuf
+= min(nsamples_in
,m_last_requested
); // prevent the user from corrupting the internal state
369 int rsinbuf_availtemp
= m_samples_in_rsinbuf
;
371 if (nsamples_in
< m_last_requested
) // flush out to ensure we can deliver
373 int fsize
=(m_last_requested
-nsamples_in
)*2 + m_sincsize
*2;
375 int alloc_size
=(m_samples_in_rsinbuf
+fsize
)*nch
;
376 WDL_ResampleSample
*zb
=m_rsinbuf
.Resize(alloc_size
,false);
377 if (m_rsinbuf
.GetSize()==alloc_size
)
379 memset(zb
+m_samples_in_rsinbuf
*nch
,0,fsize
*nch
*sizeof(WDL_ResampleSample
));
380 rsinbuf_availtemp
= m_samples_in_rsinbuf
+fsize
;
385 double srcpos
=m_fracpos
;
386 double drspos
= m_ratio
;
387 WDL_ResampleSample
*localin
= m_rsinbuf
.Get();
389 WDL_ResampleSample
*outptr
=out
;
395 if (m_sincsize
) // sinc interpolating
397 if (m_ratio
> 1.0) BuildLowPass(1.0 / (m_ratio
*1.03));
398 else BuildLowPass(1.0);
400 int filtsz
=m_filter_coeffs_size
;
401 int filtlen
= rsinbuf_availtemp
- filtsz
;
402 outlatadj
=filtsz
/2-1;
403 WDL_SincFilterSample
*filter
=m_filter_coeffs
.Get();
409 int ipos
= (int)srcpos
;
411 if (ipos
>= filtlen
-1) break; // quit decoding, not enough input samples
413 SincSample1(outptr
,localin
+ ipos
,srcpos
-ipos
,filter
,filtsz
);
423 int ipos
= (int)srcpos
;
425 if (ipos
>= filtlen
-1) break; // quit decoding, not enough input samples
427 SincSample2(outptr
,localin
+ ipos
*2,srcpos
-ipos
,filter
,filtsz
);
437 int ipos
= (int)srcpos
;
439 if (ipos
>= filtlen
-1) break; // quit decoding, not enough input samples
441 SincSample(outptr
,localin
+ ipos
*nch
,srcpos
-ipos
,nch
,filter
,filtsz
);
448 else if (!m_interp
) // point sampling
454 int ipos
= (int)srcpos
;
455 if (ipos
>= rsinbuf_availtemp
) break; // quit decoding, not enough input samples
457 *outptr
++ = localin
[ipos
];
466 int ipos
= (int)srcpos
;
467 if (ipos
>= rsinbuf_availtemp
) break; // quit decoding, not enough input samples
471 outptr
[0] = localin
[ipos
];
472 outptr
[1] = localin
[ipos
+1];
481 int ipos
= (int)srcpos
;
482 if (ipos
>= rsinbuf_availtemp
) break; // quit decoding, not enough input samples
484 memcpy(outptr
,localin
+ ipos
*nch
,nch
*sizeof(WDL_ResampleSample
));
490 else // linear interpolation
496 int ipos
= (int)srcpos
;
497 double fracpos
=srcpos
-ipos
;
499 if (ipos
>= rsinbuf_availtemp
-1)
501 break; // quit decoding, not enough input samples
504 double ifracpos
=1.0-fracpos
;
505 WDL_ResampleSample
*inptr
= localin
+ ipos
;
506 *outptr
++ = inptr
[0]*(ifracpos
) + inptr
[1]*(fracpos
);
515 int ipos
= (int)srcpos
;
516 double fracpos
=srcpos
-ipos
;
518 if (ipos
>= rsinbuf_availtemp
-1)
520 break; // quit decoding, not enough input samples
523 double ifracpos
=1.0-fracpos
;
524 WDL_ResampleSample
*inptr
= localin
+ ipos
*2;
525 outptr
[0] = inptr
[0]*(ifracpos
) + inptr
[2]*(fracpos
);
526 outptr
[1] = inptr
[1]*(ifracpos
) + inptr
[3]*(fracpos
);
536 int ipos
= (int)srcpos
;
537 double fracpos
=srcpos
-ipos
;
539 if (ipos
>= rsinbuf_availtemp
-1)
541 break; // quit decoding, not enough input samples
544 double ifracpos
=1.0-fracpos
;
546 WDL_ResampleSample
*inptr
= localin
+ ipos
*nch
;
549 *outptr
++ = inptr
[0]*(ifracpos
) + inptr
[nch
]*(fracpos
);
561 if (m_ratio
< 1.0 && ret
>0) // filter output
563 if (!m_iirfilter
) m_iirfilter
= new WDL_Resampler_IIRFilter
;
565 m_iirfilter
->setParms(m_ratio
*m_filterpos
,m_filterq
);
569 for (x
=0; x
< nch
; x
++)
570 for (a
= 0; a
< n
; a
++)
571 m_iirfilter
->Apply(out
+x
,out
+x
,ret
,nch
,offs
++);
577 if (ret
>0 && rsinbuf_availtemp
>m_samples_in_rsinbuf
) // we had to pad!!
579 // check for the case where rsinbuf_availtemp>m_samples_in_rsinbuf, decrease ret down to actual valid samples
580 double adj
=(srcpos
-m_samples_in_rsinbuf
+ outlatadj
) / drspos
;
583 ret
-= (int) (adj
+ 0.5);
588 int isrcpos
=(int)srcpos
;
589 m_fracpos
= srcpos
- isrcpos
;
590 m_samples_in_rsinbuf
-= isrcpos
;
591 if (m_samples_in_rsinbuf
<= 0) m_samples_in_rsinbuf
=0;
593 memcpy(localin
, localin
+ isrcpos
*nch
,m_samples_in_rsinbuf
*sizeof(WDL_ResampleSample
)*nch
);