xref: /haiku/src/apps/cortex/addons/common/audio_buffer_tools.h (revision 19ae20e67e91fc09cc9fc5c0e60e21e24e7a53eb)
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