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.
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
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.
63 #define FRAC_ONE (1<<FRAC_BITS)
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
71 #define INTERMEDIATE_BUFFER_SIZE 512
75 * Audio rate converter based on simple resampling. Used when no
76 * interpolation is required.
78 * Limited to sampling frequency <= 65535 Hz.
81 const st_sample_t
*inPtr
;
84 /** position of how far output is ahead of input */
85 /** Holds what would have been opos-ipos */
88 /** fractional position increment in the output stream */
91 st_sample_t inBuf
[INTERMEDIATE_BUFFER_SIZE
];
94 template<bool stereo
, bool reverseStereo
>
95 class SimpleRateConverter
: public RateConverter
{
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
) {
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");
127 sr
.opos_inc
= inrate
/ outrate
;
134 #define ARM_SimpleRate_M _ARM_SimpleRate_M
135 #define ARM_SimpleRate_S _ARM_SimpleRate_S
136 #define ARM_SimpleRate_R _ARM_SimpleRate_R
140 extern "C" void ARM_SimpleRate_M(AudioStream
&input
,
141 int (*fn
)(Audio::AudioStream
&,int16
*,int),
142 SimpleRateDetails
*sr
,
148 extern "C" void ARM_SimpleRate_S(AudioStream
&input
,
149 int (*fn
)(Audio::AudioStream
&,int16
*,int),
150 SimpleRateDetails
*sr
,
156 extern "C" void ARM_SimpleRate_R(AudioStream
&input
,
157 int (*fn
)(Audio::AudioStream
&,int16
*,int),
158 SimpleRateDetails
*sr
,
164 extern "C" int SimpleRate_readFudge(Audio::AudioStream
&input
,
167 #ifdef DEBUG_RATECONV
168 fprintf(stderr
, "Reading ptr=%x n%d\n", a
, b
);
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
);
182 ARM_SimpleRate_M(input
,
183 &SimpleRate_readFudge
,
185 obuf
, osamp
, vol_l
, vol_r
);
186 } else if (reverseStereo
) {
187 ARM_SimpleRate_R(input
,
188 &SimpleRate_readFudge
,
190 obuf
, osamp
, vol_l
, vol_r
);
192 ARM_SimpleRate_S(input
,
193 &SimpleRate_readFudge
,
195 obuf
, osamp
, vol_l
, vol_r
);
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.
212 const st_sample_t
*inPtr
;
215 /** position of how far output is ahead of input */
216 /** Holds what would have been opos-ipos<<16 + opos_frac */
219 /** integer position increment in the output stream */
222 /** current sample(s) in the input stream (left/right channel) */
224 /** last sample(s) in the input stream (left/right channel) */
225 /** Note, these are deliberately ints, not st_sample_t's */
228 st_sample_t inBuf
[INTERMEDIATE_BUFFER_SIZE
];
233 #define ARM_LinearRate_M _ARM_LinearRate_M
234 #define ARM_LinearRate_S _ARM_LinearRate_S
235 #define ARM_LinearRate_R _ARM_LinearRate_R
239 extern "C" void ARM_LinearRate_M(AudioStream
&input
,
240 int (*fn
)(Audio::AudioStream
&,int16
*,int),
241 LinearRateDetails
*lr
,
247 extern "C" void ARM_LinearRate_S(AudioStream
&input
,
248 int (*fn
)(Audio::AudioStream
&,int16
*,int),
249 LinearRateDetails
*lr
,
255 extern "C" void ARM_LinearRate_R(AudioStream
&input
,
256 int (*fn
)(Audio::AudioStream
&,int16
*,int),
257 LinearRateDetails
*lr
,
263 template<bool stereo
, bool reverseStereo
>
264 class LinearRateConverter
: public RateConverter
{
266 LinearRateDetails lr
;
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
) {
278 * Prepare processing.
280 template<bool stereo
, bool reverseStereo
>
281 LinearRateConverter
<stereo
, reverseStereo
>::LinearRateConverter(st_rate_t inrate
, st_rate_t outrate
) {
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");
295 incr
= (inrate
<< FRAC_BITS
) / outrate
;
299 lr
.ilast
[0] = lr
.ilast
[1] = 32768;
300 lr
.icur
[0] = lr
.icur
[1] = 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
);
317 ARM_LinearRate_M(input
,
318 &SimpleRate_readFudge
,
320 obuf
, osamp
, vol_l
, vol_r
);
321 } else if (reverseStereo
) {
322 ARM_LinearRate_R(input
,
323 &SimpleRate_readFudge
,
325 obuf
, osamp
, vol_l
, vol_r
);
327 ARM_LinearRate_S(input
,
328 &SimpleRate_readFudge
,
330 obuf
, osamp
, vol_l
, vol_r
);
340 * Simple audio rate converter for the case that the inrate equals the outrate.
344 #define ARM_CopyRate_M _ARM_CopyRate_M
345 #define ARM_CopyRate_S _ARM_CopyRate_S
346 #define ARM_CopyRate_R _ARM_CopyRate_R
350 extern "C" void ARM_CopyRate_M(st_size_t len
,
354 st_sample_t
*_buffer
);
356 extern "C" void ARM_CopyRate_S(st_size_t len
,
360 st_sample_t
*_buffer
);
362 extern "C" void ARM_CopyRate_R(st_size_t len
,
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
;
374 CopyRateConverter() : _buffer(0), _bufferSize(0) {}
375 ~CopyRateConverter() {
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
);
391 // Reallocate temp buffer, if necessary
392 if (osamp
> _bufferSize
) {
394 _buffer
= (st_sample_t
*)malloc(osamp
* 2);
398 // Read up to 'osamp' samples into our temporary buffer
399 len
= input
.readBuffer(_buffer
, osamp
);
403 // Mix the data into the output buffer
404 if (stereo
&& reverseStereo
)
405 ARM_CopyRate_R(len
, obuf
, vol_l
, vol_r
, _buffer
);
407 ARM_CopyRate_S(len
, obuf
, vol_l
, vol_r
, _buffer
);
409 ARM_CopyRate_M(len
, obuf
, vol_l
, vol_r
, _buffer
);
413 virtual int drain(st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol
) {
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) {
430 return new SimpleRateConverter
<true, true>(inrate
, outrate
);
432 return new SimpleRateConverter
<true, false>(inrate
, outrate
);
434 return new SimpleRateConverter
<false, false>(inrate
, outrate
);
438 return new LinearRateConverter
<true, true>(inrate
, outrate
);
440 return new LinearRateConverter
<true, false>(inrate
, outrate
);
442 return new LinearRateConverter
<false, false>(inrate
, outrate
);
447 return new CopyRateConverter
<true, true>();
449 return new CopyRateConverter
<true, false>();
451 return new CopyRateConverter
<false, false>();
455 } // End of namespace Audio