2018-06-17 20:34:53 +08:00
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
This file is part of the JUCE library.
|
|
|
|
Copyright (c) 2017 - ROLI Ltd.
|
|
|
|
|
|
|
|
JUCE is an open source library subject to commercial or open-source
|
|
|
|
licensing.
|
|
|
|
|
|
|
|
The code included in this file is provided under the terms of the ISC license
|
|
|
|
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
|
|
|
To use, copy, modify, and/or distribute this software for any purpose with or
|
|
|
|
without fee is hereby granted provided that the above copyright notice and
|
|
|
|
this permission notice appear in all copies.
|
|
|
|
|
|
|
|
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
|
|
|
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
|
|
|
DISCLAIMED.
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace juce
|
|
|
|
{
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fffff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
|
|
|
ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
|
|
|
ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fffff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
|
|
|
ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
|
|
|
ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fffffff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto maxVal = (double) 0x7fffffff;
|
|
|
|
auto intData = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (dest != (void*) source || destBytesPerSample <= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += destBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= destBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
|
|
|
|
|
|
|
char* d = static_cast<char*> (dest);
|
|
|
|
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<float*> (d) = source[i];
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
#if JUCE_BIG_ENDIAN
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
|
2018-06-17 20:34:53 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
d += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
auto d = static_cast<char*> (dest);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<float*> (d) = source[i];
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
#if JUCE_LITTLE_ENDIAN
|
2019-06-23 03:41:38 +08:00
|
|
|
*reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
|
2018-06-17 20:34:53 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
d += destBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
const float scale = 1.0f / 0x7fff;
|
2019-06-23 03:41:38 +08:00
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
const float scale = 1.0f / 0x7fff;
|
2019-06-23 03:41:38 +08:00
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
const float scale = 1.0f / 0x7fffff;
|
2019-06-23 03:41:38 +08:00
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
|
|
|
dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
|
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
|
|
|
dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
const float scale = 1.0f / 0x7fffff;
|
2019-06-23 03:41:38 +08:00
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
|
|
|
dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
|
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
|
|
|
dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
const float scale = 1.0f / (float) 0x7fffffff;
|
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
const float scale = 1.0f / (float) 0x7fffffff;
|
|
|
|
auto intData = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
if (source != (void*) dest || srcBytesPerSample >= 4)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
intData += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intData += srcBytesPerSample * numSamples;
|
|
|
|
|
|
|
|
for (int i = numSamples; --i >= 0;)
|
|
|
|
{
|
|
|
|
intData -= srcBytesPerSample;
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
|
2018-06-17 20:34:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto s = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = *reinterpret_cast<const float*> (s);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
#if JUCE_BIG_ENDIAN
|
2019-06-23 03:41:38 +08:00
|
|
|
auto d = reinterpret_cast<uint32*> (dest + i);
|
2018-06-17 20:34:53 +08:00
|
|
|
*d = ByteOrder::swap (*d);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto s = static_cast<const char*> (source);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
dest[i] = *reinterpret_cast<const float*> (s);
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
#if JUCE_LITTLE_ENDIAN
|
2019-06-23 03:41:38 +08:00
|
|
|
auto d = reinterpret_cast<uint32*> (dest + i);
|
2018-06-17 20:34:53 +08:00
|
|
|
*d = ByteOrder::swap (*d);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s += srcBytesPerSample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
switch (destFormat)
|
|
|
|
{
|
|
|
|
case int16LE: convertFloatToInt16LE (source, dest, numSamples); break;
|
|
|
|
case int16BE: convertFloatToInt16BE (source, dest, numSamples); break;
|
|
|
|
case int24LE: convertFloatToInt24LE (source, dest, numSamples); break;
|
|
|
|
case int24BE: convertFloatToInt24BE (source, dest, numSamples); break;
|
|
|
|
case int32LE: convertFloatToInt32LE (source, dest, numSamples); break;
|
|
|
|
case int32BE: convertFloatToInt32BE (source, dest, numSamples); break;
|
|
|
|
case float32LE: convertFloatToFloat32LE (source, dest, numSamples); break;
|
|
|
|
case float32BE: convertFloatToFloat32BE (source, dest, numSamples); break;
|
|
|
|
default: jassertfalse; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
switch (sourceFormat)
|
|
|
|
{
|
|
|
|
case int16LE: convertInt16LEToFloat (source, dest, numSamples); break;
|
|
|
|
case int16BE: convertInt16BEToFloat (source, dest, numSamples); break;
|
|
|
|
case int24LE: convertInt24LEToFloat (source, dest, numSamples); break;
|
|
|
|
case int24BE: convertInt24BEToFloat (source, dest, numSamples); break;
|
|
|
|
case int32LE: convertInt32LEToFloat (source, dest, numSamples); break;
|
|
|
|
case int32BE: convertInt32BEToFloat (source, dest, numSamples); break;
|
|
|
|
case float32LE: convertFloat32LEToFloat (source, dest, numSamples); break;
|
|
|
|
case float32BE: convertFloat32BEToFloat (source, dest, numSamples); break;
|
|
|
|
default: jassertfalse; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
for (int chan = 0; chan < numChannels; ++chan)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto i = chan;
|
|
|
|
auto src = source [chan];
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
for (int j = 0; j < numSamples; ++j)
|
|
|
|
{
|
|
|
|
dest [i] = src [j];
|
|
|
|
i += numChannels;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:41:38 +08:00
|
|
|
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
|
2018-06-17 20:34:53 +08:00
|
|
|
{
|
|
|
|
for (int chan = 0; chan < numChannels; ++chan)
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto i = chan;
|
|
|
|
auto dst = dest [chan];
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
for (int j = 0; j < numSamples; ++j)
|
|
|
|
{
|
|
|
|
dst [j] = source [i];
|
|
|
|
i += numChannels;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
#if JUCE_UNIT_TESTS
|
|
|
|
|
|
|
|
class AudioConversionTests : public UnitTest
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AudioConversionTests() : UnitTest ("Audio data conversion", "Audio") {}
|
|
|
|
|
|
|
|
template <class F1, class E1, class F2, class E2>
|
|
|
|
struct Test5
|
|
|
|
{
|
|
|
|
static void test (UnitTest& unitTest, Random& r)
|
|
|
|
{
|
|
|
|
test (unitTest, false, r);
|
|
|
|
test (unitTest, true, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test (UnitTest& unitTest, bool inPlace, Random& r)
|
|
|
|
{
|
|
|
|
const int numSamples = 2048;
|
2019-06-23 03:41:38 +08:00
|
|
|
int32 original[numSamples], converted[numSamples], reversed[numSamples];
|
2018-06-17 20:34:53 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
|
|
|
|
bool clippingFailed = false;
|
|
|
|
|
|
|
|
for (int i = 0; i < numSamples / 2; ++i)
|
|
|
|
{
|
|
|
|
d.setAsFloat (r.nextFloat() * 2.2f - 1.1f);
|
|
|
|
|
|
|
|
if (! d.isFloatingPoint())
|
|
|
|
clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed;
|
|
|
|
|
|
|
|
++d;
|
|
|
|
d.setAsInt32 (r.nextInt());
|
|
|
|
++d;
|
|
|
|
}
|
|
|
|
|
|
|
|
unitTest.expect (! clippingFailed);
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert data from the source to dest format..
|
2019-06-23 03:41:38 +08:00
|
|
|
std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
|
|
|
|
AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
|
2018-06-17 20:34:53 +08:00
|
|
|
conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
|
|
|
|
|
|
|
|
// ..and back again..
|
2019-06-23 03:41:38 +08:00
|
|
|
conv.reset (new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
|
|
|
|
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
|
2018-06-17 20:34:53 +08:00
|
|
|
if (! inPlace)
|
|
|
|
zeromem (reversed, sizeof (reversed));
|
|
|
|
|
|
|
|
conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
|
|
|
|
|
|
|
|
{
|
|
|
|
int biggestDiff = 0;
|
|
|
|
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original);
|
|
|
|
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed);
|
|
|
|
|
|
|
|
const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution()
|
|
|
|
+ AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution();
|
|
|
|
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
|
|
{
|
|
|
|
biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32()));
|
|
|
|
++d1;
|
|
|
|
++d2;
|
|
|
|
}
|
|
|
|
|
|
|
|
unitTest.expect (biggestDiff <= errorMargin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class F1, class E1, class FormatType>
|
|
|
|
struct Test3
|
|
|
|
{
|
|
|
|
static void test (UnitTest& unitTest, Random& r)
|
|
|
|
{
|
|
|
|
Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r);
|
|
|
|
Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class FormatType, class Endianness>
|
|
|
|
struct Test2
|
|
|
|
{
|
|
|
|
static void test (UnitTest& unitTest, Random& r)
|
|
|
|
{
|
|
|
|
Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r);
|
|
|
|
Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r);
|
|
|
|
Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r);
|
|
|
|
Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r);
|
|
|
|
Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r);
|
|
|
|
Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class FormatType>
|
|
|
|
struct Test1
|
|
|
|
{
|
|
|
|
static void test (UnitTest& unitTest, Random& r)
|
|
|
|
{
|
|
|
|
Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r);
|
|
|
|
Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void runTest() override
|
|
|
|
{
|
2019-06-23 03:41:38 +08:00
|
|
|
auto r = getRandom();
|
2018-06-17 20:34:53 +08:00
|
|
|
beginTest ("Round-trip conversion: Int8");
|
|
|
|
Test1 <AudioData::Int8>::test (*this, r);
|
|
|
|
beginTest ("Round-trip conversion: Int16");
|
|
|
|
Test1 <AudioData::Int16>::test (*this, r);
|
|
|
|
beginTest ("Round-trip conversion: Int24");
|
|
|
|
Test1 <AudioData::Int24>::test (*this, r);
|
|
|
|
beginTest ("Round-trip conversion: Int32");
|
|
|
|
Test1 <AudioData::Int32>::test (*this, r);
|
|
|
|
beginTest ("Round-trip conversion: Float32");
|
|
|
|
Test1 <AudioData::Float32>::test (*this, r);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static AudioConversionTests audioConversionUnitTests;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace juce
|