- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }