OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_AudioDataConverters.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
27{
28 auto maxVal = (double) 0x7fff;
29 auto intData = static_cast<char*> (dest);
30
31 if (dest != (void*) source || destBytesPerSample <= 4)
32 {
33 for (int i = 0; i < numSamples; ++i)
34 {
35 *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
36 intData += destBytesPerSample;
37 }
38 }
39 else
40 {
41 intData += destBytesPerSample * numSamples;
42
43 for (int i = numSamples; --i >= 0;)
44 {
45 intData -= destBytesPerSample;
46 *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
47 }
48 }
49}
50
51void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
52{
53 auto maxVal = (double) 0x7fff;
54 auto intData = static_cast<char*> (dest);
55
56 if (dest != (void*) source || destBytesPerSample <= 4)
57 {
58 for (int i = 0; i < numSamples; ++i)
59 {
60 *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
61 intData += destBytesPerSample;
62 }
63 }
64 else
65 {
66 intData += destBytesPerSample * numSamples;
67
68 for (int i = numSamples; --i >= 0;)
69 {
70 intData -= destBytesPerSample;
71 *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
72 }
73 }
74}
75
76void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
77{
78 auto maxVal = (double) 0x7fffff;
79 auto intData = static_cast<char*> (dest);
80
81 if (dest != (void*) source || destBytesPerSample <= 4)
82 {
83 for (int i = 0; i < numSamples; ++i)
84 {
85 ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
86 intData += destBytesPerSample;
87 }
88 }
89 else
90 {
91 intData += destBytesPerSample * numSamples;
92
93 for (int i = numSamples; --i >= 0;)
94 {
95 intData -= destBytesPerSample;
96 ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
97 }
98 }
99}
100
101void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
102{
103 auto maxVal = (double) 0x7fffff;
104 auto intData = static_cast<char*> (dest);
105
106 if (dest != (void*) source || destBytesPerSample <= 4)
107 {
108 for (int i = 0; i < numSamples; ++i)
109 {
110 ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
111 intData += destBytesPerSample;
112 }
113 }
114 else
115 {
116 intData += destBytesPerSample * numSamples;
117
118 for (int i = numSamples; --i >= 0;)
119 {
120 intData -= destBytesPerSample;
121 ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
122 }
123 }
124}
125
126void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
127{
128 auto maxVal = (double) 0x7fffffff;
129 auto intData = static_cast<char*> (dest);
130
131 if (dest != (void*) source || destBytesPerSample <= 4)
132 {
133 for (int i = 0; i < numSamples; ++i)
134 {
135 *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
136 intData += destBytesPerSample;
137 }
138 }
139 else
140 {
141 intData += destBytesPerSample * numSamples;
142
143 for (int i = numSamples; --i >= 0;)
144 {
145 intData -= destBytesPerSample;
146 *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
147 }
148 }
149}
150
151void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
152{
153 auto maxVal = (double) 0x7fffffff;
154 auto intData = static_cast<char*> (dest);
155
156 if (dest != (void*) source || destBytesPerSample <= 4)
157 {
158 for (int i = 0; i < numSamples; ++i)
159 {
160 *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
161 intData += destBytesPerSample;
162 }
163 }
164 else
165 {
166 intData += destBytesPerSample * numSamples;
167
168 for (int i = numSamples; --i >= 0;)
169 {
170 intData -= destBytesPerSample;
171 *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
172 }
173 }
174}
175
176void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
177{
178 jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
179
180 char* d = static_cast<char*> (dest);
181
182 for (int i = 0; i < numSamples; ++i)
183 {
184 *reinterpret_cast<float*> (d) = source[i];
185
186 #if JUCE_BIG_ENDIAN
187 *reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
188 #endif
189
190 d += destBytesPerSample;
191 }
192}
193
194void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
195{
196 jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
197
198 auto d = static_cast<char*> (dest);
199
200 for (int i = 0; i < numSamples; ++i)
201 {
202 *reinterpret_cast<float*> (d) = source[i];
203
204 #if JUCE_LITTLE_ENDIAN
205 *reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
206 #endif
207
208 d += destBytesPerSample;
209 }
210}
211
212//==============================================================================
213void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
214{
215 const float scale = 1.0f / 0x7fff;
216 auto intData = static_cast<const char*> (source);
217
218 if (source != (void*) dest || srcBytesPerSample >= 4)
219 {
220 for (int i = 0; i < numSamples; ++i)
221 {
222 dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
223 intData += srcBytesPerSample;
224 }
225 }
226 else
227 {
228 intData += srcBytesPerSample * numSamples;
229
230 for (int i = numSamples; --i >= 0;)
231 {
232 intData -= srcBytesPerSample;
233 dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
234 }
235 }
236}
237
238void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
239{
240 const float scale = 1.0f / 0x7fff;
241 auto intData = static_cast<const char*> (source);
242
243 if (source != (void*) dest || srcBytesPerSample >= 4)
244 {
245 for (int i = 0; i < numSamples; ++i)
246 {
247 dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
248 intData += srcBytesPerSample;
249 }
250 }
251 else
252 {
253 intData += srcBytesPerSample * numSamples;
254
255 for (int i = numSamples; --i >= 0;)
256 {
257 intData -= srcBytesPerSample;
258 dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
259 }
260 }
261}
262
263void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
264{
265 const float scale = 1.0f / 0x7fffff;
266 auto intData = static_cast<const char*> (source);
267
268 if (source != (void*) dest || srcBytesPerSample >= 4)
269 {
270 for (int i = 0; i < numSamples; ++i)
271 {
272 dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
273 intData += srcBytesPerSample;
274 }
275 }
276 else
277 {
278 intData += srcBytesPerSample * numSamples;
279
280 for (int i = numSamples; --i >= 0;)
281 {
282 intData -= srcBytesPerSample;
283 dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
284 }
285 }
286}
287
288void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
289{
290 const float scale = 1.0f / 0x7fffff;
291 auto intData = static_cast<const char*> (source);
292
293 if (source != (void*) dest || srcBytesPerSample >= 4)
294 {
295 for (int i = 0; i < numSamples; ++i)
296 {
297 dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
298 intData += srcBytesPerSample;
299 }
300 }
301 else
302 {
303 intData += srcBytesPerSample * numSamples;
304
305 for (int i = numSamples; --i >= 0;)
306 {
307 intData -= srcBytesPerSample;
308 dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
309 }
310 }
311}
312
313void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
314{
315 const float scale = 1.0f / (float) 0x7fffffff;
316 auto intData = static_cast<const char*> (source);
317
318 if (source != (void*) dest || srcBytesPerSample >= 4)
319 {
320 for (int i = 0; i < numSamples; ++i)
321 {
322 dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
323 intData += srcBytesPerSample;
324 }
325 }
326 else
327 {
328 intData += srcBytesPerSample * numSamples;
329
330 for (int i = numSamples; --i >= 0;)
331 {
332 intData -= srcBytesPerSample;
333 dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
334 }
335 }
336}
337
338void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
339{
340 const float scale = 1.0f / (float) 0x7fffffff;
341 auto intData = static_cast<const char*> (source);
342
343 if (source != (void*) dest || srcBytesPerSample >= 4)
344 {
345 for (int i = 0; i < numSamples; ++i)
346 {
347 dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
348 intData += srcBytesPerSample;
349 }
350 }
351 else
352 {
353 intData += srcBytesPerSample * numSamples;
354
355 for (int i = numSamples; --i >= 0;)
356 {
357 intData -= srcBytesPerSample;
358 dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
359 }
360 }
361}
362
363void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
364{
365 auto s = static_cast<const char*> (source);
366
367 for (int i = 0; i < numSamples; ++i)
368 {
369 dest[i] = *reinterpret_cast<const float*> (s);
370
371 #if JUCE_BIG_ENDIAN
372 auto d = reinterpret_cast<uint32*> (dest + i);
373 *d = ByteOrder::swap (*d);
374 #endif
375
376 s += srcBytesPerSample;
377 }
378}
379
380void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
381{
382 auto s = static_cast<const char*> (source);
383
384 for (int i = 0; i < numSamples; ++i)
385 {
386 dest[i] = *reinterpret_cast<const float*> (s);
387
388 #if JUCE_LITTLE_ENDIAN
389 auto d = reinterpret_cast<uint32*> (dest + i);
390 *d = ByteOrder::swap (*d);
391 #endif
392
393 s += srcBytesPerSample;
394 }
395}
396
397
398//==============================================================================
399void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples)
400{
401 switch (destFormat)
402 {
403 case int16LE: convertFloatToInt16LE (source, dest, numSamples); break;
404 case int16BE: convertFloatToInt16BE (source, dest, numSamples); break;
405 case int24LE: convertFloatToInt24LE (source, dest, numSamples); break;
406 case int24BE: convertFloatToInt24BE (source, dest, numSamples); break;
407 case int32LE: convertFloatToInt32LE (source, dest, numSamples); break;
408 case int32BE: convertFloatToInt32BE (source, dest, numSamples); break;
409 case float32LE: convertFloatToFloat32LE (source, dest, numSamples); break;
410 case float32BE: convertFloatToFloat32BE (source, dest, numSamples); break;
411 default: jassertfalse; break;
412 }
413}
414
415void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples)
416{
417 switch (sourceFormat)
418 {
419 case int16LE: convertInt16LEToFloat (source, dest, numSamples); break;
420 case int16BE: convertInt16BEToFloat (source, dest, numSamples); break;
421 case int24LE: convertInt24LEToFloat (source, dest, numSamples); break;
422 case int24BE: convertInt24BEToFloat (source, dest, numSamples); break;
423 case int32LE: convertInt32LEToFloat (source, dest, numSamples); break;
424 case int32BE: convertInt32BEToFloat (source, dest, numSamples); break;
425 case float32LE: convertFloat32LEToFloat (source, dest, numSamples); break;
426 case float32BE: convertFloat32BEToFloat (source, dest, numSamples); break;
427 default: jassertfalse; break;
428 }
429}
430
431//==============================================================================
432void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
433{
434 for (int chan = 0; chan < numChannels; ++chan)
435 {
436 auto i = chan;
437 auto src = source [chan];
438
439 for (int j = 0; j < numSamples; ++j)
440 {
441 dest [i] = src [j];
442 i += numChannels;
443 }
444 }
445}
446
447void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
448{
449 for (int chan = 0; chan < numChannels; ++chan)
450 {
451 auto i = chan;
452 auto dst = dest [chan];
453
454 for (int j = 0; j < numSamples; ++j)
455 {
456 dst [j] = source [i];
457 i += numChannels;
458 }
459 }
460}
461
462
463//==============================================================================
464//==============================================================================
465#if JUCE_UNIT_TESTS
466
467class AudioConversionTests : public UnitTest
468{
469public:
471 : UnitTest ("Audio data conversion", UnitTestCategories::audio)
472 {}
473
474 template <class F1, class E1, class F2, class E2>
475 struct Test5
476 {
477 static void test (UnitTest& unitTest, Random& r)
478 {
479 test (unitTest, false, r);
480 test (unitTest, true, r);
481 }
482
483 static void test (UnitTest& unitTest, bool inPlace, Random& r)
484 {
485 const int numSamples = 2048;
486 int32 original [(size_t) numSamples],
487 converted[(size_t) numSamples],
488 reversed [(size_t) numSamples];
489
490 {
491 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
492 bool clippingFailed = false;
493
494 for (int i = 0; i < numSamples / 2; ++i)
495 {
496 d.setAsFloat (r.nextFloat() * 2.2f - 1.1f);
497
498 if (! d.isFloatingPoint())
499 clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed;
500
501 ++d;
502 d.setAsInt32 (r.nextInt());
503 ++d;
504 }
505
506 unitTest.expect (! clippingFailed);
507 }
508
509 // convert data from the source to dest format..
510 std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
511 AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
512 conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
513
514 // ..and back again..
515 conv.reset (new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
516 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
517 if (! inPlace)
518 zeromem (reversed, sizeof (reversed));
519
520 conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
521
522 {
523 int biggestDiff = 0;
524 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original);
525 AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed);
526
527 const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution()
528 + AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution();
529
530 for (int i = 0; i < numSamples; ++i)
531 {
532 biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32()));
533 ++d1;
534 ++d2;
535 }
536
537 unitTest.expect (biggestDiff <= errorMargin);
538 }
539 }
540 };
541
542 template <class F1, class E1, class FormatType>
543 struct Test3
544 {
545 static void test (UnitTest& unitTest, Random& r)
546 {
547 Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r);
548 Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r);
549 }
550 };
551
552 template <class FormatType, class Endianness>
553 struct Test2
554 {
555 static void test (UnitTest& unitTest, Random& r)
556 {
557 Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r);
558 Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r);
559 Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r);
560 Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r);
561 Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r);
562 Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r);
563 }
564 };
565
566 template <class FormatType>
567 struct Test1
568 {
569 static void test (UnitTest& unitTest, Random& r)
570 {
571 Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r);
572 Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r);
573 }
574 };
575
576 void runTest() override
577 {
578 auto r = getRandom();
579 beginTest ("Round-trip conversion: Int8");
580 Test1 <AudioData::Int8>::test (*this, r);
581 beginTest ("Round-trip conversion: Int16");
582 Test1 <AudioData::Int16>::test (*this, r);
583 beginTest ("Round-trip conversion: Int24");
584 Test1 <AudioData::Int24>::test (*this, r);
585 beginTest ("Round-trip conversion: Int32");
586 Test1 <AudioData::Int32>::test (*this, r);
587 beginTest ("Round-trip conversion: Float32");
588 Test1 <AudioData::Float32>::test (*this, r);
589 }
590};
591
592static AudioConversionTests audioConversionUnitTests;
593
594#endif
595
596} // namespace juce
Array()=default
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
static Type swapIfLittleEndian(Type value) noexcept
static void littleEndian24BitToChars(int32 value, void *destBytes) noexcept
static JUCE_CONSTEXPR int bigEndian24Bit(const void *bytes) noexcept
static void bigEndian24BitToChars(int32 value, void *destBytes) noexcept
static Type swapIfBigEndian(Type value) noexcept
static JUCE_CONSTEXPR int littleEndian24Bit(const void *bytes) noexcept