ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

rate.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * The code in this file is based on code with Copyright 1998 Fabrice Bellard
00025  * Fabrice original code is part of SoX (http://sox.sourceforge.net).
00026  * Max Horn adapted that code to the needs of ScummVM and rewrote it partial,
00027  * in the process removing any use of floating point arithmetic. Various other
00028  * improvements over the original code were made.
00029  */
00030 
00031 #include "audio/audiostream.h"
00032 #include "audio/rate.h"
00033 #include "audio/mixer.h"
00034 #include "common/frac.h"
00035 #include "common/textconsole.h"
00036 #include "common/util.h"
00037 
00038 namespace Audio {
00039 
00040 
00047 #define INTERMEDIATE_BUFFER_SIZE 512
00048 
00054 enum {
00055     FRAC_BITS_LOW = 15,
00056     FRAC_ONE_LOW = (1L << FRAC_BITS_LOW),
00057     FRAC_HALF_LOW = (1L << (FRAC_BITS_LOW-1))
00058 };
00059 
00066 template<bool stereo, bool reverseStereo>
00067 class SimpleRateConverter : public RateConverter {
00068 protected:
00069     st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
00070     const st_sample_t *inPtr;
00071     int inLen;
00072 
00075     long opos;
00076 
00078     long opos_inc;
00079 
00080 public:
00081     SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
00082     int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
00083     int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00084         return ST_SUCCESS;
00085     }
00086 };
00087 
00088 
00089 /*
00090  * Prepare processing.
00091  */
00092 template<bool stereo, bool reverseStereo>
00093 SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
00094     if ((inrate % outrate) != 0) {
00095         error("Input rate must be a multiple of output rate to use rate effect");
00096     }
00097 
00098     if (inrate >= 65536 || outrate >= 65536) {
00099         error("rate effect can only handle rates < 65536");
00100     }
00101 
00102     opos = 1;
00103 
00104     /* increment */
00105     opos_inc = inrate / outrate;
00106 
00107     inLen = 0;
00108 }
00109 
00110 /*
00111  * Processed signed long samples from ibuf to obuf.
00112  * Return number of sample pairs processed.
00113  */
00114 template<bool stereo, bool reverseStereo>
00115 int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
00116     st_sample_t *ostart, *oend;
00117 
00118     ostart = obuf;
00119     oend = obuf + osamp * 2;
00120 
00121     while (obuf < oend) {
00122 
00123         // read enough input samples so that opos >= 0
00124         do {
00125             // Check if we have to refill the buffer
00126             if (inLen == 0) {
00127                 inPtr = inBuf;
00128                 inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
00129                 if (inLen <= 0)
00130                     return (obuf - ostart) / 2;
00131             }
00132             inLen -= (stereo ? 2 : 1);
00133             opos--;
00134             if (opos >= 0) {
00135                 inPtr += (stereo ? 2 : 1);
00136             }
00137         } while (opos >= 0);
00138 
00139         st_sample_t out0, out1;
00140         out0 = *inPtr++;
00141         out1 = (stereo ? *inPtr++ : out0);
00142 
00143         // Increment output position
00144         opos += opos_inc;
00145 
00146         // output left channel
00147         clampedAdd(obuf[reverseStereo    ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
00148 
00149         // output right channel
00150         clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
00151 
00152         obuf += 2;
00153     }
00154     return (obuf - ostart) / 2;
00155 }
00156 
00168 template<bool stereo, bool reverseStereo>
00169 class LinearRateConverter : public RateConverter {
00170 protected:
00171     st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
00172     const st_sample_t *inPtr;
00173     int inLen;
00174 
00176     frac_t opos;
00177 
00179     frac_t opos_inc;
00180 
00182     st_sample_t ilast0, ilast1;
00184     st_sample_t icur0, icur1;
00185 
00186 public:
00187     LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
00188     int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
00189     int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00190         return ST_SUCCESS;
00191     }
00192 };
00193 
00194 
00195 /*
00196  * Prepare processing.
00197  */
00198 template<bool stereo, bool reverseStereo>
00199 LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
00200     if (inrate >= 131072 || outrate >= 131072) {
00201         error("rate effect can only handle rates < 131072");
00202     }
00203 
00204     opos = FRAC_ONE_LOW;
00205 
00206     // Compute the linear interpolation increment.
00207     // This will overflow if inrate >= 2^17, and underflow if outrate >= 2^17.
00208     // Also, if the quotient of the two rate becomes too small / too big, that
00209     // would cause problems, but since we rarely scale from 1 to 65536 Hz or vice
00210     // versa, I think we can live with that limitation ;-).
00211     opos_inc = (inrate << FRAC_BITS_LOW) / outrate;
00212 
00213     ilast0 = ilast1 = 0;
00214     icur0 = icur1 = 0;
00215 
00216     inLen = 0;
00217 }
00218 
00219 /*
00220  * Processed signed long samples from ibuf to obuf.
00221  * Return number of sample pairs processed.
00222  */
00223 template<bool stereo, bool reverseStereo>
00224 int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
00225     st_sample_t *ostart, *oend;
00226 
00227     ostart = obuf;
00228     oend = obuf + osamp * 2;
00229 
00230     while (obuf < oend) {
00231 
00232         // read enough input samples so that opos < 0
00233         while ((frac_t)FRAC_ONE_LOW <= opos) {
00234             // Check if we have to refill the buffer
00235             if (inLen == 0) {
00236                 inPtr = inBuf;
00237                 inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
00238                 if (inLen <= 0)
00239                     return (obuf - ostart) / 2;
00240             }
00241             inLen -= (stereo ? 2 : 1);
00242             ilast0 = icur0;
00243             icur0 = *inPtr++;
00244             if (stereo) {
00245                 ilast1 = icur1;
00246                 icur1 = *inPtr++;
00247             }
00248             opos -= FRAC_ONE_LOW;
00249         }
00250 
00251         // Loop as long as the outpos trails behind, and as long as there is
00252         // still space in the output buffer.
00253         while (opos < (frac_t)FRAC_ONE_LOW && obuf < oend) {
00254             // interpolate
00255             st_sample_t out0, out1;
00256             out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF_LOW) >> FRAC_BITS_LOW));
00257             out1 = (stereo ?
00258                           (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF_LOW) >> FRAC_BITS_LOW)) :
00259                           out0);
00260 
00261             // output left channel
00262             clampedAdd(obuf[reverseStereo    ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
00263 
00264             // output right channel
00265             clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
00266 
00267             obuf += 2;
00268 
00269             // Increment output position
00270             opos += opos_inc;
00271         }
00272     }
00273     return (obuf - ostart) / 2;
00274 }
00275 
00276 
00277 #pragma mark -
00278 
00279 
00283 template<bool stereo, bool reverseStereo>
00284 class CopyRateConverter : public RateConverter {
00285     st_sample_t *_buffer;
00286     st_size_t _bufferSize;
00287 public:
00288     CopyRateConverter() : _buffer(0), _bufferSize(0) {}
00289     ~CopyRateConverter() {
00290         free(_buffer);
00291     }
00292 
00293     virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
00294         assert(input.isStereo() == stereo);
00295 
00296         st_sample_t *ptr;
00297         st_size_t len;
00298 
00299         st_sample_t *ostart = obuf;
00300 
00301         if (stereo)
00302             osamp *= 2;
00303 
00304         // Reallocate temp buffer, if necessary
00305         if (osamp > _bufferSize) {
00306             free(_buffer);
00307             _buffer = (st_sample_t *)malloc(osamp * 2);
00308             _bufferSize = osamp;
00309         }
00310 
00311         if (!_buffer)
00312             error("[CopyRateConverter::flow] Cannot allocate memory for temp buffer");
00313 
00314         // Read up to 'osamp' samples into our temporary buffer
00315         len = input.readBuffer(_buffer, osamp);
00316 
00317         // Mix the data into the output buffer
00318         ptr = _buffer;
00319         for (; len > 0; len -= (stereo ? 2 : 1)) {
00320             st_sample_t out0, out1;
00321             out0 = *ptr++;
00322             out1 = (stereo ? *ptr++ : out0);
00323 
00324             // output left channel
00325             clampedAdd(obuf[reverseStereo    ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
00326 
00327             // output right channel
00328             clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
00329 
00330             obuf += 2;
00331         }
00332         return (obuf - ostart) / 2;
00333     }
00334 
00335     virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00336         return ST_SUCCESS;
00337     }
00338 };
00339 
00340 
00341 #pragma mark -
00342 
00343 template<bool stereo, bool reverseStereo>
00344 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
00345     if (inrate != outrate) {
00346         if ((inrate % outrate) == 0 && (inrate < 65536)) {
00347             return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);
00348         } else {
00349             return new LinearRateConverter<stereo, reverseStereo>(inrate, outrate);
00350         }
00351     } else {
00352         return new CopyRateConverter<stereo, reverseStereo>();
00353     }
00354 }
00355 
00359 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
00360     if (stereo) {
00361         if (reverseStereo)
00362             return makeRateConverter<true, true>(inrate, outrate);
00363         else
00364             return makeRateConverter<true, false>(inrate, outrate);
00365     } else
00366         return makeRateConverter<false, false>(inrate, outrate);
00367 }
00368 
00369 } // End of namespace Audio


Generated on Sat Aug 17 2019 05:00:25 for ResidualVM by doxygen 1.7.1
curved edge   curved edge