OpenShot Library | libopenshot-audio  0.2.0
juce_AudioChannelSet.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 
23 namespace juce
24 {
25 
26 
27 
28 AudioChannelSet::AudioChannelSet (uint32 c) : channels (static_cast<int64> (c))
29 {
30 }
31 
32 AudioChannelSet::AudioChannelSet (const Array<ChannelType>& c)
33 {
34  for (auto channel : c)
35  addChannel (channel);
36 }
37 
38 bool AudioChannelSet::operator== (const AudioChannelSet& other) const noexcept { return channels == other.channels; }
39 bool AudioChannelSet::operator!= (const AudioChannelSet& other) const noexcept { return channels != other.channels; }
40 bool AudioChannelSet::operator< (const AudioChannelSet& other) const noexcept { return channels < other.channels; }
41 
42 String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type)
43 {
44  if (type >= discreteChannel0)
45  return "Discrete " + String (type - discreteChannel0 + 1);
46 
47  switch (type)
48  {
49  case left: return NEEDS_TRANS("Left");
50  case right: return NEEDS_TRANS("Right");
51  case centre: return NEEDS_TRANS("Centre");
52  case LFE: return NEEDS_TRANS("LFE");
53  case leftSurround: return NEEDS_TRANS("Left Surround");
54  case rightSurround: return NEEDS_TRANS("Right Surround");
55  case leftCentre: return NEEDS_TRANS("Left Centre");
56  case rightCentre: return NEEDS_TRANS("Right Centre");
57  case centreSurround: return NEEDS_TRANS("Centre Surround");
58  case leftSurroundRear: return NEEDS_TRANS("Left Surround Rear");
59  case rightSurroundRear: return NEEDS_TRANS("Right Surround Rear");
60  case topMiddle: return NEEDS_TRANS("Top Middle");
61  case topFrontLeft: return NEEDS_TRANS("Top Front Left");
62  case topFrontCentre: return NEEDS_TRANS("Top Front Centre");
63  case topFrontRight: return NEEDS_TRANS("Top Front Right");
64  case topRearLeft: return NEEDS_TRANS("Top Rear Left");
65  case topRearCentre: return NEEDS_TRANS("Top Rear Centre");
66  case topRearRight: return NEEDS_TRANS("Top Rear Right");
67  case wideLeft: return NEEDS_TRANS("Wide Left");
68  case wideRight: return NEEDS_TRANS("Wide Right");
69  case LFE2: return NEEDS_TRANS("LFE 2");
70  case leftSurroundSide: return NEEDS_TRANS("Left Surround Side");
71  case rightSurroundSide: return NEEDS_TRANS("Right Surround Side");
72  case ambisonicW: return NEEDS_TRANS("Ambisonic W");
73  case ambisonicX: return NEEDS_TRANS("Ambisonic X");
74  case ambisonicY: return NEEDS_TRANS("Ambisonic Y");
75  case ambisonicZ: return NEEDS_TRANS("Ambisonic Z");
76  case topSideLeft: return NEEDS_TRANS("Top Side Left");
77  case topSideRight: return NEEDS_TRANS("Top Side Right");
78  case ambisonicACN4: return NEEDS_TRANS("Ambisonic 4");
79  case ambisonicACN5: return NEEDS_TRANS("Ambisonic 5");
80  case ambisonicACN6: return NEEDS_TRANS("Ambisonic 6");
81  case ambisonicACN7: return NEEDS_TRANS("Ambisonic 7");
82  case ambisonicACN8: return NEEDS_TRANS("Ambisonic 8");
83  case ambisonicACN9: return NEEDS_TRANS("Ambisonic 9");
84  case ambisonicACN10: return NEEDS_TRANS("Ambisonic 10");
85  case ambisonicACN11: return NEEDS_TRANS("Ambisonic 11");
86  case ambisonicACN12: return NEEDS_TRANS("Ambisonic 12");
87  case ambisonicACN13: return NEEDS_TRANS("Ambisonic 13");
88  case ambisonicACN14: return NEEDS_TRANS("Ambisonic 14");
89  case ambisonicACN15: return NEEDS_TRANS("Ambisonic 15");
90  case bottomFrontLeft: return NEEDS_TRANS("Bottom Front Left");
91  case bottomFrontCentre: return NEEDS_TRANS("Bottom Front Centre");
92  case bottomFrontRight: return NEEDS_TRANS("Bottom Front Right");
93  case bottomSideLeft: return NEEDS_TRANS("Bottom Side Left");
94  case bottomSideRight: return NEEDS_TRANS("Bottom Side Right");
95  case bottomRearLeft: return NEEDS_TRANS("Bottom Rear Left");
96  case bottomRearCentre: return NEEDS_TRANS("Bottom Rear Centre");
97  case bottomRearRight: return NEEDS_TRANS("Bottom Rear Right");
98  case discreteChannel0: return NEEDS_TRANS("Discrete channel");
99  default: break;
100  }
101 
102  return "Unknown";
103 }
104 
105 String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelType type)
106 {
107  if (type >= discreteChannel0)
108  return String (type - discreteChannel0 + 1);
109 
110  switch (type)
111  {
112  case left: return "L";
113  case right: return "R";
114  case centre: return "C";
115  case LFE: return "Lfe";
116  case leftSurround: return "Ls";
117  case rightSurround: return "Rs";
118  case leftCentre: return "Lc";
119  case rightCentre: return "Rc";
120  case centreSurround: return "Cs";
121  case leftSurroundRear: return "Lrs";
122  case rightSurroundRear: return "Rrs";
123  case topMiddle: return "Tm";
124  case topFrontLeft: return "Tfl";
125  case topFrontCentre: return "Tfc";
126  case topFrontRight: return "Tfr";
127  case topRearLeft: return "Trl";
128  case topRearCentre: return "Trc";
129  case topRearRight: return "Trr";
130  case wideLeft: return "Wl";
131  case wideRight: return "Wr";
132  case LFE2: return "Lfe2";
133  case leftSurroundSide: return "Lss";
134  case rightSurroundSide: return "Rss";
135  case ambisonicACN0: return "ACN0";
136  case ambisonicACN1: return "ACN1";
137  case ambisonicACN2: return "ACN2";
138  case ambisonicACN3: return "ACN3";
139  case ambisonicACN4: return "ACN4";
140  case ambisonicACN5: return "ACN5";
141  case ambisonicACN6: return "ACN6";
142  case ambisonicACN7: return "ACN7";
143  case ambisonicACN8: return "ACN8";
144  case ambisonicACN9: return "ACN9";
145  case ambisonicACN10: return "ACN10";
146  case ambisonicACN11: return "ACN11";
147  case ambisonicACN12: return "ACN12";
148  case ambisonicACN13: return "ACN13";
149  case ambisonicACN14: return "ACN14";
150  case ambisonicACN15: return "ACN15";
151  case topSideLeft: return "Tsl";
152  case topSideRight: return "Tsr";
153  case bottomFrontLeft: return "Bfl";
154  case bottomFrontCentre: return "Bfc";
155  case bottomFrontRight: return "Bfr";
156  case bottomSideLeft: return "Bsl";
157  case bottomSideRight: return "Bsr";
158  case bottomRearLeft: return "Brl";
159  case bottomRearCentre: return "Brc";
160  case bottomRearRight: return "Brr";
161  default: break;
162  }
163 
164  if (type >= ambisonicACN4 && type <= ambisonicACN35)
165  return "ACN" + String (type - ambisonicACN4 + 4);
166 
167  return {};
168 }
169 
170 AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (const String& abbr)
171 {
172  if (abbr.length() > 0 && (abbr[0] >= '0' && abbr[0] <= '9'))
173  return static_cast<AudioChannelSet::ChannelType> (static_cast<int> (discreteChannel0)
174  + abbr.getIntValue() - 1);
175 
176  if (abbr == "L") return left;
177  if (abbr == "R") return right;
178  if (abbr == "C") return centre;
179  if (abbr == "Lfe") return LFE;
180  if (abbr == "Ls") return leftSurround;
181  if (abbr == "Rs") return rightSurround;
182  if (abbr == "Lc") return leftCentre;
183  if (abbr == "Rc") return rightCentre;
184  if (abbr == "Cs") return centreSurround;
185  if (abbr == "Lrs") return leftSurroundRear;
186  if (abbr == "Rrs") return rightSurroundRear;
187  if (abbr == "Tm") return topMiddle;
188  if (abbr == "Tfl") return topFrontLeft;
189  if (abbr == "Tfc") return topFrontCentre;
190  if (abbr == "Tfr") return topFrontRight;
191  if (abbr == "Trl") return topRearLeft;
192  if (abbr == "Trc") return topRearCentre;
193  if (abbr == "Trr") return topRearRight;
194  if (abbr == "Wl") return wideLeft;
195  if (abbr == "Wr") return wideRight;
196  if (abbr == "Lfe2") return LFE2;
197  if (abbr == "Lss") return leftSurroundSide;
198  if (abbr == "Rss") return rightSurroundSide;
199  if (abbr == "W") return ambisonicW;
200  if (abbr == "X") return ambisonicX;
201  if (abbr == "Y") return ambisonicY;
202  if (abbr == "Z") return ambisonicZ;
203  if (abbr == "ACN0") return ambisonicACN0;
204  if (abbr == "ACN1") return ambisonicACN1;
205  if (abbr == "ACN2") return ambisonicACN2;
206  if (abbr == "ACN3") return ambisonicACN3;
207  if (abbr == "ACN4") return ambisonicACN4;
208  if (abbr == "ACN5") return ambisonicACN5;
209  if (abbr == "ACN6") return ambisonicACN6;
210  if (abbr == "ACN7") return ambisonicACN7;
211  if (abbr == "ACN8") return ambisonicACN8;
212  if (abbr == "ACN9") return ambisonicACN9;
213  if (abbr == "ACN10") return ambisonicACN10;
214  if (abbr == "ACN11") return ambisonicACN11;
215  if (abbr == "ACN12") return ambisonicACN12;
216  if (abbr == "ACN13") return ambisonicACN13;
217  if (abbr == "ACN14") return ambisonicACN14;
218  if (abbr == "ACN15") return ambisonicACN15;
219  if (abbr == "Tsl") return topSideLeft;
220  if (abbr == "Tsr") return topSideRight;
221  if (abbr == "Bfl") return bottomFrontLeft;
222  if (abbr == "Bfc") return bottomFrontCentre;
223  if (abbr == "Bfr") return bottomFrontRight;
224  if (abbr == "Bsl") return bottomSideLeft;
225  if (abbr == "Bsr") return bottomSideRight;
226  if (abbr == "Brl") return bottomRearLeft;
227  if (abbr == "Brc") return bottomRearCentre;
228  if (abbr == "Brr") return bottomRearRight;
229  return unknown;
230 }
231 
232 String AudioChannelSet::getSpeakerArrangementAsString() const
233 {
234  StringArray speakerTypes;
235 
236  for (auto& speaker : getChannelTypes())
237  {
238  auto name = getAbbreviatedChannelTypeName (speaker);
239 
240  if (name.isNotEmpty())
241  speakerTypes.add (name);
242  }
243 
244  return speakerTypes.joinIntoString (" ");
245 }
246 
247 AudioChannelSet AudioChannelSet::fromAbbreviatedString (const String& str)
248 {
249  AudioChannelSet set;
250 
251  for (auto& abbr : StringArray::fromTokens (str, true))
252  {
253  auto type = getChannelTypeFromAbbreviation (abbr);
254 
255  if (type != unknown)
256  set.addChannel (type);
257  }
258 
259  return set;
260 }
261 
262 String AudioChannelSet::getDescription() const
263 {
264  if (isDiscreteLayout()) return "Discrete #" + String (size());
265  if (*this == disabled()) return "Disabled";
266  if (*this == mono()) return "Mono";
267  if (*this == stereo()) return "Stereo";
268 
269  if (*this == createLCR()) return "LCR";
270  if (*this == createLRS()) return "LRS";
271  if (*this == createLCRS()) return "LCRS";
272 
273  if (*this == create5point0()) return "5.0 Surround";
274  if (*this == create5point1()) return "5.1 Surround";
275  if (*this == create6point0()) return "6.0 Surround";
276  if (*this == create6point1()) return "6.1 Surround";
277  if (*this == create6point0Music()) return "6.0 (Music) Surround";
278  if (*this == create6point1Music()) return "6.1 (Music) Surround";
279  if (*this == create7point0()) return "7.0 Surround";
280  if (*this == create7point1()) return "7.1 Surround";
281  if (*this == create7point0SDDS()) return "7.0 Surround SDDS";
282  if (*this == create7point1SDDS()) return "7.1 Surround SDDS";
283  if (*this == create7point0point2()) return "7.0.2 Surround";
284  if (*this == create7point1point2()) return "7.1.2 Surround";
285 
286  if (*this == quadraphonic()) return "Quadraphonic";
287  if (*this == pentagonal()) return "Pentagonal";
288  if (*this == hexagonal()) return "Hexagonal";
289  if (*this == octagonal()) return "Octagonal";
290 
291  // ambisonics
292  {
293  auto order = getAmbisonicOrder();
294 
295  if (order >= 0)
296  {
297  String suffix;
298 
299  switch (order)
300  {
301  case 1: suffix = "st"; break;
302  case 2: suffix = "nd"; break;
303  case 3: suffix = "rd"; break;
304  default: suffix = "th"; break;
305  }
306 
307  return String (order) + suffix + " Order Ambisonics";
308  }
309  }
310 
311  return "Unknown";
312 }
313 
314 bool AudioChannelSet::isDiscreteLayout() const noexcept
315 {
316  for (auto& speaker : getChannelTypes())
317  if (speaker <= ambisonicACN35)
318  return false;
319 
320  return true;
321 }
322 
323 int AudioChannelSet::size() const noexcept
324 {
325  return channels.countNumberOfSetBits();
326 }
327 
328 AudioChannelSet::ChannelType AudioChannelSet::getTypeOfChannel (int index) const noexcept
329 {
330  int bit = channels.findNextSetBit(0);
331 
332  for (int i = 0; i < index && bit >= 0; ++i)
333  bit = channels.findNextSetBit (bit + 1);
334 
335  return static_cast<ChannelType> (bit);
336 }
337 
338 int AudioChannelSet::getChannelIndexForType (AudioChannelSet::ChannelType type) const noexcept
339 {
340  int idx = 0;
341 
342  for (int bit = channels.findNextSetBit (0); bit >= 0; bit = channels.findNextSetBit (bit + 1))
343  {
344  if (static_cast<ChannelType> (bit) == type)
345  return idx;
346 
347  idx++;
348  }
349 
350  return -1;
351 }
352 
353 Array<AudioChannelSet::ChannelType> AudioChannelSet::getChannelTypes() const
354 {
355  Array<ChannelType> result;
356 
357  for (int bit = channels.findNextSetBit(0); bit >= 0; bit = channels.findNextSetBit (bit + 1))
358  result.add (static_cast<ChannelType> (bit));
359 
360  return result;
361 }
362 
363 void AudioChannelSet::addChannel (ChannelType newChannel)
364 {
365  const int bit = static_cast<int> (newChannel);
366  jassert (bit >= 0 && bit < 1024);
367  channels.setBit (bit);
368 }
369 
370 void AudioChannelSet::removeChannel (ChannelType newChannel)
371 {
372  const int bit = static_cast<int> (newChannel);
373  jassert (bit >= 0 && bit < 1024);
374  channels.clearBit (bit);
375 }
376 
377 AudioChannelSet AudioChannelSet::disabled() { return {}; }
378 AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet (1u << centre); }
379 AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ((1u << left) | (1u << right)); }
380 AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre)); }
381 AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << surround)); }
382 AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << surround)); }
383 AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround)); }
384 AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround)); }
385 AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
386 AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
387 AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
388 AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
389 AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
390 AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
391 AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
392 AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
393 AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround)); }
394 AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
395 AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
396 AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround) | (1u << wideLeft) | (1u << wideRight)); }
397 AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
398 AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
399 
400 AudioChannelSet AudioChannelSet::ambisonic (int order)
401 {
402  jassert (isPositiveAndBelow (order, 6));
403 
404  if (order == 0)
405  return AudioChannelSet ((uint32) (1 << ambisonicACN0));
406 
407  AudioChannelSet set ((1u << ambisonicACN0) | (1u << ambisonicACN1) | (1u << ambisonicACN2) | (1u << ambisonicACN3));
408 
409  auto numAmbisonicChannels = (order + 1) * (order + 1);
410  set.channels.setRange (ambisonicACN4, numAmbisonicChannels - 4, true);
411 
412  return set;
413 }
414 
415 int AudioChannelSet::getAmbisonicOrder() const
416 {
417  auto ambisonicOrder = getAmbisonicOrderForNumChannels (size());
418 
419  if (ambisonicOrder >= 0)
420  return (*this == ambisonic (ambisonicOrder) ? ambisonicOrder : -1);
421 
422  return -1;
423 }
424 
425 AudioChannelSet AudioChannelSet::discreteChannels (int numChannels)
426 {
427  AudioChannelSet s;
428  s.channels.setRange (discreteChannel0, numChannels, true);
429  return s;
430 }
431 
432 AudioChannelSet AudioChannelSet::canonicalChannelSet (int numChannels)
433 {
434  if (numChannels == 1) return AudioChannelSet::mono();
435  if (numChannels == 2) return AudioChannelSet::stereo();
436  if (numChannels == 3) return AudioChannelSet::createLCR();
437  if (numChannels == 4) return AudioChannelSet::quadraphonic();
438  if (numChannels == 5) return AudioChannelSet::create5point0();
439  if (numChannels == 6) return AudioChannelSet::create5point1();
440  if (numChannels == 7) return AudioChannelSet::create7point0();
441  if (numChannels == 8) return AudioChannelSet::create7point1();
442 
443  return discreteChannels (numChannels);
444 }
445 
446 AudioChannelSet AudioChannelSet::namedChannelSet (int numChannels)
447 {
448  if (numChannels == 1) return AudioChannelSet::mono();
449  if (numChannels == 2) return AudioChannelSet::stereo();
450  if (numChannels == 3) return AudioChannelSet::createLCR();
451  if (numChannels == 4) return AudioChannelSet::quadraphonic();
452  if (numChannels == 5) return AudioChannelSet::create5point0();
453  if (numChannels == 6) return AudioChannelSet::create5point1();
454  if (numChannels == 7) return AudioChannelSet::create7point0();
455  if (numChannels == 8) return AudioChannelSet::create7point1();
456 
457  return {};
458 }
459 
460 Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int numChannels)
461 {
462  Array<AudioChannelSet> retval;
463 
464  if (numChannels != 0)
465  {
466  retval.add (AudioChannelSet::discreteChannels (numChannels));
467 
468  if (numChannels == 1)
469  {
470  retval.add (AudioChannelSet::mono());
471  }
472  else if (numChannels == 2)
473  {
474  retval.add (AudioChannelSet::stereo());
475  }
476  else if (numChannels == 3)
477  {
478  retval.add (AudioChannelSet::createLCR());
479  retval.add (AudioChannelSet::createLRS());
480  }
481  else if (numChannels == 4)
482  {
483  retval.add (AudioChannelSet::quadraphonic());
484  retval.add (AudioChannelSet::createLCRS());
485  }
486  else if (numChannels == 5)
487  {
488  retval.add (AudioChannelSet::create5point0());
489  retval.add (AudioChannelSet::pentagonal());
490  }
491  else if (numChannels == 6)
492  {
493  retval.add (AudioChannelSet::create5point1());
494  retval.add (AudioChannelSet::create6point0());
495  retval.add (AudioChannelSet::create6point0Music());
496  retval.add (AudioChannelSet::hexagonal());
497  }
498  else if (numChannels == 7)
499  {
500  retval.add (AudioChannelSet::create7point0());
501  retval.add (AudioChannelSet::create7point0SDDS());
502  retval.add (AudioChannelSet::create6point1());
503  retval.add (AudioChannelSet::create6point1Music());
504  }
505  else if (numChannels == 8)
506  {
507  retval.add (AudioChannelSet::create7point1());
508  retval.add (AudioChannelSet::create7point1SDDS());
509  retval.add (AudioChannelSet::octagonal());
510  }
511 
512  auto order = getAmbisonicOrderForNumChannels (numChannels);
513  if (order >= 0)
514  retval.add (AudioChannelSet::ambisonic (order));
515  }
516 
517  return retval;
518 }
519 
520 AudioChannelSet JUCE_CALLTYPE AudioChannelSet::channelSetWithChannels (const Array<ChannelType>& channelArray)
521 {
522  AudioChannelSet set;
523 
524  for (auto ch : channelArray)
525  {
526  jassert (! set.channels[static_cast<int> (ch)]);
527 
528  set.addChannel (ch);
529  }
530 
531  return set;
532 }
533 
534 //==============================================================================
535 AudioChannelSet JUCE_CALLTYPE AudioChannelSet::fromWaveChannelMask (int32 dwChannelMask)
536 {
537  return AudioChannelSet (static_cast<uint32> ((dwChannelMask & ((1 << 18) - 1)) << 1));
538 }
539 
540 int32 AudioChannelSet::getWaveChannelMask() const noexcept
541 {
542  if (channels.getHighestBit() > topRearRight)
543  return -1;
544 
545  return (channels.toInteger() >> 1);
546 }
547 
548 //==============================================================================
549 int JUCE_CALLTYPE AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels)
550 {
551  auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f;
552  auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne)));
553 
554  if (ambisonicOrder > 5)
555  return -1;
556 
557  return (static_cast<float> (ambisonicOrder) == sqrtMinusOne ? ambisonicOrder : -1);
558 }
559 
560 //==============================================================================
561 #if JUCE_UNIT_TESTS
562 class AudioChannelSetUnitTest : public UnitTest
563 {
564 public:
565  AudioChannelSetUnitTest() : UnitTest ("AudioChannelSetUnitTest", "Audio") {}
566 
567  void runTest() override
568  {
569  auto max = AudioChannelSet::maxChannelsOfNamedLayout;
570 
571  beginTest ("maxChannelsOfNamedLayout is non-discrete");
572  expect (AudioChannelSet::channelSetsWithNumberOfChannels (max).size() >= 2);
573 
574  beginTest ("channelSetsWithNumberOfChannels returns correct speaker count");
575  {
576  for (auto ch = 1; ch <= max; ++ch)
577  {
578  auto channelSets = AudioChannelSet::channelSetsWithNumberOfChannels (ch);
579 
580  for (auto set : channelSets)
581  expect (set.size() == ch);
582  }
583  }
584 
585  beginTest ("Ambisonics");
586  {
587  uint64 mask = 0;
588 
589  mask |= (1ull << AudioChannelSet::ambisonicACN0);
590  checkAmbisonic (mask, 0, "0th Order Ambisonics");
591 
592  mask |= (1ull << AudioChannelSet::ambisonicACN1) | (1ull << AudioChannelSet::ambisonicACN2) | (1ull << AudioChannelSet::ambisonicACN3);
593  checkAmbisonic (mask, 1, "1st Order Ambisonics");
594 
595  mask |= (1ull << AudioChannelSet::ambisonicACN4) | (1ull << AudioChannelSet::ambisonicACN5) | (1ull << AudioChannelSet::ambisonicACN6)
596  | (1ull << AudioChannelSet::ambisonicACN7) | (1ull << AudioChannelSet::ambisonicACN8);
597  checkAmbisonic (mask, 2, "2nd Order Ambisonics");
598 
599  mask |= (1ull << AudioChannelSet::ambisonicACN9) | (1ull << AudioChannelSet::ambisonicACN10) | (1ull << AudioChannelSet::ambisonicACN11)
600  | (1ull << AudioChannelSet::ambisonicACN12) | (1ull << AudioChannelSet::ambisonicACN13) | (1ull << AudioChannelSet::ambisonicACN14)
601  | (1ull << AudioChannelSet::ambisonicACN15);
602  checkAmbisonic (mask, 3, "3rd Order Ambisonics");
603 
604  mask |= (1ull << AudioChannelSet::ambisonicACN16) | (1ull << AudioChannelSet::ambisonicACN17) | (1ull << AudioChannelSet::ambisonicACN18)
605  | (1ull << AudioChannelSet::ambisonicACN19) | (1ull << AudioChannelSet::ambisonicACN20) | (1ull << AudioChannelSet::ambisonicACN21)
606  | (1ull << AudioChannelSet::ambisonicACN22) | (1ull << AudioChannelSet::ambisonicACN23) | (1ull << AudioChannelSet::ambisonicACN24);
607  checkAmbisonic (mask, 4, "4th Order Ambisonics");
608 
609  mask |= (1ull << AudioChannelSet::ambisonicACN25) | (1ull << AudioChannelSet::ambisonicACN26) | (1ull << AudioChannelSet::ambisonicACN27)
610  | (1ull << AudioChannelSet::ambisonicACN28) | (1ull << AudioChannelSet::ambisonicACN29) | (1ull << AudioChannelSet::ambisonicACN30)
611  | (1ull << AudioChannelSet::ambisonicACN31) | (1ull << AudioChannelSet::ambisonicACN32) | (1ull << AudioChannelSet::ambisonicACN33)
612  | (1ull << AudioChannelSet::ambisonicACN34) | (1ull << AudioChannelSet::ambisonicACN35);
613  checkAmbisonic (mask, 5, "5th Order Ambisonics");
614  }
615  }
616 
617 private:
618  void checkAmbisonic (uint64 mask, int order, const char* layoutName)
619  {
620  auto expected = AudioChannelSet::ambisonic (order);
621  auto numChannels = expected.size();
622 
623  expect (numChannels == BigInteger ((int64) mask).countNumberOfSetBits());
624  expect (channelSetFromMask (mask) == expected);
625 
626  expect (order == expected.getAmbisonicOrder());
627  expect (expected.getDescription() == layoutName);
628 
629  auto layouts = AudioChannelSet::channelSetsWithNumberOfChannels (numChannels);
630  expect (layouts.contains (expected));
631 
632  for (auto layout : layouts)
633  expect (layout.getAmbisonicOrder() == (layout == expected ? order : -1));
634  }
635 
636  static AudioChannelSet channelSetFromMask (uint64 mask)
637  {
638  Array<AudioChannelSet::ChannelType> channels;
639  for (int bit = 0; bit <= 62; ++bit)
640  if ((mask & (1ull << bit)) != 0)
641  channels.add (static_cast<AudioChannelSet::ChannelType> (bit));
642 
643  return AudioChannelSet::channelSetWithChannels (channels);
644  }
645 };
646 
647 static AudioChannelSetUnitTest audioChannelSetUnitTest;
648 #endif
649 
650 } // namespace juce
juce::StringArray
A special array for holding a list of strings.
Definition: juce_StringArray.h:38
juce::Array::add
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:375
juce::StringArray::joinIntoString
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
Joins the strings in the array together into one string.
Definition: juce_StringArray.cpp:288
juce::Array
Holds a resizable array of primitive or copy-by-value objects.
Definition: juce_Array.h:59
juce::AudioChannelSet::addChannel
void addChannel(ChannelType newChannelType)
Adds a channel to the set.
Definition: juce_AudioChannelSet.cpp:363
juce::AudioChannelSet
Represents a set of audio channel types.
Definition: juce_AudioChannelSet.h:50
juce::AudioChannelSet::ChannelType
ChannelType
Represents different audio channel types.
Definition: juce_AudioChannelSet.h:279
juce::String::length
int length() const noexcept
Returns the number of characters in the string.
Definition: juce_String.cpp:518
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::BigInteger::setRange
void setRange(int startBit, int numBits, bool shouldBeSet)
Sets a range of bits to be either on or off.
Definition: juce_BigInteger.cpp:325
juce::StringArray::add
void add(String stringToAdd)
Appends a string at the end of the array.
Definition: juce_StringArray.cpp:135
juce::String::getIntValue
int getIntValue() const noexcept
Reads the value of the string as a decimal number (up to 32 bits in size).
Definition: juce_String.cpp:1869
juce::AudioChannelSet::AudioChannelSet
AudioChannelSet()=default
Creates an empty channel set.