resamplesubs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /* $Id$ */
  2. /*
  3. * Digital Audio Resampling Home Page located at
  4. * http://www-ccrma.stanford.edu/~jos/resample/.
  5. *
  6. * SOFTWARE FOR SAMPLING-RATE CONVERSION AND FIR DIGITAL FILTER DESIGN
  7. *
  8. * Snippet from the resample.1 man page:
  9. *
  10. * HISTORY
  11. *
  12. * The first version of this software was written by Julius O. Smith III
  13. * <jos@ccrma.stanford.edu> at CCRMA <http://www-ccrma.stanford.edu> in
  14. * 1981. It was called SRCONV and was written in SAIL for PDP-10
  15. * compatible machines. The algorithm was first published in
  16. *
  17. * Smith, Julius O. and Phil Gossett. ``A Flexible Sampling-Rate
  18. * Conversion Method,'' Proceedings (2): 19.4.1-19.4.4, IEEE Conference
  19. * on Acoustics, Speech, and Signal Processing, San Diego, March 1984.
  20. *
  21. * An expanded tutorial based on this paper is available at the Digital
  22. * Audio Resampling Home Page given above.
  23. *
  24. * Circa 1988, the SRCONV program was translated from SAIL to C by
  25. * Christopher Lee Fraley working with Roger Dannenberg at CMU.
  26. *
  27. * Since then, the C version has been maintained by jos.
  28. *
  29. * Sndlib support was added 6/99 by John Gibson <jgg9c@virginia.edu>.
  30. *
  31. * The resample program is free software distributed in accordance
  32. * with the Lesser GNU Public License (LGPL). There is NO warranty; not
  33. * even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  34. */
  35. /* PJMEDIA modification:
  36. * - remove resample(), just use SrcUp, SrcUD, and SrcLinear directly.
  37. * - move FilterUp() and FilterUD() from filterkit.c
  38. * - move stddefs.h and resample.h to this file.
  39. * - const correctness.
  40. */
  41. #include <resamplesubs.h>
  42. #include "config.h"
  43. #include "stddefs.h"
  44. #include "resample.h"
  45. #ifdef _MSC_VER
  46. # pragma warning(push, 3)
  47. //# pragma warning(disable: 4245) // Conversion from uint to ushort
  48. # pragma warning(disable: 4244) // Conversion from double to uint
  49. # pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
  50. # pragma warning(disable: 4761) // integral size mismatch in argument; conversion supplied
  51. #endif
  52. #if defined(RESAMPLE_HAS_SMALL_FILTER) && RESAMPLE_HAS_SMALL_FILTER!=0
  53. # include "smallfilter.h"
  54. #else
  55. # define SMALL_FILTER_NMULT 0
  56. # define SMALL_FILTER_SCALE 0
  57. # define SMALL_FILTER_NWING 0
  58. # define SMALL_FILTER_IMP NULL
  59. # define SMALL_FILTER_IMPD NULL
  60. #endif
  61. #if defined(RESAMPLE_HAS_LARGE_FILTER) && RESAMPLE_HAS_LARGE_FILTER!=0
  62. # include "largefilter.h"
  63. #else
  64. # define LARGE_FILTER_NMULT 0
  65. # define LARGE_FILTER_SCALE 0
  66. # define LARGE_FILTER_NWING 0
  67. # define LARGE_FILTER_IMP NULL
  68. # define LARGE_FILTER_IMPD NULL
  69. #endif
  70. #undef INLINE
  71. #define INLINE
  72. #define HAVE_FILTER 0
  73. #ifndef NULL
  74. # define NULL 0
  75. #endif
  76. static INLINE RES_HWORD WordToHword(RES_WORD v, int scl)
  77. {
  78. RES_HWORD out;
  79. RES_WORD llsb = (1<<(scl-1));
  80. v += llsb; /* round */
  81. v >>= scl;
  82. if (v>MAX_HWORD) {
  83. v = MAX_HWORD;
  84. } else if (v < MIN_HWORD) {
  85. v = MIN_HWORD;
  86. }
  87. out = (RES_HWORD) v;
  88. return out;
  89. }
  90. /* Sampling rate conversion using linear interpolation for maximum speed.
  91. */
  92. static int
  93. SrcLinear(const RES_HWORD X[], RES_HWORD Y[], double pFactor, RES_UHWORD nx)
  94. {
  95. RES_HWORD iconst;
  96. RES_UWORD time = 0;
  97. const RES_HWORD *xp;
  98. RES_HWORD *Ystart, *Yend;
  99. RES_WORD v,x1,x2;
  100. double dt; /* Step through input signal */
  101. RES_UWORD dtb; /* Fixed-point version of Dt */
  102. //RES_UWORD endTime; /* When time reaches EndTime, return to user */
  103. dt = 1.0/pFactor; /* Output sampling period */
  104. dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
  105. Ystart = Y;
  106. Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
  107. //endTime = time + (1<<Np)*(RES_WORD)nx;
  108. // Integer round down in dtb calculation may cause (endTime % dtb > 0),
  109. // so it may cause resample write pass the output buffer (Y >= Yend).
  110. // while (time < endTime)
  111. while (Y < Yend)
  112. {
  113. iconst = (time) & Pmask;
  114. xp = &X[(time)>>Np]; /* Ptr to current input sample */
  115. x1 = *xp++;
  116. x2 = *xp;
  117. x1 *= ((1<<Np)-iconst);
  118. x2 *= iconst;
  119. v = x1 + x2;
  120. *Y++ = WordToHword(v,Np); /* Deposit output */
  121. time += dtb; /* Move to next sample by time increment */
  122. }
  123. return (Y - Ystart); /* Return number of output samples */
  124. }
  125. static RES_WORD FilterUp(const RES_HWORD Imp[], const RES_HWORD ImpD[],
  126. RES_UHWORD Nwing, RES_BOOL Interp,
  127. const RES_HWORD *Xp, RES_HWORD Ph, RES_HWORD Inc)
  128. {
  129. const RES_HWORD *Hp;
  130. const RES_HWORD *Hdp = NULL;
  131. const RES_HWORD *End;
  132. RES_HWORD a = 0;
  133. RES_WORD v, t;
  134. v=0;
  135. Hp = &Imp[Ph>>Na];
  136. End = &Imp[Nwing];
  137. if (Interp) {
  138. Hdp = &ImpD[Ph>>Na];
  139. a = Ph & Amask;
  140. }
  141. if (Inc == 1) /* If doing right wing... */
  142. { /* ...drop extra coeff, so when Ph is */
  143. End--; /* 0.5, we don't do too many mult's */
  144. if (Ph == 0) /* If the phase is zero... */
  145. { /* ...then we've already skipped the */
  146. Hp += Npc; /* first sample, so we must also */
  147. Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
  148. }
  149. }
  150. if (Interp)
  151. while (Hp < End) {
  152. t = *Hp; /* Get filter coeff */
  153. t += (((RES_WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
  154. Hdp += Npc; /* Filter coeff differences step */
  155. t *= *Xp; /* Mult coeff by input sample */
  156. if (t & (1<<(Nhxn-1))) /* Round, if needed */
  157. t += (1<<(Nhxn-1));
  158. t >>= Nhxn; /* Leave some guard bits, but come back some */
  159. v += t; /* The filter output */
  160. Hp += Npc; /* Filter coeff step */
  161. Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
  162. }
  163. else
  164. while (Hp < End) {
  165. t = *Hp; /* Get filter coeff */
  166. t *= *Xp; /* Mult coeff by input sample */
  167. if (t & (1<<(Nhxn-1))) /* Round, if needed */
  168. t += (1<<(Nhxn-1));
  169. t >>= Nhxn; /* Leave some guard bits, but come back some */
  170. v += t; /* The filter output */
  171. Hp += Npc; /* Filter coeff step */
  172. Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
  173. }
  174. return(v);
  175. }
  176. static RES_WORD FilterUD(const RES_HWORD Imp[], const RES_HWORD ImpD[],
  177. RES_UHWORD Nwing, RES_BOOL Interp,
  178. const RES_HWORD *Xp, RES_HWORD Ph, RES_HWORD Inc, RES_UHWORD dhb)
  179. {
  180. RES_HWORD a;
  181. const RES_HWORD *Hp, *Hdp, *End;
  182. RES_WORD v, t;
  183. RES_UWORD Ho;
  184. v=0;
  185. Ho = (Ph*(RES_UWORD)dhb)>>Np;
  186. End = &Imp[Nwing];
  187. if (Inc == 1) /* If doing right wing... */
  188. { /* ...drop extra coeff, so when Ph is */
  189. End--; /* 0.5, we don't do too many mult's */
  190. if (Ph == 0) /* If the phase is zero... */
  191. Ho += dhb; /* ...then we've already skipped the */
  192. } /* first sample, so we must also */
  193. /* skip ahead in Imp[] and ImpD[] */
  194. if (Interp)
  195. while ((Hp = &Imp[Ho>>Na]) < End) {
  196. t = *Hp; /* Get IR sample */
  197. Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table*/
  198. a = Ho & Amask; /* a is logically between 0 and 1 */
  199. t += (((RES_WORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
  200. t *= *Xp; /* Mult coeff by input sample */
  201. if (t & 1<<(Nhxn-1)) /* Round, if needed */
  202. t += 1<<(Nhxn-1);
  203. t >>= Nhxn; /* Leave some guard bits, but come back some */
  204. v += t; /* The filter output */
  205. Ho += dhb; /* IR step */
  206. Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
  207. }
  208. else
  209. while ((Hp = &Imp[Ho>>Na]) < End) {
  210. t = *Hp; /* Get IR sample */
  211. t *= *Xp; /* Mult coeff by input sample */
  212. if (t & 1<<(Nhxn-1)) /* Round, if needed */
  213. t += 1<<(Nhxn-1);
  214. t >>= Nhxn; /* Leave some guard bits, but come back some */
  215. v += t; /* The filter output */
  216. Ho += dhb; /* IR step */
  217. Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
  218. }
  219. return(v);
  220. }
  221. /* Sampling rate up-conversion only subroutine;
  222. * Slightly faster than down-conversion;
  223. */
  224. static int SrcUp(const RES_HWORD X[], RES_HWORD Y[], double pFactor,
  225. RES_UHWORD nx, RES_UHWORD pNwing, RES_UHWORD pLpScl,
  226. const RES_HWORD pImp[], const RES_HWORD pImpD[], RES_BOOL Interp)
  227. {
  228. const RES_HWORD *xp;
  229. RES_HWORD *Ystart, *Yend;
  230. RES_WORD v;
  231. double dt; /* Step through input signal */
  232. RES_UWORD dtb; /* Fixed-point version of Dt */
  233. RES_UWORD time = 0;
  234. //RES_UWORD endTime; /* When time reaches EndTime, return to user */
  235. dt = 1.0/pFactor; /* Output sampling period */
  236. dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
  237. Ystart = Y;
  238. Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
  239. //endTime = time + (1<<Np)*(RES_WORD)nx;
  240. // Integer round down in dtb calculation may cause (endTime % dtb > 0),
  241. // so it may cause resample write pass the output buffer (Y >= Yend).
  242. // while (time < endTime)
  243. while (Y < Yend)
  244. {
  245. xp = &X[time>>Np]; /* Ptr to current input sample */
  246. /* Perform left-wing inner product */
  247. v = 0;
  248. v = FilterUp(pImp, pImpD, pNwing, Interp, xp, (RES_HWORD)(time&Pmask),-1);
  249. /* Perform right-wing inner product */
  250. v += FilterUp(pImp, pImpD, pNwing, Interp, xp+1, (RES_HWORD)((-time)&Pmask),1);
  251. v >>= Nhg; /* Make guard bits */
  252. v *= pLpScl; /* Normalize for unity filter gain */
  253. *Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */
  254. time += dtb; /* Move to next sample by time increment */
  255. }
  256. return (Y - Ystart); /* Return the number of output samples */
  257. }
  258. /* Sampling rate conversion subroutine */
  259. static int SrcUD(const RES_HWORD X[], RES_HWORD Y[], double pFactor,
  260. RES_UHWORD nx, RES_UHWORD pNwing, RES_UHWORD pLpScl,
  261. const RES_HWORD pImp[], const RES_HWORD pImpD[], RES_BOOL Interp)
  262. {
  263. const RES_HWORD *xp;
  264. RES_HWORD *Ystart, *Yend;
  265. RES_WORD v;
  266. double dh; /* Step through filter impulse response */
  267. double dt; /* Step through input signal */
  268. RES_UWORD time = 0;
  269. //RES_UWORD endTime; /* When time reaches EndTime, return to user */
  270. RES_UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */
  271. dt = 1.0/pFactor; /* Output sampling period */
  272. dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */
  273. dh = MIN(Npc, pFactor*Npc); /* Filter sampling period */
  274. dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */
  275. Ystart = Y;
  276. Yend = Ystart + (unsigned)(nx * pFactor + 0.5);
  277. //endTime = time + (1<<Np)*(RES_WORD)nx;
  278. // Integer round down in dtb calculation may cause (endTime % dtb > 0),
  279. // so it may cause resample write pass the output buffer (Y >= Yend).
  280. // while (time < endTime)
  281. while (Y < Yend)
  282. {
  283. xp = &X[time>>Np]; /* Ptr to current input sample */
  284. v = FilterUD(pImp, pImpD, pNwing, Interp, xp, (RES_HWORD)(time&Pmask),
  285. -1, dhb); /* Perform left-wing inner product */
  286. v += FilterUD(pImp, pImpD, pNwing, Interp, xp+1, (RES_HWORD)((-time)&Pmask),
  287. 1, dhb); /* Perform right-wing inner product */
  288. v >>= Nhg; /* Make guard bits */
  289. v *= pLpScl; /* Normalize for unity filter gain */
  290. *Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */
  291. time += dtb; /* Move to next sample by time increment */
  292. }
  293. return (Y - Ystart); /* Return the number of output samples */
  294. }
  295. DECL(int) res_SrcLinear(const RES_HWORD X[], RES_HWORD Y[],
  296. double pFactor, RES_UHWORD nx)
  297. {
  298. return SrcLinear(X, Y, pFactor, nx);
  299. }
  300. DECL(int) res_Resample(const RES_HWORD X[], RES_HWORD Y[], double pFactor,
  301. RES_UHWORD nx, RES_BOOL LargeF, RES_BOOL Interp)
  302. {
  303. if (pFactor >= 1) {
  304. if (LargeF)
  305. return SrcUp(X, Y, pFactor, nx,
  306. LARGE_FILTER_NWING, LARGE_FILTER_SCALE,
  307. LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp);
  308. else
  309. return SrcUp(X, Y, pFactor, nx,
  310. SMALL_FILTER_NWING, SMALL_FILTER_SCALE,
  311. SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp);
  312. } else {
  313. if (LargeF)
  314. return SrcUD(X, Y, pFactor, nx,
  315. LARGE_FILTER_NWING, LARGE_FILTER_SCALE * pFactor + 0.5,
  316. LARGE_FILTER_IMP, LARGE_FILTER_IMPD, Interp);
  317. else
  318. return SrcUD(X, Y, pFactor, nx,
  319. SMALL_FILTER_NWING, SMALL_FILTER_SCALE * pFactor + 0.5,
  320. SMALL_FILTER_IMP, SMALL_FILTER_IMPD, Interp);
  321. }
  322. }
  323. DECL(int) res_GetXOFF(double pFactor, RES_BOOL LargeF)
  324. {
  325. if (LargeF)
  326. return (LARGE_FILTER_NMULT + 1) / 2.0 *
  327. MAX(1.0, 1.0/pFactor);
  328. else
  329. return (SMALL_FILTER_NMULT + 1) / 2.0 *
  330. MAX(1.0, 1.0/pFactor);
  331. }