OpenShot Audio Library | OpenShotAudio  0.3.1
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 //==============================================================================
562 //==============================================================================
563 #if JUCE_UNIT_TESTS
564 
565 class AudioChannelSetUnitTest : public UnitTest
566 {
567 public:
568  AudioChannelSetUnitTest()
569  : UnitTest ("AudioChannelSetUnitTest", UnitTestCategories::audio)
570  {}
571 
572  void runTest() override
573  {
574  auto max = AudioChannelSet::maxChannelsOfNamedLayout;
575 
576  beginTest ("maxChannelsOfNamedLayout is non-discrete");
577  expect (AudioChannelSet::channelSetsWithNumberOfChannels (max).size() >= 2);
578 
579  beginTest ("channelSetsWithNumberOfChannels returns correct speaker count");
580  {
581  for (auto ch = 1; ch <= max; ++ch)
582  {
583  auto channelSets = AudioChannelSet::channelSetsWithNumberOfChannels (ch);
584 
585  for (auto set : channelSets)
586  expect (set.size() == ch);
587  }
588  }
589 
590  beginTest ("Ambisonics");
591  {
592  uint64 mask = 0;
593 
594  mask |= (1ull << AudioChannelSet::ambisonicACN0);
595  checkAmbisonic (mask, 0, "0th Order Ambisonics");
596 
597  mask |= (1ull << AudioChannelSet::ambisonicACN1) | (1ull << AudioChannelSet::ambisonicACN2) | (1ull << AudioChannelSet::ambisonicACN3);
598  checkAmbisonic (mask, 1, "1st Order Ambisonics");
599 
600  mask |= (1ull << AudioChannelSet::ambisonicACN4) | (1ull << AudioChannelSet::ambisonicACN5) | (1ull << AudioChannelSet::ambisonicACN6)
601  | (1ull << AudioChannelSet::ambisonicACN7) | (1ull << AudioChannelSet::ambisonicACN8);
602  checkAmbisonic (mask, 2, "2nd Order Ambisonics");
603 
604  mask |= (1ull << AudioChannelSet::ambisonicACN9) | (1ull << AudioChannelSet::ambisonicACN10) | (1ull << AudioChannelSet::ambisonicACN11)
605  | (1ull << AudioChannelSet::ambisonicACN12) | (1ull << AudioChannelSet::ambisonicACN13) | (1ull << AudioChannelSet::ambisonicACN14)
606  | (1ull << AudioChannelSet::ambisonicACN15);
607  checkAmbisonic (mask, 3, "3rd Order Ambisonics");
608 
609  mask |= (1ull << AudioChannelSet::ambisonicACN16) | (1ull << AudioChannelSet::ambisonicACN17) | (1ull << AudioChannelSet::ambisonicACN18)
610  | (1ull << AudioChannelSet::ambisonicACN19) | (1ull << AudioChannelSet::ambisonicACN20) | (1ull << AudioChannelSet::ambisonicACN21)
611  | (1ull << AudioChannelSet::ambisonicACN22) | (1ull << AudioChannelSet::ambisonicACN23) | (1ull << AudioChannelSet::ambisonicACN24);
612  checkAmbisonic (mask, 4, "4th Order Ambisonics");
613 
614  mask |= (1ull << AudioChannelSet::ambisonicACN25) | (1ull << AudioChannelSet::ambisonicACN26) | (1ull << AudioChannelSet::ambisonicACN27)
615  | (1ull << AudioChannelSet::ambisonicACN28) | (1ull << AudioChannelSet::ambisonicACN29) | (1ull << AudioChannelSet::ambisonicACN30)
616  | (1ull << AudioChannelSet::ambisonicACN31) | (1ull << AudioChannelSet::ambisonicACN32) | (1ull << AudioChannelSet::ambisonicACN33)
617  | (1ull << AudioChannelSet::ambisonicACN34) | (1ull << AudioChannelSet::ambisonicACN35);
618  checkAmbisonic (mask, 5, "5th Order Ambisonics");
619  }
620  }
621 
622 private:
623  void checkAmbisonic (uint64 mask, int order, const char* layoutName)
624  {
625  auto expected = AudioChannelSet::ambisonic (order);
626  auto numChannels = expected.size();
627 
628  expect (numChannels == BigInteger ((int64) mask).countNumberOfSetBits());
629  expect (channelSetFromMask (mask) == expected);
630 
631  expect (order == expected.getAmbisonicOrder());
632  expect (expected.getDescription() == layoutName);
633 
634  auto layouts = AudioChannelSet::channelSetsWithNumberOfChannels (numChannels);
635  expect (layouts.contains (expected));
636 
637  for (auto layout : layouts)
638  expect (layout.getAmbisonicOrder() == (layout == expected ? order : -1));
639  }
640 
641  static AudioChannelSet channelSetFromMask (uint64 mask)
642  {
644  for (int bit = 0; bit <= 62; ++bit)
645  if ((mask & (1ull << bit)) != 0)
646  channels.add (static_cast<AudioChannelSet::ChannelType> (bit));
647 
648  return AudioChannelSet::channelSetWithChannels (channels);
649  }
650 };
651 
652 static AudioChannelSetUnitTest audioChannelSetUnitTest;
653 
654 #endif
655 
656 } // namespace juce
void add(const ElementType &newElement)
Definition: juce_Array.h:418
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
int getIntValue() const noexcept
int length() const noexcept
void add(String stringToAdd)
void setRange(int startBit, int numBits, bool shouldBeSet)