26JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
27JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
29void AudioDataConverters::convertFloatToInt16LE (const
float* source,
void* dest,
int numSamples,
int destBytesPerSample)
31 auto maxVal = (double) 0x7fff;
32 auto intData =
static_cast<char*
> (dest);
34 if (dest != (
void*) source || destBytesPerSample <= 4)
36 for (
int i = 0; i < numSamples; ++i)
38 *unalignedPointerCast<uint16*> (intData) =
ByteOrder::swapIfBigEndian ((uint16) (
short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
39 intData += destBytesPerSample;
44 intData += destBytesPerSample * numSamples;
46 for (
int i = numSamples; --i >= 0;)
48 intData -= destBytesPerSample;
49 *unalignedPointerCast<uint16*> (intData) =
ByteOrder::swapIfBigEndian ((uint16) (
short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
54void AudioDataConverters::convertFloatToInt16BE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
56 auto maxVal = (double) 0x7fff;
57 auto intData =
static_cast<char*
> (dest);
59 if (dest != (
void*) source || destBytesPerSample <= 4)
61 for (
int i = 0; i < numSamples; ++i)
63 *unalignedPointerCast<uint16*> (intData) =
ByteOrder::swapIfLittleEndian ((uint16) (
short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
64 intData += destBytesPerSample;
69 intData += destBytesPerSample * numSamples;
71 for (
int i = numSamples; --i >= 0;)
73 intData -= destBytesPerSample;
74 *unalignedPointerCast<uint16*> (intData) =
ByteOrder::swapIfLittleEndian ((uint16) (
short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
79void AudioDataConverters::convertFloatToInt24LE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
81 auto maxVal = (double) 0x7fffff;
82 auto intData =
static_cast<char*
> (dest);
84 if (dest != (
void*) source || destBytesPerSample <= 4)
86 for (
int i = 0; i < numSamples; ++i)
89 intData += destBytesPerSample;
94 intData += destBytesPerSample * numSamples;
96 for (
int i = numSamples; --i >= 0;)
98 intData -= destBytesPerSample;
104void AudioDataConverters::convertFloatToInt24BE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
106 auto maxVal = (double) 0x7fffff;
107 auto intData =
static_cast<char*
> (dest);
109 if (dest != (
void*) source || destBytesPerSample <= 4)
111 for (
int i = 0; i < numSamples; ++i)
114 intData += destBytesPerSample;
119 intData += destBytesPerSample * numSamples;
121 for (
int i = numSamples; --i >= 0;)
123 intData -= destBytesPerSample;
129void AudioDataConverters::convertFloatToInt32LE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
131 auto maxVal = (double) 0x7fffffff;
132 auto intData =
static_cast<char*
> (dest);
134 if (dest != (
void*) source || destBytesPerSample <= 4)
136 for (
int i = 0; i < numSamples; ++i)
138 *unalignedPointerCast<uint32*> (intData) =
ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
139 intData += destBytesPerSample;
144 intData += destBytesPerSample * numSamples;
146 for (
int i = numSamples; --i >= 0;)
148 intData -= destBytesPerSample;
149 *unalignedPointerCast<uint32*> (intData) =
ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
154void AudioDataConverters::convertFloatToInt32BE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
156 auto maxVal = (double) 0x7fffffff;
157 auto intData =
static_cast<char*
> (dest);
159 if (dest != (
void*) source || destBytesPerSample <= 4)
161 for (
int i = 0; i < numSamples; ++i)
163 *unalignedPointerCast<uint32*> (intData) =
ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
164 intData += destBytesPerSample;
169 intData += destBytesPerSample * numSamples;
171 for (
int i = numSamples; --i >= 0;)
173 intData -= destBytesPerSample;
174 *unalignedPointerCast<uint32*> (intData) =
ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
179void AudioDataConverters::convertFloatToFloat32LE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
181 jassert (dest != (
void*) source || destBytesPerSample <= 4);
183 char* d =
static_cast<char*
> (dest);
185 for (
int i = 0; i < numSamples; ++i)
187 *unalignedPointerCast<float*> (d) = source[i];
190 *unalignedPointerCast<uint32*> (d) =
ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
193 d += destBytesPerSample;
197void AudioDataConverters::convertFloatToFloat32BE (
const float* source,
void* dest,
int numSamples,
int destBytesPerSample)
199 jassert (dest != (
void*) source || destBytesPerSample <= 4);
201 auto d =
static_cast<char*
> (dest);
203 for (
int i = 0; i < numSamples; ++i)
205 *unalignedPointerCast<float*> (d) = source[i];
207 #if JUCE_LITTLE_ENDIAN
208 *unalignedPointerCast<uint32*> (d) =
ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
211 d += destBytesPerSample;
216void AudioDataConverters::convertInt16LEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
218 const float scale = 1.0f / 0x7fff;
219 auto intData =
static_cast<const char*
> (source);
221 if (source != (
void*) dest || srcBytesPerSample >= 4)
223 for (
int i = 0; i < numSamples; ++i)
226 intData += srcBytesPerSample;
231 intData += srcBytesPerSample * numSamples;
233 for (
int i = numSamples; --i >= 0;)
235 intData -= srcBytesPerSample;
241void AudioDataConverters::convertInt16BEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
243 const float scale = 1.0f / 0x7fff;
244 auto intData =
static_cast<const char*
> (source);
246 if (source != (
void*) dest || srcBytesPerSample >= 4)
248 for (
int i = 0; i < numSamples; ++i)
251 intData += srcBytesPerSample;
256 intData += srcBytesPerSample * numSamples;
258 for (
int i = numSamples; --i >= 0;)
260 intData -= srcBytesPerSample;
266void AudioDataConverters::convertInt24LEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
268 const float scale = 1.0f / 0x7fffff;
269 auto intData =
static_cast<const char*
> (source);
271 if (source != (
void*) dest || srcBytesPerSample >= 4)
273 for (
int i = 0; i < numSamples; ++i)
276 intData += srcBytesPerSample;
281 intData += srcBytesPerSample * numSamples;
283 for (
int i = numSamples; --i >= 0;)
285 intData -= srcBytesPerSample;
291void AudioDataConverters::convertInt24BEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
293 const float scale = 1.0f / 0x7fffff;
294 auto intData =
static_cast<const char*
> (source);
296 if (source != (
void*) dest || srcBytesPerSample >= 4)
298 for (
int i = 0; i < numSamples; ++i)
301 intData += srcBytesPerSample;
306 intData += srcBytesPerSample * numSamples;
308 for (
int i = numSamples; --i >= 0;)
310 intData -= srcBytesPerSample;
316void AudioDataConverters::convertInt32LEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
318 const float scale = 1.0f / (float) 0x7fffffff;
319 auto intData =
static_cast<const char*
> (source);
321 if (source != (
void*) dest || srcBytesPerSample >= 4)
323 for (
int i = 0; i < numSamples; ++i)
326 intData += srcBytesPerSample;
331 intData += srcBytesPerSample * numSamples;
333 for (
int i = numSamples; --i >= 0;)
335 intData -= srcBytesPerSample;
341void AudioDataConverters::convertInt32BEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
343 const float scale = 1.0f / (float) 0x7fffffff;
344 auto intData =
static_cast<const char*
> (source);
346 if (source != (
void*) dest || srcBytesPerSample >= 4)
348 for (
int i = 0; i < numSamples; ++i)
351 intData += srcBytesPerSample;
356 intData += srcBytesPerSample * numSamples;
358 for (
int i = numSamples; --i >= 0;)
360 intData -= srcBytesPerSample;
366void AudioDataConverters::convertFloat32LEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
368 auto s =
static_cast<const char*
> (source);
370 for (
int i = 0; i < numSamples; ++i)
372 dest[i] = *unalignedPointerCast<const float*> (s);
375 auto d = unalignedPointerCast<uint32*> (dest + i);
379 s += srcBytesPerSample;
383void AudioDataConverters::convertFloat32BEToFloat (
const void* source,
float* dest,
int numSamples,
int srcBytesPerSample)
385 auto s =
static_cast<const char*
> (source);
387 for (
int i = 0; i < numSamples; ++i)
389 dest[i] = *unalignedPointerCast<const float*> (s);
391 #if JUCE_LITTLE_ENDIAN
392 auto d = unalignedPointerCast<uint32*> (dest + i);
396 s += srcBytesPerSample;
402void AudioDataConverters::convertFloatToFormat (DataFormat destFormat,
const float* source,
void* dest,
int numSamples)
406 case int16LE: convertFloatToInt16LE (source, dest, numSamples);
break;
407 case int16BE: convertFloatToInt16BE (source, dest, numSamples);
break;
408 case int24LE: convertFloatToInt24LE (source, dest, numSamples);
break;
409 case int24BE: convertFloatToInt24BE (source, dest, numSamples);
break;
410 case int32LE: convertFloatToInt32LE (source, dest, numSamples);
break;
411 case int32BE: convertFloatToInt32BE (source, dest, numSamples);
break;
412 case float32LE: convertFloatToFloat32LE (source, dest, numSamples);
break;
413 case float32BE: convertFloatToFloat32BE (source, dest, numSamples);
break;
414 default: jassertfalse;
break;
418void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat,
const void* source,
float* dest,
int numSamples)
420 switch (sourceFormat)
422 case int16LE: convertInt16LEToFloat (source, dest, numSamples);
break;
423 case int16BE: convertInt16BEToFloat (source, dest, numSamples);
break;
424 case int24LE: convertInt24LEToFloat (source, dest, numSamples);
break;
425 case int24BE: convertInt24BEToFloat (source, dest, numSamples);
break;
426 case int32LE: convertInt32LEToFloat (source, dest, numSamples);
break;
427 case int32BE: convertInt32BEToFloat (source, dest, numSamples);
break;
428 case float32LE: convertFloat32LEToFloat (source, dest, numSamples);
break;
429 case float32BE: convertFloat32BEToFloat (source, dest, numSamples);
break;
430 default: jassertfalse;
break;
435void AudioDataConverters::interleaveSamples (
const float** source,
float* dest,
int numSamples,
int numChannels)
437 using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
440 AudioData::InterleavedDest<Format> { dest, numChannels },
444void AudioDataConverters::deinterleaveSamples (
const float* source,
float** dest,
int numSamples,
int numChannels)
446 using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
449 AudioData::NonInterleavedDest<Format> { dest, numChannels },
457class AudioConversionTests final :
public UnitTest
460 AudioConversionTests()
461 : UnitTest (
"Audio data conversion", UnitTestCategories::audio)
464 template <
class F1,
class E1,
class F2,
class E2>
467 static void test (UnitTest& unitTest, Random& r)
469 test (unitTest,
false, r);
470 test (unitTest,
true, r);
473 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
474 static
void test (UnitTest& unitTest,
bool inPlace, Random& r)
476 const int numSamples = 2048;
477 int32 original [(size_t) numSamples],
478 converted[(
size_t) numSamples],
479 reversed [(size_t) numSamples];
482 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
483 bool clippingFailed =
false;
485 for (
int i = 0; i < numSamples / 2; ++i)
487 d.setAsFloat (r.nextFloat() * 2.2f - 1.1f);
489 if (! d.isFloatingPoint())
490 clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed;
493 d.setAsInt32 (r.nextInt());
497 unitTest.expect (! clippingFailed);
501 std::unique_ptr<AudioData::Converter> conv (
new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
502 AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
503 conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
506 conv.reset (
new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
507 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
509 zeromem (reversed,
sizeof (reversed));
511 conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
515 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original);
516 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed);
518 const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution()
519 + AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution();
521 for (
int i = 0; i < numSamples; ++i)
523 biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32()));
528 unitTest.expect (biggestDiff <= errorMargin);
531 JUCE_END_IGNORE_WARNINGS_MSVC
534 template <
class F1,
class E1,
class FormatType>
537 static void test (UnitTest& unitTest, Random& r)
539 Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r);
540 Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r);
544 template <
class FormatType,
class Endianness>
547 static void test (UnitTest& unitTest, Random& r)
549 Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r);
550 Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r);
551 Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r);
552 Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r);
553 Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r);
554 Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r);
558 template <
class FormatType>
561 static void test (UnitTest& unitTest, Random& r)
563 Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r);
564 Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r);
568 void runTest()
override
570 auto r = getRandom();
571 beginTest (
"Round-trip conversion: Int8");
572 Test1 <AudioData::Int8>::test (*
this, r);
573 beginTest (
"Round-trip conversion: Int16");
574 Test1 <AudioData::Int16>::test (*
this, r);
575 beginTest (
"Round-trip conversion: Int24");
576 Test1 <AudioData::Int24>::test (*
this, r);
577 beginTest (
"Round-trip conversion: Int32");
578 Test1 <AudioData::Int32>::test (*
this, r);
579 beginTest (
"Round-trip conversion: Float32");
580 Test1 <AudioData::Float32>::test (*
this, r);
582 using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
584 beginTest (
"Interleaving");
586 constexpr auto numChannels = 4;
587 constexpr auto numSamples = 512;
589 AudioBuffer<float> sourceBuffer { numChannels, numSamples },
590 destBuffer { 1, numChannels * numSamples };
592 for (
int ch = 0; ch < numChannels; ++ch)
593 for (
int i = 0; i < numSamples; ++i)
594 sourceBuffer.setSample (ch, i, r.nextFloat());
597 AudioData::InterleavedDest<Format> { destBuffer.getWritePointer (0), numChannels },
600 for (
int ch = 0; ch < numChannels; ++ch)
601 for (
int i = 0; i < numSamples; ++i)
602 expectEquals (destBuffer.getSample (0, ch + (i * numChannels)), sourceBuffer.getSample (ch, i));
605 beginTest (
"Deinterleaving");
607 constexpr auto numChannels = 4;
608 constexpr auto numSamples = 512;
610 AudioBuffer<float> sourceBuffer { 1, numChannels * numSamples },
611 destBuffer { numChannels, numSamples };
613 for (
int ch = 0; ch < numChannels; ++ch)
614 for (
int i = 0; i < numSamples; ++i)
615 sourceBuffer.setSample (0, ch + (i * numChannels), r.nextFloat());
618 AudioData::NonInterleavedDest<Format> { destBuffer.getArrayOfWritePointers(), numChannels },
621 for (
int ch = 0; ch < numChannels; ++ch)
622 for (
int i = 0; i < numSamples; ++i)
623 expectEquals (sourceBuffer.getSample (0, ch + (i * numChannels)), destBuffer.getSample (ch, i));
628static AudioConversionTests audioConversionUnitTests;
632JUCE_END_IGNORE_WARNINGS_MSVC
633JUCE_END_IGNORE_WARNINGS_GCC_LIKE
static void interleaveSamples(NonInterleavedSource< SourceFormat... > source, InterleavedDest< DestFormat... > dest, int numSamples)
static void deinterleaveSamples(InterleavedSource< SourceFormat... > source, NonInterleavedDest< DestFormat... > dest, int numSamples)
static Type swapIfLittleEndian(Type value) noexcept
static void littleEndian24BitToChars(int32 value, void *destBytes) noexcept
static constexpr uint16 swap(uint16 value) noexcept
static void bigEndian24BitToChars(int32 value, void *destBytes) noexcept
static constexpr int littleEndian24Bit(const void *bytes) noexcept
static Type swapIfBigEndian(Type value) noexcept
static constexpr int bigEndian24Bit(const void *bytes) noexcept