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/* 50template<class from_sample_t, class to_sample_t> 51void convert_sample(from_sample_t in, to_sample_t& out) { 52 out = (to_sample_t)in; // +++++ arbitrary conversion stub 53} 54*/ 55 56inline void convert_sample(float& in, float& out) { 57 out = in; 58} 59 60inline void convert_sample(uchar& in, float& out) { 61 out = (float)(in - 128) / 127.0; 62} 63 64inline void convert_sample(short& in, float& out) { 65 out = (float)in / 32767.0; 66} 67 68inline void convert_sample(int32& in, float& out) { 69 out = (float)in / (float)0x7fffffff; 70} 71 72inline void convert_sample(float& in, uchar& out) { 73 out = (uchar)(in * 127.0); 74} 75 76inline void convert_sample(float& in, short& out) { 77 out = (short)(in * 32767.0); 78} 79 80inline void convert_sample(float& in, int32& out) { 81 out = (int32)(in * 0x7fffffff); 82} 83 84inline void swap_convert_sample(float& in, float& out) { 85 out = B_SWAP_FLOAT(in); 86} 87 88inline void swap_convert_sample(uchar& in, float& out) { 89 // no swap needed for char 90 out = (float)(in - 128) / 127.0; 91} 92 93inline void swap_convert_sample(short& in, float& out) { 94 out = (float)(int16)(B_SWAP_INT16(in)) / 32767.0; 95} 96 97inline void swap_convert_sample(int32& in, float& out) { 98 out = (float)(int32)(B_SWAP_INT32(in)) / (float)0x7fffffff; 99} 100 101inline void swap_convert_sample(float& in, uchar& out) { 102 out = (uchar)((B_SWAP_FLOAT(in)) * 127.0); 103} 104 105inline void swap_convert_sample(float& in, short& out) { 106 out = (short)((B_SWAP_FLOAT(in)) * 32767.0); 107} 108 109inline void swap_convert_sample(float& in, int32& out) { 110 out = (int32)((B_SWAP_FLOAT(in)) * 0x7fffffff); 111} 112 113 114template<class to_sample_t> 115inline 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 134template<class from_sample_t> 135inline 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 154inline 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 183template<class from_sample_t, class to_sample_t> 184inline 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 209template<class from_sample_t, class to_sample_t> 210inline 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 234template<class from_sample_t, class to_sample_t> 235inline 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 260template<class from_sample_t, class to_sample_t> 261inline 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 298template<class from_sample_t, class to_sample_t> 299inline 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 350template<class from_sample_t, class to_sample_t> 351inline 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