You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

641 lines
16KB

  1. /*
  2. WDL - resample.cpp
  3. Copyright (C) 2010 and later Cockos Incorporated
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. You may also distribute this software under the LGPL v2 or later.
  18. */
  19. #include "resample.h"
  20. #include <math.h>
  21. #include "denormal.h"
  22. #ifndef PI
  23. #define PI 3.1415926535897932384626433832795
  24. #endif
  25. class WDL_Resampler::WDL_Resampler_IIRFilter
  26. {
  27. public:
  28. WDL_Resampler_IIRFilter()
  29. {
  30. m_fpos=-1;
  31. Reset();
  32. }
  33. ~WDL_Resampler_IIRFilter()
  34. {
  35. }
  36. void Reset()
  37. {
  38. memset(m_hist,0,sizeof(m_hist));
  39. }
  40. void setParms(double fpos, double Q)
  41. {
  42. if (fabs(fpos-m_fpos)<0.000001) return;
  43. m_fpos=fpos;
  44. double pos = fpos * PI;
  45. double cpos=cos(pos);
  46. double spos=sin(pos);
  47. double alpha=spos/(2.0*Q);
  48. double sc=1.0/( 1 + alpha);
  49. m_b1 = (1-cpos) * sc;
  50. m_b2 = m_b0 = m_b1*0.5;
  51. m_a1 = -2 * cpos * sc;
  52. m_a2 = (1-alpha)*sc;
  53. }
  54. void Apply(WDL_ResampleSample *in1, WDL_ResampleSample *out1, int ns, int span, int w)
  55. {
  56. double b0=m_b0,b1=m_b1,b2=m_b2,a1=m_a1,a2=m_a2;
  57. double *hist=m_hist[w];
  58. while (ns--)
  59. {
  60. double in=*in1;
  61. in1+=span;
  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);
  65. out1+=span;
  66. }
  67. }
  68. private:
  69. double m_fpos;
  70. double m_a1,m_a2;
  71. double m_b0,m_b1,m_b2;
  72. double m_hist[WDL_RESAMPLE_MAX_FILTERS*WDL_RESAMPLE_MAX_NCH][4];
  73. };
  74. void inline WDL_Resampler::SincSample(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, int nch, const WDL_SincFilterSample *filter, int filtsz)
  75. {
  76. const int oversize=m_lp_oversize;
  77. fracpos *= oversize;
  78. const int ifpos=(int)fracpos;
  79. filter += (oversize-ifpos) * filtsz;
  80. fracpos -= ifpos;
  81. int x;
  82. for (x = 0; x < nch; x ++)
  83. {
  84. double sum=0.0,sum2=0.0;
  85. const WDL_SincFilterSample *fptr2=filter;
  86. const WDL_SincFilterSample *fptr=fptr2 - filtsz;
  87. const WDL_ResampleSample *iptr=inptr+x;
  88. int i=filtsz/2;
  89. while (i--)
  90. {
  91. sum += fptr[0]*iptr[0];
  92. sum2 += fptr2[0]*iptr[0];
  93. sum += fptr[1]*iptr[nch];
  94. sum2 += fptr2[1]*iptr[nch];
  95. iptr+=nch*2;
  96. fptr+=2;
  97. fptr2+=2;
  98. }
  99. outptr[x]=sum*fracpos + sum2*(1.0-fracpos);
  100. }
  101. }
  102. void inline WDL_Resampler::SincSample1(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz)
  103. {
  104. const int oversize=m_lp_oversize;
  105. fracpos *= oversize;
  106. const int ifpos=(int)fracpos;
  107. fracpos -= ifpos;
  108. double sum=0.0,sum2=0.0;
  109. const WDL_SincFilterSample *fptr2=filter + (oversize-ifpos) * filtsz;
  110. const WDL_SincFilterSample *fptr=fptr2 - filtsz;
  111. const WDL_ResampleSample *iptr=inptr;
  112. int i=filtsz/2;
  113. while (i--)
  114. {
  115. sum += fptr[0]*iptr[0];
  116. sum2 += fptr2[0]*iptr[0];
  117. sum += fptr[1]*iptr[1];
  118. sum2 += fptr2[1]*iptr[1];
  119. iptr+=2;
  120. fptr+=2;
  121. fptr2+=2;
  122. }
  123. outptr[0]=sum*fracpos+sum2*(1.0-fracpos);
  124. }
  125. void inline WDL_Resampler::SincSample2(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz)
  126. {
  127. const int oversize=m_lp_oversize;
  128. fracpos *= oversize;
  129. const int ifpos=(int)fracpos;
  130. fracpos -= ifpos;
  131. const WDL_SincFilterSample *fptr2=filter + (oversize-ifpos) * filtsz;
  132. const WDL_SincFilterSample *fptr=fptr2 - filtsz;
  133. double sum=0.0;
  134. double sum2=0.0;
  135. double sumb=0.0;
  136. double sum2b=0.0;
  137. const WDL_ResampleSample *iptr=inptr;
  138. int i=filtsz/2;
  139. while (i--)
  140. {
  141. sum += fptr[0]*iptr[0];
  142. sum2 += fptr[0]*iptr[1];
  143. sumb += fptr2[0]*iptr[0];
  144. sum2b += fptr2[0]*iptr[1];
  145. sum += fptr[1]*iptr[2];
  146. sum2 += fptr[1]*iptr[3];
  147. sumb += fptr2[1]*iptr[2];
  148. sum2b += fptr2[1]*iptr[3];
  149. iptr+=4;
  150. fptr+=2;
  151. fptr2+=2;
  152. }
  153. outptr[0]=sum*fracpos + sumb*(1.0-fracpos);
  154. outptr[1]=sum2*fracpos + sum2b*(1.0-fracpos);
  155. }
  156. WDL_Resampler::WDL_Resampler(int initialinputbuffersize)
  157. {
  158. m_filterq=0.707f;
  159. m_filterpos=0.693f; // .792 ?
  160. m_sincoversize=0;
  161. m_lp_oversize=1;
  162. m_sincsize=0;
  163. m_filtercnt=1;
  164. m_interp=true;
  165. m_feedmode=false;
  166. m_filter_coeffs_size=0;
  167. m_sratein=44100.0;
  168. m_srateout=44100.0;
  169. m_ratio=1.0;
  170. m_filter_ratio=-1.0;
  171. m_iirfilter=0;
  172. if (initialinputbuffersize>0)
  173. m_rsinbuf.Resize(initialinputbuffersize);
  174. Reset();
  175. }
  176. WDL_Resampler::~WDL_Resampler()
  177. {
  178. delete m_iirfilter;
  179. }
  180. void WDL_Resampler::Reset(double fracpos)
  181. {
  182. m_last_requested=0;
  183. m_filtlatency=0;
  184. m_fracpos=fracpos;
  185. m_samples_in_rsinbuf=0;
  186. if (m_iirfilter) m_iirfilter->Reset();
  187. }
  188. void WDL_Resampler::SetMode(bool interp, int filtercnt, bool sinc, int sinc_size, int sinc_interpsize)
  189. {
  190. m_sincsize = sinc && sinc_size>= 4 ? sinc_size > 8192 ? 8192 : (sinc_size&~1) : 0;
  191. m_sincoversize = m_sincsize ? (sinc_interpsize<= 1 ? 1 : sinc_interpsize>=8192 ? 8192 : sinc_interpsize) : 1;
  192. m_filtercnt = m_sincsize ? 0 : (filtercnt<=0?0 : filtercnt >= WDL_RESAMPLE_MAX_FILTERS ? WDL_RESAMPLE_MAX_FILTERS : filtercnt);
  193. m_interp=interp && !m_sincsize;
  194. // char buf[512];
  195. // sprintf(buf,"setting interp=%d, filtercnt=%d, sinc=%d,%d\n",m_interp,m_filtercnt,m_sincsize,m_sincoversize);
  196. // OutputDebugString(buf);
  197. if (!m_sincsize)
  198. {
  199. m_filter_coeffs.Resize(0);
  200. m_filter_coeffs_size=0;
  201. }
  202. if (!m_filtercnt)
  203. {
  204. delete m_iirfilter;
  205. m_iirfilter=0;
  206. }
  207. }
  208. void WDL_Resampler::SetRates(double rate_in, double rate_out)
  209. {
  210. if (rate_in<1.0) rate_in=1.0;
  211. if (rate_out<1.0) rate_out=1.0;
  212. if (rate_in != m_sratein || rate_out != m_srateout)
  213. {
  214. m_sratein=rate_in;
  215. m_srateout=rate_out;
  216. m_ratio=m_sratein / m_srateout;
  217. }
  218. }
  219. void WDL_Resampler::BuildLowPass(double filtpos) // only called in sinc modes
  220. {
  221. const int wantsize=m_sincsize;
  222. const int wantinterp=m_sincoversize;
  223. if (m_filter_ratio!=filtpos ||
  224. m_filter_coeffs_size != wantsize ||
  225. m_lp_oversize != wantinterp)
  226. {
  227. m_lp_oversize = wantinterp;
  228. m_filter_ratio=filtpos;
  229. // build lowpass filter
  230. const int allocsize = wantsize*(m_lp_oversize+1);
  231. WDL_SincFilterSample *cfout=m_filter_coeffs.Resize(allocsize);
  232. if (m_filter_coeffs.GetSize()==allocsize)
  233. {
  234. m_filter_coeffs_size=wantsize;
  235. const double dwindowpos = 2.0 * PI/(double)wantsize;
  236. const double dsincpos = PI * filtpos; // filtpos is outrate/inrate, i.e. 0.5 is going to half rate
  237. const int hwantsize=wantsize/2;
  238. double filtpower=0.0;
  239. WDL_SincFilterSample *ptrout = cfout;
  240. int slice;
  241. for (slice=0;slice<=wantinterp;slice++)
  242. {
  243. const double frac = slice / (double)wantinterp;
  244. const int center_x = slice == 0 ? hwantsize : slice == wantinterp ? hwantsize-1 : -1;
  245. int x;
  246. for (x=0;x<wantsize;x++)
  247. {
  248. if (x==center_x)
  249. {
  250. // we know this will be 1.0
  251. *ptrout++ = 1.0;
  252. }
  253. else
  254. {
  255. const double xfrac = frac + x;
  256. const double windowpos = dwindowpos * xfrac;
  257. const double sincpos = dsincpos * (xfrac - hwantsize);
  258. // blackman-harris * sinc
  259. const double val = (0.35875 - 0.48829 * cos(windowpos) + 0.14128 * cos(2*windowpos) - 0.01168 * cos(3*windowpos)) * sin(sincpos) / sincpos;
  260. if (slice<wantinterp) filtpower+=val;
  261. *ptrout++ = (WDL_SincFilterSample)val;
  262. }
  263. }
  264. }
  265. filtpower = wantinterp/(filtpower+1.0);
  266. int x;
  267. for (x = 0; x < allocsize; x ++)
  268. {
  269. cfout[x] = (WDL_SincFilterSample) (cfout[x]*filtpower);
  270. }
  271. }
  272. else m_filter_coeffs_size=0;
  273. }
  274. }
  275. double WDL_Resampler::GetCurrentLatency()
  276. {
  277. double v=((double)m_samples_in_rsinbuf-m_filtlatency)/m_sratein;
  278. if (v<0.0)v=0.0;
  279. return v;
  280. }
  281. int WDL_Resampler::ResamplePrepare(int out_samples, int nch, WDL_ResampleSample **inbuffer)
  282. {
  283. if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) return 0;
  284. int fsize=0;
  285. if (m_sincsize>1) fsize = m_sincsize;
  286. int hfs=fsize/2;
  287. if (hfs>1 && m_samples_in_rsinbuf<hfs-1)
  288. {
  289. m_filtlatency+=hfs-1 - m_samples_in_rsinbuf;
  290. m_samples_in_rsinbuf=hfs-1;
  291. if (m_samples_in_rsinbuf>0)
  292. {
  293. WDL_ResampleSample *p = m_rsinbuf.Resize(m_samples_in_rsinbuf*nch,false);
  294. memset(p,0,sizeof(WDL_ResampleSample)*m_rsinbuf.GetSize());
  295. }
  296. }
  297. int sreq = 0;
  298. if (!m_feedmode) sreq = (int)(m_ratio * out_samples) + 4 + fsize - m_samples_in_rsinbuf;
  299. else sreq = out_samples;
  300. if (sreq<0)sreq=0;
  301. again:
  302. m_rsinbuf.Resize((m_samples_in_rsinbuf+sreq)*nch,false);
  303. int sz = m_rsinbuf.GetSize()/(nch?nch:1) - m_samples_in_rsinbuf;
  304. if (sz!=sreq)
  305. {
  306. if (sreq>4 && !sz)
  307. {
  308. sreq/=2;
  309. goto again; // try again with half the size
  310. }
  311. // todo: notify of error?
  312. sreq=sz;
  313. }
  314. *inbuffer = m_rsinbuf.Get() + m_samples_in_rsinbuf*nch;
  315. m_last_requested=sreq;
  316. return sreq;
  317. }
  318. int WDL_Resampler::ResampleOut(WDL_ResampleSample *out, int nsamples_in, int nsamples_out, int nch)
  319. {
  320. if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) return 0;
  321. if (m_filtercnt>0)
  322. {
  323. if (m_ratio > 1.0 && nsamples_in > 0) // filter input
  324. {
  325. if (!m_iirfilter) m_iirfilter = new WDL_Resampler_IIRFilter;
  326. int n=m_filtercnt;
  327. m_iirfilter->setParms((1.0/m_ratio)*m_filterpos,m_filterq);
  328. WDL_ResampleSample *buf=(WDL_ResampleSample *)m_rsinbuf.Get() + m_samples_in_rsinbuf*nch;
  329. int a,x;
  330. int offs=0;
  331. for (x=0; x < nch; x ++)
  332. for (a = 0; a < n; a ++)
  333. m_iirfilter->Apply(buf+x,buf+x,nsamples_in,nch,offs++);
  334. }
  335. }
  336. // prevent the caller from corrupting the internal state
  337. m_samples_in_rsinbuf += nsamples_in < m_last_requested ? nsamples_in : m_last_requested;
  338. int rsinbuf_availtemp = m_samples_in_rsinbuf;
  339. if (nsamples_in < m_last_requested) // flush out to ensure we can deliver
  340. {
  341. int fsize=(m_last_requested-nsamples_in)*2 + m_sincsize*2;
  342. int alloc_size=(m_samples_in_rsinbuf+fsize)*nch;
  343. WDL_ResampleSample *zb=m_rsinbuf.Resize(alloc_size,false);
  344. if (m_rsinbuf.GetSize()==alloc_size)
  345. {
  346. memset(zb+m_samples_in_rsinbuf*nch,0,fsize*nch*sizeof(WDL_ResampleSample));
  347. rsinbuf_availtemp = m_samples_in_rsinbuf+fsize;
  348. }
  349. }
  350. int ret=0;
  351. double srcpos=m_fracpos;
  352. double drspos = m_ratio;
  353. WDL_ResampleSample *localin = m_rsinbuf.Get();
  354. WDL_ResampleSample *outptr=out;
  355. int ns=nsamples_out;
  356. int outlatadj=0;
  357. if (m_sincsize) // sinc interpolating
  358. {
  359. if (m_ratio > 1.0) BuildLowPass(1.0 / (m_ratio*1.03));
  360. else BuildLowPass(1.0);
  361. int filtsz=m_filter_coeffs_size;
  362. int filtlen = rsinbuf_availtemp - filtsz;
  363. outlatadj=filtsz/2-1;
  364. WDL_SincFilterSample *filter=m_filter_coeffs.Get();
  365. if (nch == 1)
  366. {
  367. while (ns--)
  368. {
  369. int ipos = (int)srcpos;
  370. if (ipos >= filtlen-1) break; // quit decoding, not enough input samples
  371. SincSample1(outptr,localin + ipos,srcpos-ipos,filter,filtsz);
  372. outptr ++;
  373. srcpos+=drspos;
  374. ret++;
  375. }
  376. }
  377. else if (nch==2)
  378. {
  379. while (ns--)
  380. {
  381. int ipos = (int)srcpos;
  382. if (ipos >= filtlen-1) break; // quit decoding, not enough input samples
  383. SincSample2(outptr,localin + ipos*2,srcpos-ipos,filter,filtsz);
  384. outptr+=2;
  385. srcpos+=drspos;
  386. ret++;
  387. }
  388. }
  389. else
  390. {
  391. while (ns--)
  392. {
  393. int ipos = (int)srcpos;
  394. if (ipos >= filtlen-1) break; // quit decoding, not enough input samples
  395. SincSample(outptr,localin + ipos*nch,srcpos-ipos,nch,filter,filtsz);
  396. outptr += nch;
  397. srcpos+=drspos;
  398. ret++;
  399. }
  400. }
  401. }
  402. else if (!m_interp) // point sampling
  403. {
  404. if (nch == 1)
  405. {
  406. while (ns--)
  407. {
  408. int ipos = (int)srcpos;
  409. if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples
  410. *outptr++ = localin[ipos];
  411. srcpos+=drspos;
  412. ret++;
  413. }
  414. }
  415. else if (nch == 2)
  416. {
  417. while (ns--)
  418. {
  419. int ipos = (int)srcpos;
  420. if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples
  421. ipos+=ipos;
  422. outptr[0] = localin[ipos];
  423. outptr[1] = localin[ipos+1];
  424. outptr+=2;
  425. srcpos+=drspos;
  426. ret++;
  427. }
  428. }
  429. else
  430. while (ns--)
  431. {
  432. int ipos = (int)srcpos;
  433. if (ipos >= rsinbuf_availtemp) break; // quit decoding, not enough input samples
  434. memcpy(outptr,localin + ipos*nch,nch*sizeof(WDL_ResampleSample));
  435. outptr += nch;
  436. srcpos+=drspos;
  437. ret++;
  438. }
  439. }
  440. else // linear interpolation
  441. {
  442. if (nch == 1)
  443. {
  444. while (ns--)
  445. {
  446. int ipos = (int)srcpos;
  447. double fracpos=srcpos-ipos;
  448. if (ipos >= rsinbuf_availtemp-1)
  449. {
  450. break; // quit decoding, not enough input samples
  451. }
  452. double ifracpos=1.0-fracpos;
  453. WDL_ResampleSample *inptr = localin + ipos;
  454. *outptr++ = inptr[0]*(ifracpos) + inptr[1]*(fracpos);
  455. srcpos+=drspos;
  456. ret++;
  457. }
  458. }
  459. else if (nch == 2)
  460. {
  461. while (ns--)
  462. {
  463. int ipos = (int)srcpos;
  464. double fracpos=srcpos-ipos;
  465. if (ipos >= rsinbuf_availtemp-1)
  466. {
  467. break; // quit decoding, not enough input samples
  468. }
  469. double ifracpos=1.0-fracpos;
  470. WDL_ResampleSample *inptr = localin + ipos*2;
  471. outptr[0] = inptr[0]*(ifracpos) + inptr[2]*(fracpos);
  472. outptr[1] = inptr[1]*(ifracpos) + inptr[3]*(fracpos);
  473. outptr += 2;
  474. srcpos+=drspos;
  475. ret++;
  476. }
  477. }
  478. else
  479. {
  480. while (ns--)
  481. {
  482. int ipos = (int)srcpos;
  483. double fracpos=srcpos-ipos;
  484. if (ipos >= rsinbuf_availtemp-1)
  485. {
  486. break; // quit decoding, not enough input samples
  487. }
  488. double ifracpos=1.0-fracpos;
  489. int ch=nch;
  490. WDL_ResampleSample *inptr = localin + ipos*nch;
  491. while (ch--)
  492. {
  493. *outptr++ = inptr[0]*(ifracpos) + inptr[nch]*(fracpos);
  494. inptr++;
  495. }
  496. srcpos+=drspos;
  497. ret++;
  498. }
  499. }
  500. }
  501. if (m_filtercnt>0)
  502. {
  503. if (m_ratio < 1.0 && ret>0) // filter output
  504. {
  505. if (!m_iirfilter) m_iirfilter = new WDL_Resampler_IIRFilter;
  506. int n=m_filtercnt;
  507. m_iirfilter->setParms(m_ratio*m_filterpos,m_filterq);
  508. int x,a;
  509. int offs=0;
  510. for (x=0; x < nch; x ++)
  511. for (a = 0; a < n; a ++)
  512. m_iirfilter->Apply(out+x,out+x,ret,nch,offs++);
  513. }
  514. }
  515. if (ret>0 && rsinbuf_availtemp>m_samples_in_rsinbuf) // we had to pad!!
  516. {
  517. // check for the case where rsinbuf_availtemp>m_samples_in_rsinbuf, decrease ret down to actual valid samples
  518. double adj=(srcpos-m_samples_in_rsinbuf + outlatadj) / drspos;
  519. if (adj>0)
  520. {
  521. ret -= (int) (adj + 0.5);
  522. if (ret<0)ret=0;
  523. }
  524. }
  525. int isrcpos=(int)srcpos;
  526. if (isrcpos > m_samples_in_rsinbuf) isrcpos=m_samples_in_rsinbuf;
  527. m_fracpos = srcpos - isrcpos;
  528. m_samples_in_rsinbuf -= isrcpos;
  529. if (m_samples_in_rsinbuf <= 0) m_samples_in_rsinbuf=0;
  530. else
  531. memmove(localin, localin + isrcpos*nch,m_samples_in_rsinbuf*sizeof(WDL_ResampleSample)*nch);
  532. return ret;
  533. }