Only set interface palette when painting backdrop. (This fixes movie palette.)
[scummvm-innocent.git] / sound / rate_arm.cpp
blobbf72d4e00e5e53f7541139d4e68fbd32112a2503
1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $URL$
22 * $Id$
27 * The code in this file, together with the rate_arm_asm.s file offers
28 * an ARM optimised version of the code in rate.cpp. The operation of this
29 * code should be identical to that of rate.cpp, but faster. The heavy
30 * lifting is done in the assembler file.
32 * To be as portable as possible we implement the core routines with C
33 * linkage in assembly, and implement the C++ routines that call into
34 * the C here. The C++ symbol mangling varies wildly between compilers,
35 * so this is the simplest way to ensure that the C/C++ combination should
36 * work on as many ARM based platforms as possible.
38 * Essentially the algorithm herein is the same as that in rate.cpp, so
39 * anyone seeking to understand this should attempt to understand that
40 * first. That code was based in turn on code with Copyright 1998 Fabrice
41 * Bellard - part of SoX (http://sox.sourceforge.net).
42 * Max Horn adapted that code to the needs of ScummVM and partially rewrote
43 * it, in the process removing any use of floating point arithmetic. Various
44 * other improvments over the original code were made.
47 #include "sound/audiostream.h"
48 #include "sound/rate.h"
49 #include "sound/mixer.h"
50 #include "common/util.h"
52 //#define DEBUG_RATECONV
54 namespace Audio {
56 /**
57 * The precision of the fractional computations used by the rate converter.
58 * Normally you should never have to modify this value.
59 * This stuff is defined in common/frac.h, but we redefine it here as the
60 * ARM routine we call doesn't respect those definitions.
62 #define FRAC_BITS 16
63 #define FRAC_ONE (1<<FRAC_BITS)
65 /**
66 * The size of the intermediate input cache. Bigger values may increase
67 * performance, but only until some point (depends largely on cache size,
68 * target processor and various other factors), at which it will decrease
69 * again.
71 #define INTERMEDIATE_BUFFER_SIZE 512
74 /**
75 * Audio rate converter based on simple resampling. Used when no
76 * interpolation is required.
78 * Limited to sampling frequency <= 65535 Hz.
80 typedef struct {
81 const st_sample_t *inPtr;
82 int inLen;
84 /** position of how far output is ahead of input */
85 /** Holds what would have been opos-ipos */
86 long opos;
88 /** fractional position increment in the output stream */
89 long opos_inc;
91 st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
92 } SimpleRateDetails;
94 template<bool stereo, bool reverseStereo>
95 class SimpleRateConverter : public RateConverter {
96 protected:
97 SimpleRateDetails sr;
98 public:
99 SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
100 int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
101 int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
102 return (ST_SUCCESS);
108 * Prepare processing.
110 template<bool stereo, bool reverseStereo>
111 SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
112 if (inrate == outrate) {
113 error("Input and Output rates must be different to use rate effect");
116 if ((inrate % outrate) != 0) {
117 error("Input rate must be a multiple of Output rate to use rate effect");
120 if (inrate >= 65536 || outrate >= 65536) {
121 error("rate effect can only handle rates < 65536");
124 sr.opos = 1;
126 /* increment */
127 sr.opos_inc = inrate / outrate;
129 sr.inLen = 0;
132 extern "C" {
133 #ifndef IPHONE
134 #define ARM_SimpleRate_M _ARM_SimpleRate_M
135 #define ARM_SimpleRate_S _ARM_SimpleRate_S
136 #define ARM_SimpleRate_R _ARM_SimpleRate_R
137 #endif
140 extern "C" void ARM_SimpleRate_M(AudioStream &input,
141 int (*fn)(Audio::AudioStream&,int16*,int),
142 SimpleRateDetails *sr,
143 st_sample_t *obuf,
144 st_size_t osamp,
145 st_volume_t vol_l,
146 st_volume_t vol_r);
148 extern "C" void ARM_SimpleRate_S(AudioStream &input,
149 int (*fn)(Audio::AudioStream&,int16*,int),
150 SimpleRateDetails *sr,
151 st_sample_t *obuf,
152 st_size_t osamp,
153 st_volume_t vol_l,
154 st_volume_t vol_r);
156 extern "C" void ARM_SimpleRate_R(AudioStream &input,
157 int (*fn)(Audio::AudioStream&,int16*,int),
158 SimpleRateDetails *sr,
159 st_sample_t *obuf,
160 st_size_t osamp,
161 st_volume_t vol_l,
162 st_volume_t vol_r);
164 extern "C" int SimpleRate_readFudge(Audio::AudioStream &input,
165 int16 *a, int b)
167 #ifdef DEBUG_RATECONV
168 fprintf(stderr, "Reading ptr=%x n%d\n", a, b);
169 fflush(stderr);
170 #endif
171 return input.readBuffer(a, b);
174 template<bool stereo, bool reverseStereo>
175 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) {
177 #ifdef DEBUG_RATECONV
178 fprintf(stderr, "Simple st=%d rev=%d\n", stereo, reverseStereo);
179 fflush(stderr);
180 #endif
181 if (!stereo) {
182 ARM_SimpleRate_M(input,
183 &SimpleRate_readFudge,
184 &sr,
185 obuf, osamp, vol_l, vol_r);
186 } else if (reverseStereo) {
187 ARM_SimpleRate_R(input,
188 &SimpleRate_readFudge,
189 &sr,
190 obuf, osamp, vol_l, vol_r);
191 } else {
192 ARM_SimpleRate_S(input,
193 &SimpleRate_readFudge,
194 &sr,
195 obuf, osamp, vol_l, vol_r);
197 return (ST_SUCCESS);
201 * Audio rate converter based on simple linear Interpolation.
203 * The use of fractional increment allows us to use no buffer. It
204 * avoid the problems at the end of the buffer we had with the old
205 * method which stored a possibly big buffer of size
206 * lcm(in_rate,out_rate).
208 * Limited to sampling frequency <= 65535 Hz.
211 typedef struct {
212 const st_sample_t *inPtr;
213 int inLen;
215 /** position of how far output is ahead of input */
216 /** Holds what would have been opos-ipos<<16 + opos_frac */
217 long opos;
219 /** integer position increment in the output stream */
220 long opos_inc;
222 /** current sample(s) in the input stream (left/right channel) */
223 st_sample_t icur[2];
224 /** last sample(s) in the input stream (left/right channel) */
225 /** Note, these are deliberately ints, not st_sample_t's */
226 int32 ilast[2];
228 st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
229 } LinearRateDetails;
231 extern "C" {
232 #ifndef IPHONE
233 #define ARM_LinearRate_M _ARM_LinearRate_M
234 #define ARM_LinearRate_S _ARM_LinearRate_S
235 #define ARM_LinearRate_R _ARM_LinearRate_R
236 #endif
239 extern "C" void ARM_LinearRate_M(AudioStream &input,
240 int (*fn)(Audio::AudioStream&,int16*,int),
241 LinearRateDetails *lr,
242 st_sample_t *obuf,
243 st_size_t osamp,
244 st_volume_t vol_l,
245 st_volume_t vol_r);
247 extern "C" void ARM_LinearRate_S(AudioStream &input,
248 int (*fn)(Audio::AudioStream&,int16*,int),
249 LinearRateDetails *lr,
250 st_sample_t *obuf,
251 st_size_t osamp,
252 st_volume_t vol_l,
253 st_volume_t vol_r);
255 extern "C" void ARM_LinearRate_R(AudioStream &input,
256 int (*fn)(Audio::AudioStream&,int16*,int),
257 LinearRateDetails *lr,
258 st_sample_t *obuf,
259 st_size_t osamp,
260 st_volume_t vol_l,
261 st_volume_t vol_r);
263 template<bool stereo, bool reverseStereo>
264 class LinearRateConverter : public RateConverter {
265 protected:
266 LinearRateDetails lr;
268 public:
269 LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
270 int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
271 int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
272 return (ST_SUCCESS);
278 * Prepare processing.
280 template<bool stereo, bool reverseStereo>
281 LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
282 unsigned long incr;
284 if (inrate == outrate) {
285 error("Input and Output rates must be different to use rate effect");
288 if (inrate >= 65536 || outrate >= 65536) {
289 error("rate effect can only handle rates < 65536");
292 lr.opos = FRAC_ONE;
294 /* increment */
295 incr = (inrate << FRAC_BITS) / outrate;
297 lr.opos_inc = incr;
299 lr.ilast[0] = lr.ilast[1] = 32768;
300 lr.icur[0] = lr.icur[1] = 0;
302 lr.inLen = 0;
306 * Processed signed long samples from ibuf to obuf.
307 * Return number of samples processed.
309 template<bool stereo, bool reverseStereo>
310 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) {
312 #ifdef DEBUG_RATECONV
313 fprintf(stderr, "Linear st=%d rev=%d\n", stereo, reverseStereo);
314 fflush(stderr);
315 #endif
316 if (!stereo) {
317 ARM_LinearRate_M(input,
318 &SimpleRate_readFudge,
319 &lr,
320 obuf, osamp, vol_l, vol_r);
321 } else if (reverseStereo) {
322 ARM_LinearRate_R(input,
323 &SimpleRate_readFudge,
324 &lr,
325 obuf, osamp, vol_l, vol_r);
326 } else {
327 ARM_LinearRate_S(input,
328 &SimpleRate_readFudge,
329 &lr,
330 obuf, osamp, vol_l, vol_r);
332 return (ST_SUCCESS);
336 #pragma mark -
340 * Simple audio rate converter for the case that the inrate equals the outrate.
342 extern "C" {
343 #ifndef IPHONE
344 #define ARM_CopyRate_M _ARM_CopyRate_M
345 #define ARM_CopyRate_S _ARM_CopyRate_S
346 #define ARM_CopyRate_R _ARM_CopyRate_R
347 #endif
350 extern "C" void ARM_CopyRate_M(st_size_t len,
351 st_sample_t *obuf,
352 st_volume_t vol_l,
353 st_volume_t vol_r,
354 st_sample_t *_buffer);
356 extern "C" void ARM_CopyRate_S(st_size_t len,
357 st_sample_t *obuf,
358 st_volume_t vol_l,
359 st_volume_t vol_r,
360 st_sample_t *_buffer);
362 extern "C" void ARM_CopyRate_R(st_size_t len,
363 st_sample_t *obuf,
364 st_volume_t vol_l,
365 st_volume_t vol_r,
366 st_sample_t *_buffer);
369 template<bool stereo, bool reverseStereo>
370 class CopyRateConverter : public RateConverter {
371 st_sample_t *_buffer;
372 st_size_t _bufferSize;
373 public:
374 CopyRateConverter() : _buffer(0), _bufferSize(0) {}
375 ~CopyRateConverter() {
376 free(_buffer);
379 virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
380 assert(input.isStereo() == stereo);
382 #ifdef DEBUG_RATECONV
383 fprintf(stderr, "Copy st=%d rev=%d\n", stereo, reverseStereo);
384 fflush(stderr);
385 #endif
386 st_size_t len;
388 if (stereo)
389 osamp *= 2;
391 // Reallocate temp buffer, if necessary
392 if (osamp > _bufferSize) {
393 free(_buffer);
394 _buffer = (st_sample_t *)malloc(osamp * 2);
395 _bufferSize = osamp;
398 // Read up to 'osamp' samples into our temporary buffer
399 len = input.readBuffer(_buffer, osamp);
400 if (len <= 0)
401 return (ST_SUCCESS);
403 // Mix the data into the output buffer
404 if (stereo && reverseStereo)
405 ARM_CopyRate_R(len, obuf, vol_l, vol_r, _buffer);
406 else if (stereo)
407 ARM_CopyRate_S(len, obuf, vol_l, vol_r, _buffer);
408 else
409 ARM_CopyRate_M(len, obuf, vol_l, vol_r, _buffer);
411 return (ST_SUCCESS);
413 virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
414 return (ST_SUCCESS);
419 #pragma mark -
423 * Create and return a RateConverter object for the specified input and output rates.
425 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
426 if (inrate != outrate) {
427 if ((inrate % outrate) == 0) {
428 if (stereo) {
429 if (reverseStereo)
430 return new SimpleRateConverter<true, true>(inrate, outrate);
431 else
432 return new SimpleRateConverter<true, false>(inrate, outrate);
433 } else
434 return new SimpleRateConverter<false, false>(inrate, outrate);
435 } else {
436 if (stereo) {
437 if (reverseStereo)
438 return new LinearRateConverter<true, true>(inrate, outrate);
439 else
440 return new LinearRateConverter<true, false>(inrate, outrate);
441 } else
442 return new LinearRateConverter<false, false>(inrate, outrate);
444 } else {
445 if (stereo) {
446 if (reverseStereo)
447 return new CopyRateConverter<true, true>();
448 else
449 return new CopyRateConverter<true, false>();
450 } else
451 return new CopyRateConverter<false, false>();
455 } // End of namespace Audio