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 is based on code with Copyright 1998 Fabrice Bellard
28 * Fabrice original code is part of SoX (http://sox.sourceforge.net).
29 * Max Horn adapted that code to the needs of ScummVM and rewrote it partial,
30 * in the process removing any use of floating point arithmetic. Various other
31 * improvments over the original code were made.
34 #include "sound/audiostream.h"
35 #include "sound/rate.h"
36 #include "sound/mixer.h"
37 #include "common/frac.h"
38 #include "common/util.h"
44 * The size of the intermediate input cache. Bigger values may increase
45 * performance, but only until some point (depends largely on cache size,
46 * target processor and various other factors), at which it will decrease
49 #define INTERMEDIATE_BUFFER_SIZE 512
53 * Audio rate converter based on simple resampling. Used when no
54 * interpolation is required.
56 * Limited to sampling frequency <= 65535 Hz.
58 template<bool stereo
, bool reverseStereo
>
59 class SimpleRateConverter
: public RateConverter
{
61 st_sample_t inBuf
[INTERMEDIATE_BUFFER_SIZE
];
62 const st_sample_t
*inPtr
;
65 /** position of how far output is ahead of input */
66 /** Holds what would have been opos-ipos */
69 /** fractional position increment in the output stream */
73 SimpleRateConverter(st_rate_t inrate
, st_rate_t outrate
);
74 int flow(AudioStream
&input
, st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol_l
, st_volume_t vol_r
);
75 int drain(st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol
) {
84 template<bool stereo
, bool reverseStereo
>
85 SimpleRateConverter
<stereo
, reverseStereo
>::SimpleRateConverter(st_rate_t inrate
, st_rate_t outrate
) {
86 if ((inrate
% outrate
) != 0) {
87 error("Input rate must be a multiple of output rate to use rate effect");
90 if (inrate
>= 65536 || outrate
>= 65536) {
91 error("rate effect can only handle rates < 65536");
97 opos_inc
= inrate
/ outrate
;
103 * Processed signed long samples from ibuf to obuf.
104 * Return number of samples processed.
106 template<bool stereo
, bool reverseStereo
>
107 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
) {
108 st_sample_t
*ostart
, *oend
;
111 oend
= obuf
+ osamp
* 2;
113 while (obuf
< oend
) {
115 // read enough input samples so that opos >= 0
117 // Check if we have to refill the buffer
120 inLen
= input
.readBuffer(inBuf
, ARRAYSIZE(inBuf
));
124 inLen
-= (stereo
? 2 : 1);
127 inPtr
+= (stereo
? 2 : 1);
131 st_sample_t out0
, out1
;
133 out1
= (stereo
? *inPtr
++ : out0
);
135 // Increment output position
138 // output left channel
139 clampedAdd(obuf
[reverseStereo
], (out0
* (int)vol_l
) / Audio::Mixer::kMaxMixerVolume
);
141 // output right channel
142 clampedAdd(obuf
[reverseStereo
^ 1], (out1
* (int)vol_r
) / Audio::Mixer::kMaxMixerVolume
);
150 * Audio rate converter based on simple linear Interpolation.
152 * The use of fractional increment allows us to use no buffer. It
153 * avoid the problems at the end of the buffer we had with the old
154 * method which stored a possibly big buffer of size
155 * lcm(in_rate,out_rate).
157 * Limited to sampling frequency <= 65535 Hz.
160 template<bool stereo
, bool reverseStereo
>
161 class LinearRateConverter
: public RateConverter
{
163 st_sample_t inBuf
[INTERMEDIATE_BUFFER_SIZE
];
164 const st_sample_t
*inPtr
;
167 /** fractional position of the output stream in input stream unit */
170 /** fractional position increment in the output stream */
173 /** last sample(s) in the input stream (left/right channel) */
174 st_sample_t ilast0
, ilast1
;
175 /** current sample(s) in the input stream (left/right channel) */
176 st_sample_t icur0
, icur1
;
179 LinearRateConverter(st_rate_t inrate
, st_rate_t outrate
);
180 int flow(AudioStream
&input
, st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol_l
, st_volume_t vol_r
);
181 int drain(st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol
) {
188 * Prepare processing.
190 template<bool stereo
, bool reverseStereo
>
191 LinearRateConverter
<stereo
, reverseStereo
>::LinearRateConverter(st_rate_t inrate
, st_rate_t outrate
) {
192 if (inrate
>= 65536 || outrate
>= 65536) {
193 error("rate effect can only handle rates < 65536");
198 // Compute the linear interpolation increment.
199 // This will overflow if inrate >= 2^16, and underflow if outrate >= 2^16.
200 // Also, if the quotient of the two rate becomes too small / too big, that
201 // would cause problems, but since we rarely scale from 1 to 65536 Hz or vice
202 // versa, I think we can live with that limiation ;-).
203 opos_inc
= (inrate
<< FRAC_BITS
) / outrate
;
212 * Processed signed long samples from ibuf to obuf.
213 * Return number of samples processed.
215 template<bool stereo
, bool reverseStereo
>
216 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
) {
217 st_sample_t
*ostart
, *oend
;
220 oend
= obuf
+ osamp
* 2;
222 while (obuf
< oend
) {
224 // read enough input samples so that opos < 0
225 while ((frac_t
)FRAC_ONE
<= opos
) {
226 // Check if we have to refill the buffer
229 inLen
= input
.readBuffer(inBuf
, ARRAYSIZE(inBuf
));
233 inLen
-= (stereo
? 2 : 1);
243 // Loop as long as the outpos trails behind, and as long as there is
244 // still space in the output buffer.
245 while (opos
< (frac_t
)FRAC_ONE
&& obuf
< oend
) {
247 st_sample_t out0
, out1
;
248 out0
= (st_sample_t
)(ilast0
+ (((icur0
- ilast0
) * opos
+ FRAC_HALF
) >> FRAC_BITS
));
250 (st_sample_t
)(ilast1
+ (((icur1
- ilast1
) * opos
+ FRAC_HALF
) >> FRAC_BITS
)) :
253 // output left channel
254 clampedAdd(obuf
[reverseStereo
], (out0
* (int)vol_l
) / Audio::Mixer::kMaxMixerVolume
);
256 // output right channel
257 clampedAdd(obuf
[reverseStereo
^ 1], (out1
* (int)vol_r
) / Audio::Mixer::kMaxMixerVolume
);
261 // Increment output position
273 * Simple audio rate converter for the case that the inrate equals the outrate.
275 template<bool stereo
, bool reverseStereo
>
276 class CopyRateConverter
: public RateConverter
{
277 st_sample_t
*_buffer
;
278 st_size_t _bufferSize
;
280 CopyRateConverter() : _buffer(0), _bufferSize(0) {}
281 ~CopyRateConverter() {
285 virtual int flow(AudioStream
&input
, st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol_l
, st_volume_t vol_r
) {
286 assert(input
.isStereo() == stereo
);
294 // Reallocate temp buffer, if necessary
295 if (osamp
> _bufferSize
) {
297 _buffer
= (st_sample_t
*)malloc(osamp
* 2);
301 // Read up to 'osamp' samples into our temporary buffer
302 len
= input
.readBuffer(_buffer
, osamp
);
304 // Mix the data into the output buffer
306 for (; len
> 0; len
-= (stereo
? 2 : 1)) {
307 st_sample_t out0
, out1
;
309 out1
= (stereo
? *ptr
++ : out0
);
311 // output left channel
312 clampedAdd(obuf
[reverseStereo
], (out0
* (int)vol_l
) / Audio::Mixer::kMaxMixerVolume
);
314 // output right channel
315 clampedAdd(obuf
[reverseStereo
^ 1], (out1
* (int)vol_r
) / Audio::Mixer::kMaxMixerVolume
);
322 virtual int drain(st_sample_t
*obuf
, st_size_t osamp
, st_volume_t vol
) {
330 template<bool stereo
, bool reverseStereo
>
331 RateConverter
*makeRateConverter(st_rate_t inrate
, st_rate_t outrate
) {
332 if (inrate
!= outrate
) {
333 if ((inrate
% outrate
) == 0) {
334 return new SimpleRateConverter
<stereo
, reverseStereo
>(inrate
, outrate
);
336 return new LinearRateConverter
<stereo
, reverseStereo
>(inrate
, outrate
);
339 return new CopyRateConverter
<stereo
, reverseStereo
>();
344 * Create and return a RateConverter object for the specified input and output rates.
346 RateConverter
*makeRateConverter(st_rate_t inrate
, st_rate_t outrate
, bool stereo
, bool reverseStereo
) {
349 return makeRateConverter
<true, true>(inrate
, outrate
);
351 return makeRateConverter
<true, false>(inrate
, outrate
);
353 return makeRateConverter
<false, false>(inrate
, outrate
);
356 } // End of namespace Audio