Audio.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 // originally from virtualdub
00023 
00024 #include "stdafx.h"
00025 #include "Audio.h"
00026 
00027 static long audio_pointsample_8(void *dst, void *src, long accum, long samp_frac, long cnt) {
00028         unsigned char *d = (unsigned char *)dst;
00029         unsigned char *s = (unsigned char *)src;
00030 
00031         do {
00032                 *d++ = s[accum>>19];
00033                 accum += samp_frac;
00034         } while(--cnt);
00035 
00036         return accum;
00037 }
00038 
00039 static long audio_pointsample_16(void *dst, void *src, long accum, long samp_frac, long cnt) {
00040         unsigned short *d = (unsigned short *)dst;
00041         unsigned short *s = (unsigned short *)src;
00042 
00043         do {
00044                 *d++ = s[accum>>19];
00045                 accum += samp_frac;
00046         } while(--cnt);
00047 
00048         return accum;
00049 }
00050 
00051 static long audio_pointsample_32(void *dst, void *src, long accum, long samp_frac, long cnt) {
00052         unsigned long *d = (unsigned long *)dst;
00053         unsigned long *s = (unsigned long *)src;
00054 
00055         do {
00056                 *d++ = s[accum>>19];
00057                 accum += samp_frac;
00058         } while(--cnt);
00059 
00060         return accum;
00061 }
00062 
00063 static long audio_downsample_mono8(void *dst, void *src, long *filter_bank, int filter_width, long accum, long samp_frac, long cnt) {
00064         unsigned char *d = (unsigned char *)dst;
00065         unsigned char *s = (unsigned char *)src;
00066 
00067         do {
00068                 long sum = 0;
00069                 int w;
00070                 long *fb_ptr;
00071                 unsigned char *s_ptr;
00072 
00073                 w = filter_width;
00074                 fb_ptr = filter_bank + filter_width * ((accum>>11)&0xff);
00075                 s_ptr = s + (accum>>19);
00076                 do {
00077                         sum += *fb_ptr++ * (int)*s_ptr++;
00078                 } while(--w);
00079 
00080                 if (sum < 0)
00081                         *d++ = 0;
00082                 else if (sum > 0x3fffff)
00083                         *d++ = 0xff;
00084                 else
00085                         *d++ = ((sum + 0x2000)>>14);
00086 
00087                 accum += samp_frac;
00088         } while(--cnt);
00089 
00090         return accum;
00091 }
00092 
00093 static long audio_downsample_mono16(void *dst, void *src, long *filter_bank, int filter_width, long accum, long samp_frac, long cnt) {
00094         signed short *d = (signed short *)dst;
00095         signed short *s = (signed short *)src;
00096 
00097         do {
00098                 long sum = 0;
00099                 int w;
00100                 long *fb_ptr;
00101                 signed short *s_ptr;
00102 
00103                 w = filter_width;
00104                 fb_ptr = filter_bank + filter_width * ((accum>>11)&0xff);
00105                 s_ptr = s + (accum>>19);
00106                 do {
00107                         sum += *fb_ptr++ * (int)*s_ptr++;
00108                 } while(--w);
00109 
00110                 if (sum < -0x20000000)
00111                         *d++ = -0x8000;
00112                 else if (sum > 0x1fffffff)
00113                         *d++ = 0x7fff;
00114                 else
00115                         *d++ = ((sum + 0x2000)>>14);
00116 
00117                 accum += samp_frac;
00118         } while(--cnt);
00119 
00120         return accum;
00121 }
00122 
00123 
00124 static int permute_index(int a, int b) {
00125         return (b-(a>>8)-1) + (a&255)*b;
00126 }
00127 
00128 static void make_downsample_filter(long *filter_bank, int filter_width, long samp_frac) {
00129         int i, j, v;
00130         double filt_max;
00131         double filtwidth_frac;
00132 
00133         filtwidth_frac = samp_frac/2048.0;
00134 
00135         filter_bank[filter_width-1] = 0;
00136 
00137         filt_max = (16384.0 * 524288.0) / samp_frac;
00138 
00139         for(i=0; i<128*filter_width; i++) {
00140                 int y = 0;
00141                 double d = i / filtwidth_frac;
00142 
00143                 if (d<1.0)
00144                         y = (int)(0.5 + filt_max*(1.0 - d));
00145 
00146                 filter_bank[permute_index(128*filter_width + i, filter_width)]
00147                         = filter_bank[permute_index(128*filter_width - i, filter_width)]
00148                         = y;
00149         }
00150 
00151         // Normalize the filter to correct for integer roundoff errors
00152 
00153         for(i=0; i<256*filter_width; i+=filter_width) {
00154                 v=0;
00155                 for(j=0; j<filter_width; j++)
00156                         v += filter_bank[i+j];
00157 
00158 //              _RPT2(0,"error[%02x] = %04x\n", i/filter_width, 0x4000 - v);
00159 
00160                 v = (0x4000 - v)/filter_width;
00161                 for(j=0; j<filter_width; j++)
00162                         filter_bank[i+j] += v;
00163         }
00164 
00165 //      _CrtCheckMemory();
00166 }
00167 
00168 AudioStreamResampler::AudioStreamResampler(int bps, long org_rate, long new_rate, bool fHighQuality)
00169 {
00170         samp_frac = 0x80000;
00171 
00172         this->bps = bps;
00173 
00174         if(bps == 1)
00175         {
00176                 ptsampleRout = audio_pointsample_8;
00177                 dnsampleRout = audio_downsample_mono8;
00178         }
00179         else if(bps >= 2)
00180         {
00181                 ptsampleRout = audio_pointsample_16;
00182                 dnsampleRout = audio_downsample_mono16;
00183         }
00184         else
00185         {
00186                 return;
00187         }
00188 
00189 // org_rate > new_rate!
00190         samp_frac = MulDiv(org_rate, 0x80000, new_rate);
00191 
00192         holdover = 0;
00193         filter_bank = NULL;
00194         filter_width = 1;
00195         accum = 0;
00196 
00197         // If this is a high-quality downsample, allocate memory for the filter bank
00198 
00199         if(fHighQuality)
00200         {
00201                 if(samp_frac>0x80000)
00202                 {
00203                         // HQ downsample: allocate filter bank
00204 
00205                         filter_width = ((samp_frac + 0x7ffff)>>19)<<1 <<1;
00206 
00207                         if(!(filter_bank = new long[filter_width * 256]))
00208                         {
00209                                 filter_width = 1;
00210                                 return;
00211                         }
00212 
00213                         make_downsample_filter(filter_bank, filter_width, samp_frac);
00214 
00215                         // Clear lower samples
00216 
00217                         memset(cbuffer, bps >= 2 ? 0 : 0x80, bps*filter_width);
00218 
00219                         holdover = filter_width/2;
00220                 }
00221         }
00222 }
00223 
00224 AudioStreamResampler::~AudioStreamResampler()
00225 {
00226         delete [] filter_bank;
00227 }
00228 
00229 long AudioStreamResampler::Downsample(void* input, long samplesin, void* output, long samplesout)
00230 {
00231         long lActualSamples = 0;
00232 
00233         // Downsampling is even worse because we have overlap to the left and to the
00234         // right of the interpolated point.
00235         //
00236         // We need (n/2) points to the left and (n/2-1) points to the right.
00237 
00238         while(samplesin > 0 && samplesout > 0)
00239         {
00240                 long srcSamples, dstSamples;
00241                 int nhold;
00242 
00243                 // Figure out how many source samples we need.
00244                 //
00245                 // To do this, compute the highest fixed-point accumulator we'll reach.
00246                 // Truncate that, and add the filter width.  Then subtract however many
00247                 // samples are sitting at the bottom of the buffer.
00248 
00249                 srcSamples = (long)(((__int64)samp_frac*(samplesout-1) + accum) >> 19) + filter_width - holdover;
00250 
00251                 // Don't exceed the buffer (BUFFER_SIZE - holdover).
00252 
00253                 if(srcSamples > BUFFER_SIZE - holdover)
00254                         srcSamples = BUFFER_SIZE - holdover;
00255 
00256                 // Read into buffer.
00257 
00258                 srcSamples = min(srcSamples, samplesin);
00259                 if(!srcSamples) break;
00260 
00261                 memcpy((char*)cbuffer + holdover*bps, (char*)input, srcSamples*bps);
00262                 input = (void *)((char *)input + srcSamples*bps);
00263 
00264                 // Figure out how many destination samples we'll get out of what we
00265                 // read.  We'll have (srcSamples+holdover) bytes, so the maximum
00266                 // fixed-pt accumulator we can hit is
00267                 // (srcSamples+holdover-filter_width)<<16 + 0xffff.
00268 
00269                 dstSamples = (((__int64)(srcSamples+holdover-filter_width)<<19) + 0x7ffff - accum) / samp_frac + 1;
00270 
00271                 if(dstSamples > samplesout)
00272                         dstSamples = samplesout;
00273 
00274                 if(dstSamples >= 1)
00275                 {
00276                         if(filter_bank)
00277                                 accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples);
00278                         else
00279                                 accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples);
00280 
00281                         output = (void *)((char *)output + bps * dstSamples);
00282                         lActualSamples += dstSamples;
00283                         samplesout -= dstSamples;
00284                 }
00285 
00286                 // We're "shifting" the new samples down to the bottom by discarding
00287                 // all the samples in the buffer, so adjust the fixed-pt accum
00288                 // accordingly.
00289 
00290                 accum -= ((srcSamples+holdover)<<19);
00291 
00292                 // Oops, did we need some of those?
00293                 //
00294                 // If accum=0, we need (n/2) samples back.  accum>=0x10000 is fewer,
00295                 // accum<0 is more.
00296 
00297                 nhold = - (accum>>19);
00298 
00299 //              _ASSERT(nhold<=(filter_width/2));
00300 
00301                 if (nhold>0) {
00302                         memmove(cbuffer, (char *)cbuffer+bps*(srcSamples+holdover-nhold), bps*nhold);
00303                         holdover = nhold;
00304                         accum += nhold<<19;
00305                 } else
00306                         holdover = 0;
00307 
00308 //              _ASSERT(accum>=0);
00309         }
00310 
00311         int Bytes = lActualSamples * bps;
00312 
00313         return lActualSamples;
00314 }

Generated on Tue Dec 13 14:47:26 2005 for guliverkli by  doxygen 1.4.5