JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_CoreAudioFormat.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26#if JUCE_MAC || JUCE_IOS
27
28#include <juce_audio_basics/native/juce_CoreAudioLayouts_mac.h>
29#include <juce_core/native/juce_CFHelpers_mac.h>
30
31namespace juce
32{
33
34//==============================================================================
35namespace
36{
37 const char* const coreAudioFormatName = "CoreAudio supported file";
38
39 StringArray getStringInfo (AudioFilePropertyID property, UInt32 size, void* data)
40 {
42 UInt32 sizeOfArray = sizeof (extensions.object);
43
44 const auto err = AudioFileGetGlobalInfo (property,
45 size,
46 data,
48 &extensions.object);
49
50 if (err != noErr)
51 return {};
52
53 const auto numValues = CFArrayGetCount (extensions.object);
54
55 StringArray extensionsArray;
56
57 for (CFIndex i = 0; i < numValues; ++i)
59
60 return extensionsArray;
61 }
62
64 {
66 }
67
69 {
71 }
72
74 {
75 using StreamKind = CoreAudioFormat::StreamKind;
76
77 switch (kind)
78 {
79 case StreamKind::kAiff: return kAudioFileAIFFType;
80 case StreamKind::kAifc: return kAudioFileAIFCType;
81 case StreamKind::kWave: return kAudioFileWAVEType;
82 case StreamKind::kSoundDesigner2: return kAudioFileSoundDesigner2Type;
83 case StreamKind::kNext: return kAudioFileNextType;
84 case StreamKind::kMp3: return kAudioFileMP3Type;
85 case StreamKind::kMp2: return kAudioFileMP2Type;
86 case StreamKind::kMp1: return kAudioFileMP1Type;
87 case StreamKind::kAc3: return kAudioFileAC3Type;
88 case StreamKind::kAacAdts: return kAudioFileAAC_ADTSType;
89 case StreamKind::kMpeg4: return kAudioFileMPEG4Type;
90 case StreamKind::kM4a: return kAudioFileM4AType;
91 case StreamKind::kM4b: return kAudioFileM4BType;
92 case StreamKind::kCaf: return kAudioFileCAFType;
93 case StreamKind::k3gp: return kAudioFile3GPType;
94 case StreamKind::k3gp2: return kAudioFile3GP2Type;
95 case StreamKind::kAmr: return kAudioFileAMRType;
96
97 case StreamKind::kNone: break;
98 }
99
100 return {};
101 }
102}
103
104//==============================================================================
105const char* const CoreAudioFormat::midiDataBase64 = "midiDataBase64";
106const char* const CoreAudioFormat::tempo = "tempo";
107const char* const CoreAudioFormat::timeSig = "time signature";
108const char* const CoreAudioFormat::keySig = "key signature";
109
110//==============================================================================
112{
113 static uint32 chunkName (const char* const name) noexcept { return ByteOrder::bigEndianInt (name); }
114
115 //==============================================================================
116 struct FileHeader
117 {
118 FileHeader (InputStream& input)
119 {
120 fileType = (uint32) input.readIntBigEndian();
121 fileVersion = (uint16) input.readShortBigEndian();
122 fileFlags = (uint16) input.readShortBigEndian();
123 }
124
125 uint32 fileType;
126 uint16 fileVersion;
127 uint16 fileFlags;
128 };
129
130 //==============================================================================
131 struct ChunkHeader
132 {
133 ChunkHeader (InputStream& input)
134 {
135 chunkType = (uint32) input.readIntBigEndian();
136 chunkSize = (int64) input.readInt64BigEndian();
137 }
138
139 uint32 chunkType;
140 int64 chunkSize;
141 };
142
143 //==============================================================================
145 {
146 AudioDescriptionChunk (InputStream& input)
147 {
148 sampleRate = input.readDoubleBigEndian();
149 formatID = (uint32) input.readIntBigEndian();
150 formatFlags = (uint32) input.readIntBigEndian();
151 bytesPerPacket = (uint32) input.readIntBigEndian();
152 framesPerPacket = (uint32) input.readIntBigEndian();
153 channelsPerFrame = (uint32) input.readIntBigEndian();
154 bitsPerChannel = (uint32) input.readIntBigEndian();
155 }
156
157 double sampleRate;
158 uint32 formatID;
159 uint32 formatFlags;
160 uint32 bytesPerPacket;
161 uint32 framesPerPacket;
162 uint32 channelsPerFrame;
163 uint32 bitsPerChannel;
164 };
165
166 //==============================================================================
167 static StringPairArray parseUserDefinedChunk (InputStream& input, int64 size)
168 {
169 StringPairArray infoStrings;
170 auto originalPosition = input.getPosition();
171
172 uint8 uuid[16];
173 input.read (uuid, sizeof (uuid));
174
175 if (memcmp (uuid, "\x29\x81\x92\x73\xB5\xBF\x4A\xEF\xB7\x8D\x62\xD1\xEF\x90\xBB\x2C", 16) == 0)
176 {
177 auto numEntries = (uint32) input.readIntBigEndian();
178
179 for (uint32 i = 0; i < numEntries && input.getPosition() < originalPosition + size; ++i)
180 {
181 String keyName = input.readString();
182 infoStrings.set (keyName, input.readString());
183 }
184 }
185
186 input.setPosition (originalPosition + size);
187 return infoStrings;
188 }
189
190 //==============================================================================
191 static StringPairArray parseMidiChunk (InputStream& input, int64 size)
192 {
193 auto originalPosition = input.getPosition();
194
195 MemoryBlock midiBlock;
196 input.readIntoMemoryBlock (midiBlock, (ssize_t) size);
197 MemoryInputStream midiInputStream (midiBlock, false);
198
199 StringPairArray midiMetadata;
200 MidiFile midiFile;
201
202 if (midiFile.readFrom (midiInputStream))
203 {
205
209 }
210
211 input.setPosition (originalPosition + size);
212 return midiMetadata;
213 }
214
215 static void findTempoEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
216 {
217 MidiMessageSequence tempoEvents;
218 midiFile.findAllTempoEvents (tempoEvents);
219
220 auto numTempoEvents = tempoEvents.getNumEvents();
221 MemoryOutputStream tempoSequence;
222
223 for (int i = 0; i < numTempoEvents; ++i)
224 {
225 auto tempo = getTempoFromTempoMetaEvent (tempoEvents.getEventPointer (i));
226
227 if (tempo > 0.0)
228 {
229 if (i == 0)
230 midiMetadata.set (CoreAudioFormat::tempo, String (tempo));
231
232 if (numTempoEvents > 1)
233 tempoSequence << String (tempo) << ',' << tempoEvents.getEventTime (i) << ';';
234 }
235 }
236
237 if (tempoSequence.getDataSize() > 0)
238 midiMetadata.set ("tempo sequence", tempoSequence.toUTF8());
239 }
240
241 static double getTempoFromTempoMetaEvent (MidiMessageSequence::MidiEventHolder* holder)
242 {
243 if (holder != nullptr)
244 {
245 auto& midiMessage = holder->message;
246
247 if (midiMessage.isTempoMetaEvent())
248 {
249 auto tempoSecondsPerQuarterNote = midiMessage.getTempoSecondsPerQuarterNote();
250
252 return 60.0 / tempoSecondsPerQuarterNote;
253 }
254 }
255
256 return 0.0;
257 }
258
259 static void findTimeSigEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
260 {
261 MidiMessageSequence timeSigEvents;
262 midiFile.findAllTimeSigEvents (timeSigEvents);
263 auto numTimeSigEvents = timeSigEvents.getNumEvents();
264
265 MemoryOutputStream timeSigSequence;
266
267 for (int i = 0; i < numTimeSigEvents; ++i)
268 {
269 int numerator, denominator;
270 timeSigEvents.getEventPointer (i)->message.getTimeSignatureInfo (numerator, denominator);
271
272 String timeSigString;
273 timeSigString << numerator << '/' << denominator;
274
275 if (i == 0)
277
278 if (numTimeSigEvents > 1)
279 timeSigSequence << timeSigString << ',' << timeSigEvents.getEventTime (i) << ';';
280 }
281
282 if (timeSigSequence.getDataSize() > 0)
283 midiMetadata.set ("time signature sequence", timeSigSequence.toUTF8());
284 }
285
286 static void findKeySigEvents (MidiFile& midiFile, StringPairArray& midiMetadata)
287 {
288 MidiMessageSequence keySigEvents;
289 midiFile.findAllKeySigEvents (keySigEvents);
290 auto numKeySigEvents = keySigEvents.getNumEvents();
291
292 MemoryOutputStream keySigSequence;
293
294 for (int i = 0; i < numKeySigEvents; ++i)
295 {
296 auto& message (keySigEvents.getEventPointer (i)->message);
297 auto key = jlimit (0, 14, message.getKeySignatureNumberOfSharpsOrFlats() + 7);
298 bool isMajor = message.isKeySignatureMajorKey();
299
300 static const char* majorKeys[] = { "Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#" };
301 static const char* minorKeys[] = { "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "A#" };
302
303 String keySigString (isMajor ? majorKeys[key]
304 : minorKeys[key]);
305
306 if (! isMajor)
307 keySigString << 'm';
308
309 if (i == 0)
311
312 if (numKeySigEvents > 1)
313 keySigSequence << keySigString << ',' << keySigEvents.getEventTime (i) << ';';
314 }
315
316 if (keySigSequence.getDataSize() > 0)
317 midiMetadata.set ("key signature sequence", keySigSequence.toUTF8());
318 }
319
320 //==============================================================================
321 static StringPairArray parseInformationChunk (InputStream& input)
322 {
323 StringPairArray infoStrings;
324 auto numEntries = (uint32) input.readIntBigEndian();
325
326 for (uint32 i = 0; i < numEntries; ++i)
327 infoStrings.set (input.readString(), input.readString());
328
329 return infoStrings;
330 }
331
332 //==============================================================================
333 static bool read (InputStream& input, StringPairArray& metadataValues)
334 {
335 auto originalPos = input.getPosition();
336
337 const FileHeader cafFileHeader (input);
338 const bool isCafFile = cafFileHeader.fileType == chunkName ("caff");
339
340 if (isCafFile)
341 {
342 while (! input.isExhausted())
343 {
344 const ChunkHeader chunkHeader (input);
345
346 if (chunkHeader.chunkType == chunkName ("desc"))
347 {
349 }
350 else if (chunkHeader.chunkType == chunkName ("uuid"))
351 {
352 metadataValues.addArray (parseUserDefinedChunk (input, chunkHeader.chunkSize));
353 }
354 else if (chunkHeader.chunkType == chunkName ("data"))
355 {
356 // -1 signifies an unknown data size so the data has to be at the
357 // end of the file so we must have finished the header
358
359 if (chunkHeader.chunkSize == -1)
360 break;
361
362 input.setPosition (input.getPosition() + chunkHeader.chunkSize);
363 }
364 else if (chunkHeader.chunkType == chunkName ("midi"))
365 {
366 metadataValues.addArray (parseMidiChunk (input, chunkHeader.chunkSize));
367 }
368 else if (chunkHeader.chunkType == chunkName ("info"))
369 {
370 metadataValues.addArray (parseInformationChunk (input));
371 }
372 else
373 {
374 // we aren't decoding this chunk yet so just skip over it
375 input.setPosition (input.getPosition() + chunkHeader.chunkSize);
376 }
377 }
378 }
379
380 input.setPosition (originalPos);
381
382 return isCafFile;
383 }
384};
385
386//==============================================================================
387class CoreAudioReader final : public AudioFormatReader
388{
389public:
390 using StreamKind = CoreAudioFormat::StreamKind;
391
392 CoreAudioReader (InputStream* inp, StreamKind streamKind)
393 : AudioFormatReader (inp, coreAudioFormatName)
394 {
395 usesFloatingPointData = true;
396 bitsPerSample = 32;
397
398 if (input != nullptr)
399 CoreAudioFormatMetatdata::read (*input, metadataValues);
400
402 &readCallback,
403 nullptr, // write needs to be null to avoid permissions errors
405 nullptr, // setSize needs to be null to avoid permissions errors
406 toAudioFileTypeID (streamKind),
407 &audioFileID);
408 if (status == noErr)
409 {
411
412 if (status == noErr)
413 {
420
421 numChannels = sourceAudioFormat.mChannelsPerFrame;
422 sampleRate = sourceAudioFormat.mSampleRate;
423
428 &lengthInSamples);
429
431 bool hasLayout = false;
433
435
436 if (status == noErr && sizeOfLayout >= (sizeof (AudioChannelLayout) - sizeof (AudioChannelDescription)))
437 {
438 caLayout.malloc (1, static_cast<size_t> (sizeOfLayout));
439
441 &sizeOfLayout, caLayout.get());
442
443 if (status == noErr)
444 {
445 auto fileLayout = CoreAudioLayouts::fromCoreAudio (*caLayout.get());
446
447 if (fileLayout.size() == static_cast<int> (numChannels))
448 {
449 hasLayout = true;
451 }
452 }
453 }
454
455 destinationAudioFormat.mSampleRate = sampleRate;
458 destinationAudioFormat.mBitsPerChannel = sizeof (float) * 8;
459 destinationAudioFormat.mChannelsPerFrame = numChannels;
460 destinationAudioFormat.mBytesPerFrame = sizeof (float);
461 destinationAudioFormat.mFramesPerPacket = 1;
462 destinationAudioFormat.mBytesPerPacket = destinationAudioFormat.mFramesPerPacket * destinationAudioFormat.mBytesPerFrame;
463
468 if (status == noErr)
469 {
470 bufferList.malloc (1, sizeof (AudioBufferList) + numChannels * sizeof (::AudioBuffer));
471 bufferList->mNumberBuffers = numChannels;
472 channelMap.malloc (numChannels);
473
474 if (hasLayout && caLayout != nullptr)
475 {
476 auto caOrder = CoreAudioLayouts::getCoreAudioLayoutChannels (*caLayout);
477
478 for (int i = 0; i < static_cast<int> (numChannels); ++i)
479 {
480 auto idx = channelSet.getChannelIndexForType (caOrder.getReference (i));
481 jassert (isPositiveAndBelow (idx, static_cast<int> (numChannels)));
482
483 channelMap[i] = idx;
484 }
485 }
486 else
487 {
488 for (int i = 0; i < static_cast<int> (numChannels); ++i)
489 channelMap[i] = i;
490 }
491
492 ok = true;
493 }
494 }
495 }
496 }
497
498 ~CoreAudioReader() override
499 {
502 }
503
504 //==============================================================================
505 bool readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
506 int64 startSampleInFile, int numSamples) override
507 {
508 clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
509 startSampleInFile, numSamples, lengthInSamples);
510
511 if (numSamples <= 0)
512 return true;
513
515 {
517 if (status != noErr)
518 return false;
519
521 }
522
523 while (numSamples > 0)
524 {
525 auto numThisTime = jmin (8192, numSamples);
526 auto numBytes = (size_t) numThisTime * sizeof (float);
527
528 audioDataBlock.ensureSize (numBytes * numChannels, false);
529 auto* data = static_cast<float*> (audioDataBlock.getData());
530
531 for (int j = (int) numChannels; --j >= 0;)
532 {
533 bufferList->mBuffers[j].mNumberChannels = 1;
534 bufferList->mBuffers[j].mDataByteSize = (UInt32) numBytes;
535 bufferList->mBuffers[j].mData = data;
536 data += numThisTime;
537 }
538
541
542 if (status != noErr)
543 return false;
544
545 if (numFramesToRead == 0)
546 break;
547
548 if ((int) numFramesToRead < numThisTime)
549 {
551 numBytes = (size_t) numThisTime * sizeof (float);
552 }
553
554 for (int i = numDestChannels; --i >= 0;)
555 {
556 auto* dest = destSamples[(i < (int) numChannels ? channelMap[i] : i)];
557
558 if (dest != nullptr)
559 {
560 if (i < (int) numChannels)
561 memcpy (dest + startOffsetInDestBuffer, bufferList->mBuffers[i].mData, numBytes);
562 else
563 zeromem (dest + startOffsetInDestBuffer, numBytes);
564 }
565 }
566
568 numSamples -= numThisTime;
570 }
571
572 return true;
573 }
574
575 AudioChannelSet getChannelLayout() override
576 {
577 if (channelSet.size() == static_cast<int> (numChannels))
578 return channelSet;
579
581 }
582
583 bool ok = false;
584
585private:
588 AudioChannelSet channelSet;
590 MemoryBlock audioDataBlock;
593 HeapBlock<int> channelMap;
594
595 static SInt64 getSizeCallback (void* inClientData)
596 {
597 return static_cast<CoreAudioReader*> (inClientData)->input->getTotalLength();
598 }
599
600 static OSStatus readCallback (void* inClientData, SInt64 inPosition, UInt32 requestCount,
601 void* buffer, UInt32* actualCount)
602 {
603 auto* reader = static_cast<CoreAudioReader*> (inClientData);
604 reader->input->setPosition (inPosition);
605 *actualCount = (UInt32) reader->input->read (buffer, (int) requestCount);
606 return noErr;
607 }
608
610};
611
612//==============================================================================
615 streamKind (StreamKind::kNone)
616{
617}
618
619CoreAudioFormat::CoreAudioFormat (StreamKind kind)
620 : AudioFormat (coreAudioFormatName, findFileExtensionsForCoreAudioCodec (toAudioFileTypeID (kind))),
621 streamKind (kind)
622{
623}
624
625CoreAudioFormat::~CoreAudioFormat() = default;
626
627Array<int> CoreAudioFormat::getPossibleSampleRates() { return {}; }
628Array<int> CoreAudioFormat::getPossibleBitDepths() { return {}; }
629
630bool CoreAudioFormat::canDoStereo() { return true; }
631bool CoreAudioFormat::canDoMono() { return true; }
632
633//==============================================================================
634AudioFormatReader* CoreAudioFormat::createReaderFor (InputStream* sourceStream,
635 bool deleteStreamIfOpeningFails)
636{
637 std::unique_ptr<CoreAudioReader> r (new CoreAudioReader (sourceStream, streamKind));
638
639 if (r->ok)
640 return r.release();
641
642 if (! deleteStreamIfOpeningFails)
643 r->input = nullptr;
644
645 return nullptr;
646}
647
648AudioFormatWriter* CoreAudioFormat::createWriterFor (OutputStream*,
649 double /*sampleRateToUse*/,
650 unsigned int /*numberOfChannels*/,
651 int /*bitsPerSample*/,
652 const StringPairArray& /*metadataValues*/,
653 int /*qualityOptionIndex*/)
654{
655 jassertfalse; // not yet implemented!
656 return nullptr;
657}
658
659
660//==============================================================================
661//==============================================================================
662#if JUCE_UNIT_TESTS
663
664#define DEFINE_CHANNEL_LAYOUT_DFL_ENTRY(x) CoreAudioChannelLayoutTag { x, #x, AudioChannelSet() }
665#define DEFINE_CHANNEL_LAYOUT_TAG_ENTRY(x, y) CoreAudioChannelLayoutTag { x, #x, y }
666
667class CoreAudioLayoutsUnitTest final : public UnitTest
668{
669public:
670 CoreAudioLayoutsUnitTest()
671 : UnitTest ("Core Audio Layout <-> JUCE channel layout conversion", UnitTestCategories::audio)
672 {}
673
674 // some ambisonic tags which are not explicitly defined
675 enum
676 {
677 kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order = (190U<<16) | 1,
678 kAudioChannelLayoutTag_HOA_ACN_SN3D_1Order = (190U<<16) | 4,
679 kAudioChannelLayoutTag_HOA_ACN_SN3D_2Order = (190U<<16) | 9,
680 kAudioChannelLayoutTag_HOA_ACN_SN3D_3Order = (190U<<16) | 16,
681 kAudioChannelLayoutTag_HOA_ACN_SN3D_4Order = (190U<<16) | 25,
682 kAudioChannelLayoutTag_HOA_ACN_SN3D_5Order = (190U<<16) | 36
683 };
684
685 void runTest() override
686 {
687 auto& knownTags = getAllKnownLayoutTags();
688
689 {
690 // Check that all known tags defined in CoreAudio SDK version 10.12.4 are known to JUCE
691 // Include all defined tags even if there are duplicates as Apple will sometimes change
692 // definitions
693 beginTest ("All CA tags handled");
694
695 for (auto tagEntry : knownTags)
696 {
697 auto labels = CoreAudioLayouts::fromCoreAudio (tagEntry.tag);
698
699 expect (! labels.isDiscreteLayout(), "Tag \"" + String (tagEntry.name) + "\" is not handled by JUCE");
700 }
701 }
702
703 {
704 beginTest ("Number of speakers");
705
706 for (auto tagEntry : knownTags)
707 {
708 auto labels = CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag);
709
710 expect (labels.size() == (tagEntry.tag & 0xffff), "Tag \"" + String (tagEntry.name) + "\" has incorrect channel count");
711 }
712 }
713
714 {
715 beginTest ("No duplicate speaker");
716
717 for (auto tagEntry : knownTags)
718 {
719 auto labels = CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag);
720 labels.sort();
721
722 for (int i = 0; i < (labels.size() - 1); ++i)
723 expect (labels.getReference (i) != labels.getReference (i + 1),
724 "Tag \"" + String (tagEntry.name) + "\" has the same speaker twice");
725 }
726 }
727
728 {
729 beginTest ("CA speaker list and juce layouts are consistent");
730
731 for (auto tagEntry : knownTags)
732 expect (AudioChannelSet::channelSetWithChannels (CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag))
733 == CoreAudioLayouts::fromCoreAudio (tagEntry.tag),
734 "Tag \"" + String (tagEntry.name) + "\" is not converted consistently by JUCE");
735 }
736
737 {
738 beginTest ("AudioChannelSet documentation is correct");
739
740 for (auto tagEntry : knownTags)
741 {
742 if (tagEntry.equivalentChannelSet.isDisabled())
743 continue;
744
745 expect (CoreAudioLayouts::fromCoreAudio (tagEntry.tag) == tagEntry.equivalentChannelSet,
746 "Documentation for tag \"" + String (tagEntry.name) + "\" is incorrect");
747 }
748 }
749
750 {
751 beginTest ("CA tag reverse conversion");
752
753 for (auto tagEntry : knownTags)
754 {
755 if (tagEntry.equivalentChannelSet.isDisabled())
756 continue;
757
758 expect (CoreAudioLayouts::toCoreAudio (tagEntry.equivalentChannelSet) == tagEntry.tag,
759 "Incorrect reverse conversion for tag \"" + String (tagEntry.name) + "\"");
760 }
761 }
762 }
763
764private:
765 struct CoreAudioChannelLayoutTag
766 {
767 AudioChannelLayoutTag tag;
768 const char* name;
769 AudioChannelSet equivalentChannelSet; /* referred to this in the AudioChannelSet documentation */
770 };
771
772 //==============================================================================
773 const Array<CoreAudioChannelLayoutTag>& getAllKnownLayoutTags() const
774 {
775 static CoreAudioChannelLayoutTag tags[] = {
776 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Mono, AudioChannelSet::mono()),
777 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Stereo, AudioChannelSet::stereo()),
778 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_StereoHeadphones),
779 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MatrixStereo),
780 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MidSide),
781 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_XY),
782 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Binaural),
783 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Ambisonic_B_Format),
784 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Quadraphonic, AudioChannelSet::quadraphonic()),
785 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Pentagonal, AudioChannelSet::pentagonal()),
786 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Hexagonal, AudioChannelSet::hexagonal()),
787 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Octagonal, AudioChannelSet::octagonal()),
788 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Cube),
789 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_1_0),
790 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_2_0),
791 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_3_0_A, AudioChannelSet::createLCR()),
792 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_3_0_B),
793 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_4_0_A, AudioChannelSet::createLCRS()),
794 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_4_0_B),
795 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_5_0_A, AudioChannelSet::create5point0()),
796 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_0_B),
797 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_0_C),
798 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_0_D),
799 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_5_1_A, AudioChannelSet::create5point1()),
800 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_1_B),
801 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_1_C),
802 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_5_1_D),
803 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_6_1_A, AudioChannelSet::create6point1()),
804 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_7_1_A, AudioChannelSet::create7point1SDDS()),
805 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MPEG_7_1_B),
806 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_MPEG_7_1_C, AudioChannelSet::create7point1()),
807 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Emagic_Default_7_1),
808 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_SMPTE_DTV),
809 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_1_0),
810 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_2_0),
811 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_ITU_2_1, AudioChannelSet::createLRS()),
812 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_2_2),
813 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_3_0),
814 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_3_1),
815 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_3_2),
816 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_3_2_1),
817 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_ITU_3_4_1),
818 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_0),
819 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_1),
820 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_2),
821 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_3),
822 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_4),
823 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_5),
824 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_6),
825 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_7),
826 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_8),
827 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_9),
828 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_10),
829 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_11),
830 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_12),
831 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_13),
832 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_14),
833 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_15),
834 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_16),
835 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_17),
836 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_18),
837 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_19),
838 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DVD_20),
839 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_4),
840 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_5),
841 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_6),
842 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_8),
843 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_5_0),
844 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_AudioUnit_6_0, AudioChannelSet::create6point0()),
845 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_AudioUnit_7_0, AudioChannelSet::create7point0()),
846 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_AudioUnit_7_0_Front, AudioChannelSet::create7point0SDDS()),
847 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_5_1),
848 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_6_1),
849 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_7_1),
850 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AudioUnit_7_1_Front),
851 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_3_0),
852 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_Quadraphonic),
853 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_4_0),
854 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_5_0),
855 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_5_1),
856 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_6_0),
857 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_6_1),
858 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_7_0),
859 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_7_1),
860 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_7_1_B),
861 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_7_1_C),
862 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AAC_Octagonal),
863 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_TMH_10_2_std),
864 // DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_TMH_10_2_full), no indication on how to handle this tag
865 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_1_0_1),
866 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_3_0),
867 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_3_1),
868 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_3_0_1),
869 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_2_1_1),
870 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_AC3_3_1_1),
871 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC_6_0_A),
872 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC_7_0_A),
873 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_6_1_A),
874 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_6_1_B),
875 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_6_1_C),
876 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_A),
877 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_B),
878 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_C),
879 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_D),
880 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_E),
881 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_F),
882 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_G),
883 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_EAC3_7_1_H),
884 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_3_1),
885 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_4_1),
886 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_DTS_6_0_A, AudioChannelSet::create6point0Music()),
887 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_0_B),
888 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_0_C),
889 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_DTS_6_1_A, AudioChannelSet::create6point1Music()),
890 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_B),
891 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_C),
892 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_7_0),
893 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_7_1),
894 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_0_A),
895 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_0_B),
896 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_A),
897 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_B),
898 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_D),
899 DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_D),
900 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order, AudioChannelSet::ambisonic (0)),
901 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_1Order, AudioChannelSet::ambisonic (1)),
902 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_2Order, AudioChannelSet::ambisonic (2)),
903 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_3Order, AudioChannelSet::ambisonic (3)),
904 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_4Order, AudioChannelSet::ambisonic (4)),
905 DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_5Order, AudioChannelSet::ambisonic (5))
906 };
907 static Array<CoreAudioChannelLayoutTag> knownTags (tags, sizeof (tags) / sizeof (CoreAudioChannelLayoutTag));
908
909 return knownTags;
910 }
911};
912
913static CoreAudioLayoutsUnitTest coreAudioLayoutsUnitTest;
914
915#endif
916
917} // namespace juce
918
919#endif
virtual AudioChannelSet getChannelLayout()
Get the channel layout of the audio stream.
static constexpr uint32 bigEndianInt(const void *bytes) noexcept
Turns 4 bytes into a big-endian integer.
static const char *const keySig
Metadata property name used when reading a caf file time signature information.
static const char *const midiDataBase64
Metadata property name used when reading a caf file with a MIDI chunk.
static const char *const timeSig
Metadata property name used when reading a caf file time signature information.
static const char *const tempo
Metadata property name used when reading a caf file with tempo information.
CoreAudioFormat()
Creates a format object.
static String fromCFString(CFStringRef cfString)
OSX ONLY - Creates a String from an OSX CFString.
T data(T... args)
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
typedef int
typedef float
memcpy
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
void zeromem(void *memory, size_t numBytes) noexcept
Fills a block of memory with zeros.
Definition juce_Memory.h:28
read
T size(T... args)
typedef size_t