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

rate_arm.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, together with the rate_arm_asm.s file offers
00025  * an ARM optimised version of the code in rate.cpp. The operation of this
00026  * code should be identical to that of rate.cpp, but faster. The heavy
00027  * lifting is done in the assembler file.
00028  *
00029  * To be as portable as possible we implement the core routines with C
00030  * linkage in assembly, and implement the C++ routines that call into
00031  * the C here. The C++ symbol mangling varies wildly between compilers,
00032  * so this is the simplest way to ensure that the C/C++ combination should
00033  * work on as many ARM based platforms as possible.
00034  *
00035  * Essentially the algorithm herein is the same as that in rate.cpp, so
00036  * anyone seeking to understand this should attempt to understand that
00037  * first. That code was based in turn on code with Copyright 1998 Fabrice
00038  * Bellard - part of SoX (http://sox.sourceforge.net).
00039  * Max Horn adapted that code to the needs of ScummVM and partially rewrote
00040  * it, in the process removing any use of floating point arithmetic. Various
00041  * other improvments over the original code were made.
00042  */
00043 
00044 #include "audio/audiostream.h"
00045 #include "audio/rate.h"
00046 #include "audio/mixer.h"
00047 #include "common/util.h"
00048 #include "common/textconsole.h"
00049 
00050 //#define DEBUG_RATECONV
00051 
00052 namespace Audio {
00053 
00060 #define FRAC_BITS 16
00061 #define FRAC_ONE  (1 << FRAC_BITS)
00062 
00069 #define INTERMEDIATE_BUFFER_SIZE 512
00070 
00076 enum {
00077     FRAC_BITS_LOW = 15,
00078     FRAC_ONE_LOW = (1L << FRAC_BITS_LOW),
00079     FRAC_HALF_LOW = (1L << (FRAC_BITS_LOW-1))
00080 };
00081 
00088 typedef struct {
00089     const st_sample_t *inPtr;
00090     int inLen;
00091 
00094     long opos;
00095 
00097     long opos_inc;
00098 
00099     st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
00100 } SimpleRateDetails;
00101 
00102 template<bool stereo, bool reverseStereo>
00103 class SimpleRateConverter : public RateConverter {
00104 protected:
00105     SimpleRateDetails  sr;
00106 public:
00107     SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
00108     int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
00109     int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00110         return (ST_SUCCESS);
00111     }
00112 };
00113 
00114 
00115 /*
00116  * Prepare processing.
00117  */
00118 template<bool stereo, bool reverseStereo>
00119 SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
00120     if (inrate == outrate) {
00121         error("Input and Output rates must be different to use rate effect");
00122     }
00123 
00124     if ((inrate % outrate) != 0) {
00125         error("Input rate must be a multiple of Output rate to use rate effect");
00126     }
00127 
00128     if (inrate >= 65536 || outrate >= 65536) {
00129         error("rate effect can only handle rates < 65536");
00130     }
00131 
00132     sr.opos = 1;
00133 
00134     /* increment */
00135     sr.opos_inc = inrate / outrate;
00136 
00137     sr.inLen = 0;
00138 }
00139 
00140 #ifndef IPHONE
00141 #define ARM_SimpleRate_M _ARM_SimpleRate_M
00142 #define ARM_SimpleRate_S _ARM_SimpleRate_S
00143 #define ARM_SimpleRate_R _ARM_SimpleRate_R
00144 #endif
00145 
00146 extern "C" st_sample_t *ARM_SimpleRate_M(
00147                                 AudioStream &input,
00148                                 int (*fn)(Audio::AudioStream&,int16*,int),
00149                                 SimpleRateDetails *sr,
00150                                 st_sample_t *obuf,
00151                                 st_size_t osamp,
00152                                 st_volume_t vol_l,
00153                                 st_volume_t vol_r);
00154 
00155 extern "C" st_sample_t *ARM_SimpleRate_S(
00156                                 AudioStream &input,
00157                                 int (*fn)(Audio::AudioStream&,int16*,int),
00158                                 SimpleRateDetails *sr,
00159                                 st_sample_t *obuf,
00160                                 st_size_t osamp,
00161                                 st_volume_t vol_l,
00162                                 st_volume_t vol_r);
00163 
00164 extern "C" st_sample_t *ARM_SimpleRate_R(
00165                                 AudioStream &input,
00166                                 int (*fn)(Audio::AudioStream&,int16*,int),
00167                                 SimpleRateDetails *sr,
00168                                 st_sample_t *obuf,
00169                                 st_size_t osamp,
00170                                 st_volume_t vol_l,
00171                                 st_volume_t vol_r);
00172 
00173 extern "C" int SimpleRate_readFudge(Audio::AudioStream &input, int16 *a, int b)
00174 {
00175 #ifdef DEBUG_RATECONV
00176     debug("Reading ptr=%x n%d", a, b);
00177 #endif
00178     return input.readBuffer(a, b);
00179 }
00180 
00181 template<bool stereo, bool reverseStereo>
00182 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) {
00183 
00184 #ifdef DEBUG_RATECONV
00185     debug("Simple st=%d rev=%d", stereo, reverseStereo);
00186 #endif
00187     st_sample_t *ostart = obuf;
00188 
00189     if (!stereo) {
00190         obuf = ARM_SimpleRate_M(input,
00191                                 &SimpleRate_readFudge,
00192                                 &sr,
00193                                 obuf, osamp, vol_l, vol_r);
00194     } else if (reverseStereo) {
00195         obuf = ARM_SimpleRate_R(input,
00196                                 &SimpleRate_readFudge,
00197                                 &sr,
00198                                 obuf, osamp, vol_l, vol_r);
00199     } else {
00200         obuf = ARM_SimpleRate_S(input,
00201                                 &SimpleRate_readFudge,
00202                                 &sr,
00203                                 obuf, osamp, vol_l, vol_r);
00204     }
00205 
00206     return (obuf - ostart) / 2;
00207 }
00208 
00220 typedef struct {
00221     const st_sample_t *inPtr;
00222     int inLen;
00223 
00226     long opos;
00227 
00229     long opos_inc;
00230 
00232     st_sample_t icur[2];
00235     int32 ilast[2];
00236 
00237     st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
00238 } LinearRateDetails;
00239 
00240 extern "C" {
00241 #ifndef IPHONE
00242 #define ARM_LinearRate_M _ARM_LinearRate_M
00243 #define ARM_LinearRate_S _ARM_LinearRate_S
00244 #define ARM_LinearRate_R _ARM_LinearRate_R
00245 #endif
00246 }
00247 
00248 extern "C" st_sample_t *ARM_LinearRate_M(
00249                                 AudioStream &input,
00250                                 int (*fn)(Audio::AudioStream&,int16*,int),
00251                                 LinearRateDetails *lr,
00252                                 st_sample_t *obuf,
00253                                 st_size_t osamp,
00254                                 st_volume_t vol_l,
00255                                 st_volume_t vol_r);
00256 
00257 extern "C" st_sample_t *ARM_LinearRate_S(
00258                                 AudioStream &input,
00259                                 int (*fn)(Audio::AudioStream&,int16*,int),
00260                                 LinearRateDetails *lr,
00261                                 st_sample_t *obuf,
00262                                 st_size_t osamp,
00263                                 st_volume_t vol_l,
00264                                 st_volume_t vol_r);
00265 
00266 extern "C" st_sample_t *ARM_LinearRate_R(
00267                                 AudioStream &input,
00268                                 int (*fn)(Audio::AudioStream&,int16*,int),
00269                                 LinearRateDetails *lr,
00270                                 st_sample_t *obuf,
00271                                 st_size_t osamp,
00272                                 st_volume_t vol_l,
00273                                 st_volume_t vol_r);
00274 
00275 template<bool stereo, bool reverseStereo>
00276 class LinearRateConverter : public RateConverter {
00277 protected:
00278     LinearRateDetails lr;
00279 
00280 public:
00281     LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
00282     int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
00283     int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00284         return (ST_SUCCESS);
00285     }
00286 };
00287 
00288 
00289 /*
00290  * Prepare processing.
00291  */
00292 template<bool stereo, bool reverseStereo>
00293 LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
00294     unsigned long incr;
00295 
00296     if (inrate == outrate) {
00297         error("Input and Output rates must be different to use rate effect");
00298     }
00299 
00300     if (inrate >= 131072 || outrate >= 131072) {
00301         error("rate effect can only handle rates < 131072");
00302     }
00303 
00304     lr.opos = FRAC_ONE_LOW;
00305 
00306     /* increment */
00307     incr = (inrate << FRAC_BITS_LOW) / outrate;
00308 
00309     lr.opos_inc = incr;
00310 
00311     // FIXME: Does 32768 here need changing to 65536 or 0? Compare to rate.cpp code...
00312     lr.ilast[0] = lr.ilast[1] = 32768;
00313     lr.icur[0] = lr.icur[1] = 0;
00314 
00315     lr.inLen = 0;
00316 }
00317 
00318 /*
00319  * Processed signed long samples from ibuf to obuf.
00320  * Return number of sample pairs processed.
00321  */
00322 template<bool stereo, bool reverseStereo>
00323 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) {
00324 
00325 #ifdef DEBUG_RATECONV
00326     debug("Linear st=%d rev=%d", stereo, reverseStereo);
00327 #endif
00328     st_sample_t *ostart = obuf;
00329 
00330     if (vol_l > 0xff)
00331         vol_l = 0xff;
00332 
00333     if (vol_r > 0xff)
00334         vol_r = 0xff;
00335 
00336     if (!stereo) {
00337         obuf = ARM_LinearRate_M(input,
00338                                 &SimpleRate_readFudge,
00339                                 &lr,
00340                                 obuf, osamp, vol_l, vol_r);
00341     } else if (reverseStereo) {
00342         obuf = ARM_LinearRate_R(input,
00343                                 &SimpleRate_readFudge,
00344                                 &lr,
00345                                 obuf, osamp, vol_l, vol_r);
00346     } else {
00347         obuf = ARM_LinearRate_S(input,
00348                                 &SimpleRate_readFudge,
00349                                 &lr,
00350                                 obuf, osamp, vol_l, vol_r);
00351     }
00352     return (obuf - ostart) / 2;
00353 }
00354 
00355 
00356 #pragma mark -
00357 
00358 
00362 extern "C" {
00363 #ifndef IPHONE
00364 #define ARM_CopyRate_M _ARM_CopyRate_M
00365 #define ARM_CopyRate_S _ARM_CopyRate_S
00366 #define ARM_CopyRate_R _ARM_CopyRate_R
00367 #endif
00368 }
00369 
00370 extern "C" st_sample_t *ARM_CopyRate_M(
00371                                 st_size_t len,
00372                                 st_sample_t *obuf,
00373                                 st_volume_t vol_l,
00374                                 st_volume_t vol_r,
00375                                 st_sample_t *_buffer);
00376 
00377 extern "C" st_sample_t *ARM_CopyRate_S(
00378                                 st_size_t len,
00379                                 st_sample_t *obuf,
00380                                 st_volume_t vol_l,
00381                                 st_volume_t vol_r,
00382                                 st_sample_t *_buffer);
00383 
00384 extern "C" st_sample_t *ARM_CopyRate_R(
00385                                 st_size_t len,
00386                                 st_sample_t *obuf,
00387                                 st_volume_t vol_l,
00388                                 st_volume_t vol_r,
00389                                 st_sample_t *_buffer);
00390 
00391 
00392 template<bool stereo, bool reverseStereo>
00393 class CopyRateConverter : public RateConverter {
00394     st_sample_t *_buffer;
00395     st_size_t _bufferSize;
00396 
00397 public:
00398     CopyRateConverter() : _buffer(0), _bufferSize(0) {}
00399     ~CopyRateConverter() {
00400         free(_buffer);
00401     }
00402 
00403     virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
00404         assert(input.isStereo() == stereo);
00405 
00406 #ifdef DEBUG_RATECONV
00407         debug("Copy st=%d rev=%d", stereo, reverseStereo);
00408 #endif
00409         st_size_t len;
00410         st_sample_t *ostart = obuf;
00411 
00412         if (stereo)
00413             osamp *= 2;
00414 
00415         // Reallocate temp buffer, if necessary
00416         if (osamp > _bufferSize) {
00417             free(_buffer);
00418             _buffer = (st_sample_t *)malloc(osamp * 2);
00419             _bufferSize = osamp;
00420         }
00421 
00422         // Read up to 'osamp' samples into our temporary buffer
00423         len = input.readBuffer(_buffer, osamp);
00424         if (len <= 0)
00425             return 0;
00426 
00427         // Mix the data into the output buffer
00428         if (stereo && reverseStereo)
00429             obuf = ARM_CopyRate_R(len, obuf, vol_l, vol_r, _buffer);
00430         else if (stereo)
00431             obuf = ARM_CopyRate_S(len, obuf, vol_l, vol_r, _buffer);
00432         else
00433             obuf = ARM_CopyRate_M(len, obuf, vol_l, vol_r, _buffer);
00434 
00435         return (obuf - ostart) / 2;
00436     }
00437 
00438     virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
00439         return (ST_SUCCESS);
00440     }
00441 };
00442 
00443 
00444 #pragma mark -
00445 
00446 
00450 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
00451     if (inrate != outrate) {
00452         if ((inrate % outrate) == 0 && (inrate < 65536)) {
00453             if (stereo) {
00454                 if (reverseStereo)
00455                     return new SimpleRateConverter<true, true>(inrate, outrate);
00456                 else
00457                     return new SimpleRateConverter<true, false>(inrate, outrate);
00458             } else
00459                 return new SimpleRateConverter<false, false>(inrate, outrate);
00460         } else {
00461             if (stereo) {
00462                 if (reverseStereo)
00463                     return new LinearRateConverter<true, true>(inrate, outrate);
00464                 else
00465                     return new LinearRateConverter<true, false>(inrate, outrate);
00466             } else
00467                 return new LinearRateConverter<false, false>(inrate, outrate);
00468          }
00469     } else {
00470         if (stereo) {
00471             if (reverseStereo)
00472                 return new CopyRateConverter<true, true>();
00473             else
00474                 return new CopyRateConverter<true, false>();
00475         } else
00476             return new CopyRateConverter<false, false>();
00477     }
00478 }
00479 
00480 } // End of namespace Audio


Generated on Sat Jul 20 2019 05:00:43 for ResidualVM by doxygen 1.7.1
curved edge   curved edge