1 /* ScummVM - Graphic Adventure Engine
2 *
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.
6 *
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.
11 *
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.
16 *
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.
20 *
21 */
22
23 /*
24 * The code in this file, together with the rate_arm_asm.s file offers
25 * an ARM optimised version of the code in rate.cpp. The operation of this
26 * code should be identical to that of rate.cpp, but faster. The heavy
27 * lifting is done in the assembler file.
28 *
29 * To be as portable as possible we implement the core routines with C
30 * linkage in assembly, and implement the C++ routines that call into
31 * the C here. The C++ symbol mangling varies wildly between compilers,
32 * so this is the simplest way to ensure that the C/C++ combination should
33 * work on as many ARM based platforms as possible.
34 *
35 * Essentially the algorithm herein is the same as that in rate.cpp, so
36 * anyone seeking to understand this should attempt to understand that
37 * first. That code was based in turn on code with Copyright 1998 Fabrice
38 * Bellard - part of SoX (http://sox.sourceforge.net).
39 * Max Horn adapted that code to the needs of ScummVM and partially rewrote
40 * it, in the process removing any use of floating point arithmetic. Various
41 * other improvments over the original code were made.
42 */
43
44 #include "audio/audiostream.h"
45 #include "audio/rate.h"
46 #include "audio/mixer.h"
47 #include "common/util.h"
48 #include "common/textconsole.h"
49
50 //#define DEBUG_RATECONV
51
52 namespace Audio {
53
54 /**
55 * The precision of the fractional computations used by the rate converter.
56 * Normally you should never have to modify this value.
57 * This stuff is defined in common/frac.h, but we redefine it here as the
58 * ARM routine we call doesn't respect those definitions.
59 */
60 #define FRAC_BITS 16
61 #define FRAC_ONE (1 << FRAC_BITS)
62
63 /**
64 * The size of the intermediate input cache. Bigger values may increase
65 * performance, but only until some point (depends largely on cache size,
66 * target processor and various other factors), at which it will decrease
67 * again.
68 */
69 #define INTERMEDIATE_BUFFER_SIZE 512
70
71 /**
72 * The default fractional type in frac.h (with 16 fractional bits) limits
73 * the rate conversion code to 65536Hz audio: we need to able to handle
74 * 96kHz audio, so we use fewer fractional bits in this code.
75 */
76 enum {
77 FRAC_BITS_LOW = 15,
78 FRAC_ONE_LOW = (1L << FRAC_BITS_LOW),
79 FRAC_HALF_LOW = (1L << (FRAC_BITS_LOW-1))
80 };
81
82 /**
83 * Audio rate converter based on simple resampling. Used when no
84 * interpolation is required.
85 *
86 * Limited to sampling frequency <= 65535 Hz.
87 */
88 typedef struct {
89 const st_sample_t *inPtr;
90 int inLen;
91
92 /** position of how far output is ahead of input */
93 /** Holds what would have been opos-ipos */
94 long opos;
95
96 /** fractional position increment in the output stream */
97 long opos_inc;
98
99 st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
100 } SimpleRateDetails;
101
102 template<bool stereo, bool reverseStereo>
103 class SimpleRateConverter : public RateConverter {
104 protected:
105 SimpleRateDetails sr;
106 public:
107 SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
108 int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
drain(st_sample_t * obuf,st_size_t osamp,st_volume_t vol)109 int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
110 return (ST_SUCCESS);
111 }
112 };
113
114
115 /*
116 * Prepare processing.
117 */
118 template<bool stereo, bool reverseStereo>
SimpleRateConverter(st_rate_t inrate,st_rate_t outrate)119 SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
120 if (inrate == outrate) {
121 error("Input and Output rates must be different to use rate effect");
122 }
123
124 if ((inrate % outrate) != 0) {
125 error("Input rate must be a multiple of Output rate to use rate effect");
126 }
127
128 if (inrate >= 65536 || outrate >= 65536) {
129 error("rate effect can only handle rates < 65536");
130 }
131
132 sr.opos = 1;
133
134 /* increment */
135 sr.opos_inc = inrate / outrate;
136
137 sr.inLen = 0;
138 }
139
140 #ifndef IPHONE
141 #define ARM_SimpleRate_M _ARM_SimpleRate_M
142 #define ARM_SimpleRate_S _ARM_SimpleRate_S
143 #define ARM_SimpleRate_R _ARM_SimpleRate_R
144 #endif
145
146 extern "C" st_sample_t *ARM_SimpleRate_M(
147 AudioStream &input,
148 int (*fn)(Audio::AudioStream&,int16*,int),
149 SimpleRateDetails *sr,
150 st_sample_t *obuf,
151 st_size_t osamp,
152 st_volume_t vol_l,
153 st_volume_t vol_r);
154
155 extern "C" st_sample_t *ARM_SimpleRate_S(
156 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);
163
164 extern "C" st_sample_t *ARM_SimpleRate_R(
165 AudioStream &input,
166 int (*fn)(Audio::AudioStream&,int16*,int),
167 SimpleRateDetails *sr,
168 st_sample_t *obuf,
169 st_size_t osamp,
170 st_volume_t vol_l,
171 st_volume_t vol_r);
172
SimpleRate_readFudge(Audio::AudioStream & input,int16 * a,int b)173 extern "C" int SimpleRate_readFudge(Audio::AudioStream &input, int16 *a, int b)
174 {
175 #ifdef DEBUG_RATECONV
176 debug("Reading ptr=%x n%d", a, b);
177 #endif
178 return input.readBuffer(a, b);
179 }
180
181 template<bool stereo, bool reverseStereo>
flow(AudioStream & input,st_sample_t * obuf,st_size_t osamp,st_volume_t vol_l,st_volume_t vol_r)182 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) {
183
184 #ifdef DEBUG_RATECONV
185 debug("Simple st=%d rev=%d", stereo, reverseStereo);
186 #endif
187 st_sample_t *ostart = obuf;
188
189 if (!stereo) {
190 obuf = ARM_SimpleRate_M(input,
191 &SimpleRate_readFudge,
192 &sr,
193 obuf, osamp, vol_l, vol_r);
194 } else if (reverseStereo) {
195 obuf = ARM_SimpleRate_R(input,
196 &SimpleRate_readFudge,
197 &sr,
198 obuf, osamp, vol_l, vol_r);
199 } else {
200 obuf = ARM_SimpleRate_S(input,
201 &SimpleRate_readFudge,
202 &sr,
203 obuf, osamp, vol_l, vol_r);
204 }
205
206 return (obuf - ostart) / 2;
207 }
208
209 /**
210 * Audio rate converter based on simple linear Interpolation.
211 *
212 * The use of fractional increment allows us to use no buffer. It
213 * avoid the problems at the end of the buffer we had with the old
214 * method which stored a possibly big buffer of size
215 * lcm(in_rate,out_rate).
216 *
217 * Limited to sampling frequency <= 65535 Hz.
218 */
219
220 typedef struct {
221 const st_sample_t *inPtr;
222 int inLen;
223
224 /** position of how far output is ahead of input */
225 /** Holds what would have been opos-ipos<<16 + opos_frac */
226 long opos;
227
228 /** integer position increment in the output stream */
229 long opos_inc;
230
231 /** current sample(s) in the input stream (left/right channel) */
232 st_sample_t icur[2];
233 /** last sample(s) in the input stream (left/right channel) */
234 /** Note, these are deliberately ints, not st_sample_t's */
235 int32 ilast[2];
236
237 st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
238 } LinearRateDetails;
239
240 extern "C" {
241 #ifndef IPHONE
242 #define ARM_LinearRate_M _ARM_LinearRate_M
243 #define ARM_LinearRate_S _ARM_LinearRate_S
244 #define ARM_LinearRate_R _ARM_LinearRate_R
245 #endif
246 }
247
248 extern "C" st_sample_t *ARM_LinearRate_M(
249 AudioStream &input,
250 int (*fn)(Audio::AudioStream&,int16*,int),
251 LinearRateDetails *lr,
252 st_sample_t *obuf,
253 st_size_t osamp,
254 st_volume_t vol_l,
255 st_volume_t vol_r);
256
257 extern "C" st_sample_t *ARM_LinearRate_S(
258 AudioStream &input,
259 int (*fn)(Audio::AudioStream&,int16*,int),
260 LinearRateDetails *lr,
261 st_sample_t *obuf,
262 st_size_t osamp,
263 st_volume_t vol_l,
264 st_volume_t vol_r);
265
266 extern "C" st_sample_t *ARM_LinearRate_R(
267 AudioStream &input,
268 int (*fn)(Audio::AudioStream&,int16*,int),
269 LinearRateDetails *lr,
270 st_sample_t *obuf,
271 st_size_t osamp,
272 st_volume_t vol_l,
273 st_volume_t vol_r);
274
275 template<bool stereo, bool reverseStereo>
276 class LinearRateConverter : public RateConverter {
277 protected:
278 LinearRateDetails lr;
279
280 public:
281 LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
282 int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
drain(st_sample_t * obuf,st_size_t osamp,st_volume_t vol)283 int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
284 return (ST_SUCCESS);
285 }
286 };
287
288
289 /*
290 * Prepare processing.
291 */
292 template<bool stereo, bool reverseStereo>
LinearRateConverter(st_rate_t inrate,st_rate_t outrate)293 LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
294 unsigned long incr;
295
296 if (inrate == outrate) {
297 error("Input and Output rates must be different to use rate effect");
298 }
299
300 if (inrate >= 131072 || outrate >= 131072) {
301 error("rate effect can only handle rates < 131072");
302 }
303
304 lr.opos = FRAC_ONE_LOW;
305
306 /* increment */
307 incr = (inrate << FRAC_BITS_LOW) / outrate;
308
309 lr.opos_inc = incr;
310
311 // FIXME: Does 32768 here need changing to 65536 or 0? Compare to rate.cpp code...
312 lr.ilast[0] = lr.ilast[1] = 32768;
313 lr.icur[0] = lr.icur[1] = 0;
314
315 lr.inLen = 0;
316 }
317
318 /*
319 * Processed signed long samples from ibuf to obuf.
320 * Return number of sample pairs processed.
321 */
322 template<bool stereo, bool reverseStereo>
flow(AudioStream & input,st_sample_t * obuf,st_size_t osamp,st_volume_t vol_l,st_volume_t vol_r)323 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) {
324
325 #ifdef DEBUG_RATECONV
326 debug("Linear st=%d rev=%d", stereo, reverseStereo);
327 #endif
328 st_sample_t *ostart = obuf;
329
330 if (vol_l > 0xff)
331 vol_l = 0xff;
332
333 if (vol_r > 0xff)
334 vol_r = 0xff;
335
336 if (!stereo) {
337 obuf = ARM_LinearRate_M(input,
338 &SimpleRate_readFudge,
339 &lr,
340 obuf, osamp, vol_l, vol_r);
341 } else if (reverseStereo) {
342 obuf = ARM_LinearRate_R(input,
343 &SimpleRate_readFudge,
344 &lr,
345 obuf, osamp, vol_l, vol_r);
346 } else {
347 obuf = ARM_LinearRate_S(input,
348 &SimpleRate_readFudge,
349 &lr,
350 obuf, osamp, vol_l, vol_r);
351 }
352 return (obuf - ostart) / 2;
353 }
354
355
356 #pragma mark -
357
358
359 /**
360 * Simple audio rate converter for the case that the inrate equals the outrate.
361 */
362 extern "C" {
363 #ifndef IPHONE
364 #define ARM_CopyRate_M _ARM_CopyRate_M
365 #define ARM_CopyRate_S _ARM_CopyRate_S
366 #define ARM_CopyRate_R _ARM_CopyRate_R
367 #endif
368 }
369
370 extern "C" st_sample_t *ARM_CopyRate_M(
371 st_size_t len,
372 st_sample_t *obuf,
373 st_volume_t vol_l,
374 st_volume_t vol_r,
375 st_sample_t *_buffer);
376
377 extern "C" st_sample_t *ARM_CopyRate_S(
378 st_size_t len,
379 st_sample_t *obuf,
380 st_volume_t vol_l,
381 st_volume_t vol_r,
382 st_sample_t *_buffer);
383
384 extern "C" st_sample_t *ARM_CopyRate_R(
385 st_size_t len,
386 st_sample_t *obuf,
387 st_volume_t vol_l,
388 st_volume_t vol_r,
389 st_sample_t *_buffer);
390
391
392 template<bool stereo, bool reverseStereo>
393 class CopyRateConverter : public RateConverter {
394 st_sample_t *_buffer;
395 st_size_t _bufferSize;
396
397 public:
CopyRateConverter()398 CopyRateConverter() : _buffer(0), _bufferSize(0) {}
~CopyRateConverter()399 ~CopyRateConverter() {
400 free(_buffer);
401 }
402
flow(AudioStream & input,st_sample_t * obuf,st_size_t osamp,st_volume_t vol_l,st_volume_t vol_r)403 virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
404 assert(input.isStereo() == stereo);
405
406 #ifdef DEBUG_RATECONV
407 debug("Copy st=%d rev=%d", stereo, reverseStereo);
408 #endif
409 st_size_t len;
410 st_sample_t *ostart = obuf;
411
412 if (stereo)
413 osamp *= 2;
414
415 // Reallocate temp buffer, if necessary
416 if (osamp > _bufferSize) {
417 free(_buffer);
418 _buffer = (st_sample_t *)malloc(osamp * 2);
419 _bufferSize = osamp;
420 }
421
422 // Read up to 'osamp' samples into our temporary buffer
423 len = input.readBuffer(_buffer, osamp);
424 if (len <= 0)
425 return 0;
426
427 // Mix the data into the output buffer
428 if (stereo && reverseStereo)
429 obuf = ARM_CopyRate_R(len, obuf, vol_l, vol_r, _buffer);
430 else if (stereo)
431 obuf = ARM_CopyRate_S(len, obuf, vol_l, vol_r, _buffer);
432 else
433 obuf = ARM_CopyRate_M(len, obuf, vol_l, vol_r, _buffer);
434
435 return (obuf - ostart) / 2;
436 }
437
drain(st_sample_t * obuf,st_size_t osamp,st_volume_t vol)438 virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
439 return (ST_SUCCESS);
440 }
441 };
442
443
444 #pragma mark -
445
446
447 /**
448 * Create and return a RateConverter object for the specified input and output rates.
449 */
makeRateConverter(st_rate_t inrate,st_rate_t outrate,bool stereo,bool reverseStereo)450 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
451 if (inrate != outrate) {
452 if ((inrate % outrate) == 0 && (inrate < 65536)) {
453 if (stereo) {
454 if (reverseStereo)
455 return new SimpleRateConverter<true, true>(inrate, outrate);
456 else
457 return new SimpleRateConverter<true, false>(inrate, outrate);
458 } else
459 return new SimpleRateConverter<false, false>(inrate, outrate);
460 } else {
461 if (stereo) {
462 if (reverseStereo)
463 return new LinearRateConverter<true, true>(inrate, outrate);
464 else
465 return new LinearRateConverter<true, false>(inrate, outrate);
466 } else
467 return new LinearRateConverter<false, false>(inrate, outrate);
468 }
469 } else {
470 if (stereo) {
471 if (reverseStereo)
472 return new CopyRateConverter<true, true>();
473 else
474 return new CopyRateConverter<true, false>();
475 } else
476 return new CopyRateConverter<false, false>();
477 }
478 }
479
480 } // End of namespace Audio
481