1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 // audio_buffer_tools.h
33 // eamoon@meadgroup.com
34 //
35 // Some straightforward audio buffer-handling routines
36
37 #ifndef __AUDIO_BUFFER_TOOLS_H__
38 #define __AUDIO_BUFFER_TOOLS_H__
39
40 #include <ByteOrder.h>
41 #include <Debug.h>
42
43 // ---------------------------------------------------------------- //
44 // sample conversion +++++
45 // 31mar99: providing conversion to and from float, and defining
46 // other conversions based on that.
47 // ---------------------------------------------------------------- //
48
49 /*
50 template<class from_sample_t, class to_sample_t>
51 void convert_sample(from_sample_t in, to_sample_t& out) {
52 out = (to_sample_t)in; // +++++ arbitrary conversion stub
53 }
54 */
55
convert_sample(float & in,float & out)56 inline void convert_sample(float& in, float& out) {
57 out = in;
58 }
59
convert_sample(uchar & in,float & out)60 inline void convert_sample(uchar& in, float& out) {
61 out = (float)(in - 128) / 127.0;
62 }
63
convert_sample(short & in,float & out)64 inline void convert_sample(short& in, float& out) {
65 out = (float)in / 32767.0;
66 }
67
convert_sample(int32 & in,float & out)68 inline void convert_sample(int32& in, float& out) {
69 out = (float)in / (float)0x7fffffff;
70 }
71
convert_sample(float & in,uchar & out)72 inline void convert_sample(float& in, uchar& out) {
73 out = (uchar)(in * 127.0);
74 }
75
convert_sample(float & in,short & out)76 inline void convert_sample(float& in, short& out) {
77 out = (short)(in * 32767.0);
78 }
79
convert_sample(float & in,int32 & out)80 inline void convert_sample(float& in, int32& out) {
81 out = (int32)(in * 0x7fffffff);
82 }
83
swap_convert_sample(float & in,float & out)84 inline void swap_convert_sample(float& in, float& out) {
85 out = B_SWAP_FLOAT(in);
86 }
87
swap_convert_sample(uchar & in,float & out)88 inline void swap_convert_sample(uchar& in, float& out) {
89 // no swap needed for char
90 out = (float)(in - 128) / 127.0;
91 }
92
swap_convert_sample(short & in,float & out)93 inline void swap_convert_sample(short& in, float& out) {
94 out = (float)(int16)(B_SWAP_INT16(in)) / 32767.0;
95 }
96
swap_convert_sample(int32 & in,float & out)97 inline void swap_convert_sample(int32& in, float& out) {
98 out = (float)(int32)(B_SWAP_INT32(in)) / (float)0x7fffffff;
99 }
100
swap_convert_sample(float & in,uchar & out)101 inline void swap_convert_sample(float& in, uchar& out) {
102 out = (uchar)((B_SWAP_FLOAT(in)) * 127.0);
103 }
104
swap_convert_sample(float & in,short & out)105 inline void swap_convert_sample(float& in, short& out) {
106 out = (short)((B_SWAP_FLOAT(in)) * 32767.0);
107 }
108
swap_convert_sample(float & in,int32 & out)109 inline void swap_convert_sample(float& in, int32& out) {
110 out = (int32)((B_SWAP_FLOAT(in)) * 0x7fffffff);
111 }
112
113
114 template<class to_sample_t>
convert_sample(void * pIn,to_sample_t & out,int32 in_audio_format)115 inline void convert_sample(void* pIn, to_sample_t& out, int32 in_audio_format) {
116 switch(in_audio_format) {
117 case media_raw_audio_format::B_AUDIO_UCHAR:
118 convert_sample(*(uchar*)pIn, out);
119 break;
120 case media_raw_audio_format::B_AUDIO_SHORT:
121 convert_sample(*(short*)pIn, out);
122 break;
123 case media_raw_audio_format::B_AUDIO_FLOAT:
124 convert_sample(*(float*)pIn, out);
125 break;
126 case media_raw_audio_format::B_AUDIO_INT:
127 convert_sample(*(int32*)pIn, out);
128 break;
129 default:
130 ASSERT(!"convert_sample(): bad raw_audio_format value");
131 }
132 }
133
134 template<class from_sample_t>
convert_sample(from_sample_t in,void * pOut,int32 out_audio_format)135 inline void convert_sample(from_sample_t in, void* pOut, int32 out_audio_format) {
136 switch(out_audio_format) {
137 case media_raw_audio_format::B_AUDIO_UCHAR:
138 convert_sample(in, *(uchar*)pOut);
139 break;
140 case media_raw_audio_format::B_AUDIO_SHORT:
141 convert_sample(in, *(short*)pOut);
142 break;
143 case media_raw_audio_format::B_AUDIO_FLOAT:
144 convert_sample(in, *(float*)pOut);
145 break;
146 case media_raw_audio_format::B_AUDIO_INT:
147 convert_sample(in, *(int32*)pOut);
148 break;
149 default:
150 ASSERT(!"convert_sample(): bad raw_audio_format value");
151 }
152 }
153
convert_sample(void * pIn,void * pOut,int32 in_audio_format,int32 out_audio_format)154 inline void convert_sample(void* pIn, void* pOut,
155 int32 in_audio_format, int32 out_audio_format) {
156
157 // simplest case
158 if(in_audio_format == out_audio_format)
159 return;
160
161 // one-step cases
162 if(in_audio_format == media_raw_audio_format::B_AUDIO_FLOAT)
163 convert_sample(*(float*)pIn, pOut, out_audio_format);
164
165 else if(out_audio_format == media_raw_audio_format::B_AUDIO_FLOAT)
166 convert_sample(pOut, *(float*)pIn, in_audio_format);
167
168 else {
169 // two-step cases
170 float fTemp = 0;
171 convert_sample(pIn, fTemp, in_audio_format);
172 convert_sample(fTemp, pOut, out_audio_format);
173 }
174 }
175
176 // ---------------------------------------------------------------- //
177 // data-copying helper templates
178 // ---------------------------------------------------------------- //
179
180 // copy from linear buffer to circular buffer; no rescaling
181 // returns new offset into destination buffer
182
183 template<class from_sample_t, class to_sample_t>
copy_linear_to_circular(from_sample_t * pFrom,to_sample_t * pTo,size_t samples,size_t toOffset,size_t toLength)184 inline size_t copy_linear_to_circular(
185 from_sample_t* pFrom,
186 to_sample_t* pTo,
187 size_t samples, size_t toOffset, size_t toLength) {
188
189 ASSERT(pFrom != 0);
190 ASSERT(pTo != 0);
191 ASSERT(samples > 0);
192 ASSERT(toLength > 0);
193 ASSERT(toOffset < toLength);
194
195 size_t n = toOffset;
196 for(; samples; samples--) {
197 pTo[n] = (to_sample_t)*pFrom++;
198 if(++n >= toLength)
199 n = 0;
200 }
201
202 return n;
203 }
204
205 // copy from a linear buffer in one sample format to a circular buffer
206 // in another, delegating rescaling duties to convert_sample().
207 // returns new offset into destination buffer
208
209 template<class from_sample_t, class to_sample_t>
copy_linear_to_circular_convert(from_sample_t * pFrom,to_sample_t * pTo,size_t samples,size_t toOffset,size_t toLength)210 inline size_t copy_linear_to_circular_convert(
211 from_sample_t* pFrom,
212 to_sample_t* pTo,
213 size_t samples, size_t toOffset, size_t toLength) {
214
215 ASSERT(pFrom != 0);
216 ASSERT(pTo != 0);
217 ASSERT(samples > 0);
218 ASSERT(toLength > 0);
219 ASSERT(toOffset < toLength);
220
221 size_t n = toOffset;
222 for(; samples; samples--) {
223 convert_sample(*pFrom++, pTo[n]);
224 if(++n >= toLength)
225 n = 0;
226 }
227
228 return n;
229 }
230
231 // copy from linear buffer to circular buffer; no rescaling
232 // returns new offset into source buffer
233
234 template<class from_sample_t, class to_sample_t>
copy_circular_to_linear(from_sample_t * pFrom,to_sample_t * pTo,size_t samples,size_t fromOffset,size_t fromLength)235 inline size_t copy_circular_to_linear(
236 from_sample_t* pFrom,
237 to_sample_t* pTo,
238 size_t samples, size_t fromOffset, size_t fromLength) {
239
240 ASSERT(pFrom != 0);
241 ASSERT(pTo != 0);
242 ASSERT(samples > 0);
243 ASSERT(fromLength > 0);
244 ASSERT(fromOffset < fromLength);
245
246 size_t n = fromOffset;
247 for(; samples; samples--) {
248 *pTo++ = (to_sample_t)pFrom[n];
249 if(++n >= fromLength)
250 n = 0;
251 }
252
253 return n;
254 }
255
256 // copy from a circular buffer in one sample format to a linear buffer
257 // in another, delegating rescaling duties to convert_sample().
258 // returns new offset into source buffer
259
260 template<class from_sample_t, class to_sample_t>
copy_circular_to_linear_convert(from_sample_t * pFrom,to_sample_t * pTo,size_t samples,size_t fromOffset,size_t fromLength)261 inline size_t copy_circular_to_linear_convert(
262 from_sample_t* pFrom,
263 to_sample_t* pTo,
264 size_t samples, size_t fromOffset, size_t fromLength) {
265
266 ASSERT(pFrom != 0);
267 ASSERT(pTo != 0);
268 ASSERT(samples > 0);
269 ASSERT(fromLength > 0);
270 ASSERT(fromOffset < fromLength);
271
272 size_t n = fromOffset;
273 for(; samples; samples--) {
274 convert_sample(pFrom[n], *pTo++);
275 if(++n >= fromLength)
276 n = 0;
277 }
278
279 return n;
280 }
281
282 //// copy between circular buffers in the same format
283 //// +++++ re-templatize
284 //
285 ///*template<class samp_t>
286 //inline*/ void copy_circular_to_circular(
287 // sample_t* pFrom,
288 // sample_t* pTo,
289 // size_t samples,
290 // size_t& ioFromOffset, size_t fromLength,
291 // size_t& ioToOffset, size_t toLength);
292
293 // mix from a linear buffer to a circular buffer (no rescaling)
294 // input samples are multiplied by fSourceGain; destination samples
295 // are multiplied by fFeedback
296 // returns new offset within destination buffer
297
298 template<class from_sample_t, class to_sample_t>
mix_linear_to_circular(from_sample_t * pFrom,to_sample_t * pTo,uint32 samples,uint32 toOffset,uint32 toLength,float fSourceGain,float fFeedback)299 inline size_t mix_linear_to_circular(
300 from_sample_t* pFrom,
301 to_sample_t* pTo,
302 uint32 samples,
303 uint32 toOffset,
304 uint32 toLength,
305 float fSourceGain,
306 float fFeedback) {
307
308 // feedback
309 size_t n, nLength;
310 if(fFeedback == 0.0) // +++++ memset?
311 for(n = toOffset, nLength = samples;
312 nLength;
313 n = (n+1 == toLength) ? 0 : n+1, nLength--) { pTo[n] = 0.0; }
314 else if(fFeedback != 1.0)
315 for(n = toOffset, nLength = samples;
316 nLength;
317 n = (n+1 == toLength) ? 0 : n+1, nLength--) { pTo[n] *= fFeedback; }
318 // else nothing to do
319
320 // mix source, unless muted or not provided
321 if(pFrom && fSourceGain != 0.0) {
322 if(fSourceGain == 1.0)
323 for(n = toOffset, nLength = samples;
324 nLength;
325 n = (n+1 == toLength) ? 0 : n+1, nLength--) {
326 pTo[n] += (to_sample_t)*pFrom++;
327 }
328 else
329 for(n = toOffset, nLength = samples;
330 nLength;
331 n = (n+1 == toLength) ? 0 : n+1, nLength--) {
332 pTo[n] += (to_sample_t)*pFrom++ * fSourceGain; // +++++ re-cast to dest format?
333 }
334 }
335
336 // increment loop position w/ rollover
337 toOffset += samples;
338 if(toOffset >= toLength)
339 toOffset -= toLength;
340
341 return toOffset;
342 }
343
344 // mix from a linear buffer in one sample format to a
345 // circular buffer in another, delegating to convert_sample() for rescaling
346 // input samples are multiplied by fSourceGain; destination samples
347 // are multiplied by fFeedback
348 // returns new offset within destination buffer
349
350 template<class from_sample_t, class to_sample_t>
mix_linear_to_circular_convert(from_sample_t * pFrom,to_sample_t * pTo,size_t samples,size_t toOffset,size_t toLength,float fSourceGain,float fFeedback)351 inline size_t mix_linear_to_circular_convert(
352 from_sample_t* pFrom,
353 to_sample_t* pTo,
354 size_t samples,
355 size_t toOffset,
356 size_t toLength,
357 float fSourceGain,
358 float fFeedback) {
359
360 // feedback
361 size_t n, nLength;
362 if(fFeedback == 0.0) // +++++ memset?
363 for(n = toOffset, nLength = samples;
364 nLength;
365 n = (n+1 == toLength) ? 0 : n+1, nLength--) { pTo[n] = 0.0; }
366 else if(fFeedback != 1.0)
367 for(n = toOffset, nLength = samples;
368 nLength;
369 n = (n+1 == toLength) ? 0 : n+1, nLength--) { pTo[n] *= fFeedback; }
370 // else nothing to do
371
372 // mix source, unless muted or not provided
373 if(pFrom && fSourceGain != 0.0) {
374 if(fSourceGain == 1.0)
375 for(n = toOffset, nLength = samples;
376 nLength;
377 n = (n+1 == toLength) ? 0 : n+1, nLength--) {
378 to_sample_t from;
379 convert_sample(*pFrom++, from);
380 pTo[n] += from;
381 }
382 else
383 for(n = toOffset, nLength = samples;
384 nLength;
385 n = (n+1 == toLength) ? 0 : n+1, nLength--) {
386 to_sample_t from;
387 convert_sample(*pFrom++, from);
388 pTo[n] += from * fSourceGain; // +++++ re-cast to dest format?
389 }
390 }
391
392 // increment loop position w/ rollover
393 toOffset += samples;
394 if(toOffset >= toLength)
395 toOffset -= toLength;
396
397 return toOffset;
398 }
399
400 #endif /* __AUDIO_BUFFER_TOOLS_H__ */
401