Audio.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:8k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. // originally from virtualdub
  22. #include "stdafx.h"
  23. #include "Audio.h"
  24. static long audio_pointsample_8(void *dst, void *src, long accum, long samp_frac, long cnt) {
  25. unsigned char *d = (unsigned char *)dst;
  26. unsigned char *s = (unsigned char *)src;
  27. do {
  28. *d++ = s[accum>>19];
  29. accum += samp_frac;
  30. } while(--cnt);
  31. return accum;
  32. }
  33. static long audio_pointsample_16(void *dst, void *src, long accum, long samp_frac, long cnt) {
  34. unsigned short *d = (unsigned short *)dst;
  35. unsigned short *s = (unsigned short *)src;
  36. do {
  37. *d++ = s[accum>>19];
  38. accum += samp_frac;
  39. } while(--cnt);
  40. return accum;
  41. }
  42. static long audio_pointsample_32(void *dst, void *src, long accum, long samp_frac, long cnt) {
  43. unsigned long *d = (unsigned long *)dst;
  44. unsigned long *s = (unsigned long *)src;
  45. do {
  46. *d++ = s[accum>>19];
  47. accum += samp_frac;
  48. } while(--cnt);
  49. return accum;
  50. }
  51. static long audio_downsample_mono8(void *dst, void *src, long *filter_bank, int filter_width, long accum, long samp_frac, long cnt) {
  52. unsigned char *d = (unsigned char *)dst;
  53. unsigned char *s = (unsigned char *)src;
  54. do {
  55. long sum = 0;
  56. int w;
  57. long *fb_ptr;
  58. unsigned char *s_ptr;
  59. w = filter_width;
  60. fb_ptr = filter_bank + filter_width * ((accum>>11)&0xff);
  61. s_ptr = s + (accum>>19);
  62. do {
  63. sum += *fb_ptr++ * (int)*s_ptr++;
  64. } while(--w);
  65. if (sum < 0)
  66. *d++ = 0;
  67. else if (sum > 0x3fffff)
  68. *d++ = 0xff;
  69. else
  70. *d++ = ((sum + 0x2000)>>14);
  71. accum += samp_frac;
  72. } while(--cnt);
  73. return accum;
  74. }
  75. static long audio_downsample_mono16(void *dst, void *src, long *filter_bank, int filter_width, long accum, long samp_frac, long cnt) {
  76. signed short *d = (signed short *)dst;
  77. signed short *s = (signed short *)src;
  78. do {
  79. long sum = 0;
  80. int w;
  81. long *fb_ptr;
  82. signed short *s_ptr;
  83. w = filter_width;
  84. fb_ptr = filter_bank + filter_width * ((accum>>11)&0xff);
  85. s_ptr = s + (accum>>19);
  86. do {
  87. sum += *fb_ptr++ * (int)*s_ptr++;
  88. } while(--w);
  89. if (sum < -0x20000000)
  90. *d++ = -0x8000;
  91. else if (sum > 0x1fffffff)
  92. *d++ = 0x7fff;
  93. else
  94. *d++ = ((sum + 0x2000)>>14);
  95. accum += samp_frac;
  96. } while(--cnt);
  97. return accum;
  98. }
  99. static int permute_index(int a, int b) {
  100. return (b-(a>>8)-1) + (a&255)*b;
  101. }
  102. static void make_downsample_filter(long *filter_bank, int filter_width, long samp_frac) {
  103. int i, j, v;
  104. double filt_max;
  105. double filtwidth_frac;
  106. filtwidth_frac = samp_frac/2048.0;
  107. filter_bank[filter_width-1] = 0;
  108. filt_max = (16384.0 * 524288.0) / samp_frac;
  109. for(i=0; i<128*filter_width; i++) {
  110. int y = 0;
  111. double d = i / filtwidth_frac;
  112. if (d<1.0)
  113. y = (int)(0.5 + filt_max*(1.0 - d));
  114. filter_bank[permute_index(128*filter_width + i, filter_width)]
  115. = filter_bank[permute_index(128*filter_width - i, filter_width)]
  116. = y;
  117. }
  118. // Normalize the filter to correct for integer roundoff errors
  119. for(i=0; i<256*filter_width; i+=filter_width) {
  120. v=0;
  121. for(j=0; j<filter_width; j++)
  122. v += filter_bank[i+j];
  123. // _RPT2(0,"error[%02x] = %04xn", i/filter_width, 0x4000 - v);
  124. v = (0x4000 - v)/filter_width;
  125. for(j=0; j<filter_width; j++)
  126. filter_bank[i+j] += v;
  127. }
  128. // _CrtCheckMemory();
  129. }
  130. AudioStreamResampler::AudioStreamResampler(int bps, long org_rate, long new_rate, bool fHighQuality)
  131. {
  132. samp_frac = 0x80000;
  133. this->bps = bps;
  134. if(bps == 1)
  135. {
  136. ptsampleRout = audio_pointsample_8;
  137. dnsampleRout = audio_downsample_mono8;
  138. }
  139. else if(bps >= 2)
  140. {
  141. ptsampleRout = audio_pointsample_16;
  142. dnsampleRout = audio_downsample_mono16;
  143. }
  144. else
  145. {
  146. return;
  147. }
  148. // org_rate > new_rate!
  149. samp_frac = MulDiv(org_rate, 0x80000, new_rate);
  150. holdover = 0;
  151. filter_bank = NULL;
  152. filter_width = 1;
  153. accum = 0;
  154. // If this is a high-quality downsample, allocate memory for the filter bank
  155. if(fHighQuality)
  156. {
  157. if(samp_frac>0x80000)
  158. {
  159. // HQ downsample: allocate filter bank
  160. filter_width = ((samp_frac + 0x7ffff)>>19)<<1 <<1;
  161. if(!(filter_bank = new long[filter_width * 256]))
  162. {
  163. filter_width = 1;
  164. return;
  165. }
  166. make_downsample_filter(filter_bank, filter_width, samp_frac);
  167. // Clear lower samples
  168. memset(cbuffer, bps >= 2 ? 0 : 0x80, bps*filter_width);
  169. holdover = filter_width/2;
  170. }
  171. }
  172. }
  173. AudioStreamResampler::~AudioStreamResampler()
  174. {
  175. delete [] filter_bank;
  176. }
  177. long AudioStreamResampler::Downsample(void* input, long samplesin, void* output, long samplesout)
  178. {
  179. long lActualSamples = 0;
  180. // Downsampling is even worse because we have overlap to the left and to the
  181. // right of the interpolated point.
  182. //
  183. // We need (n/2) points to the left and (n/2-1) points to the right.
  184. while(samplesin > 0 && samplesout > 0)
  185. {
  186. long srcSamples, dstSamples;
  187. int nhold;
  188. // Figure out how many source samples we need.
  189. //
  190. // To do this, compute the highest fixed-point accumulator we'll reach.
  191. // Truncate that, and add the filter width.  Then subtract however many
  192. // samples are sitting at the bottom of the buffer.
  193. srcSamples = (long)(((__int64)samp_frac*(samplesout-1) + accum) >> 19) + filter_width - holdover;
  194. // Don't exceed the buffer (BUFFER_SIZE - holdover).
  195. if(srcSamples > BUFFER_SIZE - holdover)
  196. srcSamples = BUFFER_SIZE - holdover;
  197. // Read into buffer.
  198. srcSamples = min(srcSamples, samplesin);
  199. if(!srcSamples) break;
  200. memcpy((char*)cbuffer + holdover*bps, (char*)input, srcSamples*bps);
  201. input = (void *)((char *)input + srcSamples*bps);
  202. // Figure out how many destination samples we'll get out of what we
  203. // read.  We'll have (srcSamples+holdover) bytes, so the maximum
  204. // fixed-pt accumulator we can hit is
  205. // (srcSamples+holdover-filter_width)<<16 + 0xffff.
  206. dstSamples = (((__int64)(srcSamples+holdover-filter_width)<<19) + 0x7ffff - accum) / samp_frac + 1;
  207. if(dstSamples > samplesout)
  208. dstSamples = samplesout;
  209. if(dstSamples >= 1)
  210. {
  211. if(filter_bank)
  212. accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples);
  213. else
  214. accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples);
  215. output = (void *)((char *)output + bps * dstSamples);
  216. lActualSamples += dstSamples;
  217. samplesout -= dstSamples;
  218. }
  219. // We're "shifting" the new samples down to the bottom by discarding
  220. // all the samples in the buffer, so adjust the fixed-pt accum
  221. // accordingly.
  222. accum -= ((srcSamples+holdover)<<19);
  223. // Oops, did we need some of those?
  224. //
  225. // If accum=0, we need (n/2) samples back.  accum>=0x10000 is fewer,
  226. // accum<0 is more.
  227. nhold = - (accum>>19);
  228. // _ASSERT(nhold<=(filter_width/2));
  229. if (nhold>0) {
  230. memmove(cbuffer, (char *)cbuffer+bps*(srcSamples+holdover-nhold), bps*nhold);
  231. holdover = nhold;
  232. accum += nhold<<19;
  233. } else
  234. holdover = 0;
  235. // _ASSERT(accum>=0);
  236. }
  237. int Bytes = lActualSamples * bps;
  238. return lActualSamples;
  239. }