build(deps): vendor JUCE 7.0.12
This commit is contained in:
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
|
||||
|
||||
AudioChannelSet::AudioChannelSet (uint32 c) : channels (static_cast<int64> (c))
|
||||
{
|
||||
}
|
||||
|
||||
AudioChannelSet::AudioChannelSet (const std::initializer_list<ChannelType>& c)
|
||||
{
|
||||
for (auto channel : c)
|
||||
addChannel (channel);
|
||||
}
|
||||
|
||||
bool AudioChannelSet::operator== (const AudioChannelSet& other) const noexcept { return channels == other.channels; }
|
||||
bool AudioChannelSet::operator!= (const AudioChannelSet& other) const noexcept { return channels != other.channels; }
|
||||
bool AudioChannelSet::operator< (const AudioChannelSet& other) const noexcept { return channels < other.channels; }
|
||||
|
||||
String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type)
|
||||
{
|
||||
if (type >= discreteChannel0)
|
||||
return "Discrete " + String (type - discreteChannel0 + 1);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case left: return NEEDS_TRANS ("Left");
|
||||
case right: return NEEDS_TRANS ("Right");
|
||||
case centre: return NEEDS_TRANS ("Centre");
|
||||
case LFE: return NEEDS_TRANS ("LFE");
|
||||
case leftSurround: return NEEDS_TRANS ("Left Surround");
|
||||
case rightSurround: return NEEDS_TRANS ("Right Surround");
|
||||
case leftCentre: return NEEDS_TRANS ("Left Centre");
|
||||
case rightCentre: return NEEDS_TRANS ("Right Centre");
|
||||
case centreSurround: return NEEDS_TRANS ("Centre Surround");
|
||||
case leftSurroundRear: return NEEDS_TRANS ("Left Surround Rear");
|
||||
case rightSurroundRear: return NEEDS_TRANS ("Right Surround Rear");
|
||||
case topMiddle: return NEEDS_TRANS ("Top Middle");
|
||||
case topFrontLeft: return NEEDS_TRANS ("Top Front Left");
|
||||
case topFrontCentre: return NEEDS_TRANS ("Top Front Centre");
|
||||
case topFrontRight: return NEEDS_TRANS ("Top Front Right");
|
||||
case topRearLeft: return NEEDS_TRANS ("Top Rear Left");
|
||||
case topRearCentre: return NEEDS_TRANS ("Top Rear Centre");
|
||||
case topRearRight: return NEEDS_TRANS ("Top Rear Right");
|
||||
case wideLeft: return NEEDS_TRANS ("Wide Left");
|
||||
case wideRight: return NEEDS_TRANS ("Wide Right");
|
||||
case LFE2: return NEEDS_TRANS ("LFE 2");
|
||||
case leftSurroundSide: return NEEDS_TRANS ("Left Surround Side");
|
||||
case rightSurroundSide: return NEEDS_TRANS ("Right Surround Side");
|
||||
case ambisonicW: return NEEDS_TRANS ("Ambisonic W");
|
||||
case ambisonicX: return NEEDS_TRANS ("Ambisonic X");
|
||||
case ambisonicY: return NEEDS_TRANS ("Ambisonic Y");
|
||||
case ambisonicZ: return NEEDS_TRANS ("Ambisonic Z");
|
||||
case topSideLeft: return NEEDS_TRANS ("Top Side Left");
|
||||
case topSideRight: return NEEDS_TRANS ("Top Side Right");
|
||||
case ambisonicACN4: return NEEDS_TRANS ("Ambisonic 4");
|
||||
case ambisonicACN5: return NEEDS_TRANS ("Ambisonic 5");
|
||||
case ambisonicACN6: return NEEDS_TRANS ("Ambisonic 6");
|
||||
case ambisonicACN7: return NEEDS_TRANS ("Ambisonic 7");
|
||||
case ambisonicACN8: return NEEDS_TRANS ("Ambisonic 8");
|
||||
case ambisonicACN9: return NEEDS_TRANS ("Ambisonic 9");
|
||||
case ambisonicACN10: return NEEDS_TRANS ("Ambisonic 10");
|
||||
case ambisonicACN11: return NEEDS_TRANS ("Ambisonic 11");
|
||||
case ambisonicACN12: return NEEDS_TRANS ("Ambisonic 12");
|
||||
case ambisonicACN13: return NEEDS_TRANS ("Ambisonic 13");
|
||||
case ambisonicACN14: return NEEDS_TRANS ("Ambisonic 14");
|
||||
case ambisonicACN15: return NEEDS_TRANS ("Ambisonic 15");
|
||||
case ambisonicACN16: return NEEDS_TRANS ("Ambisonic 16");
|
||||
case ambisonicACN17: return NEEDS_TRANS ("Ambisonic 17");
|
||||
case ambisonicACN18: return NEEDS_TRANS ("Ambisonic 18");
|
||||
case ambisonicACN19: return NEEDS_TRANS ("Ambisonic 19");
|
||||
case ambisonicACN20: return NEEDS_TRANS ("Ambisonic 20");
|
||||
case ambisonicACN21: return NEEDS_TRANS ("Ambisonic 21");
|
||||
case ambisonicACN22: return NEEDS_TRANS ("Ambisonic 22");
|
||||
case ambisonicACN23: return NEEDS_TRANS ("Ambisonic 23");
|
||||
case ambisonicACN24: return NEEDS_TRANS ("Ambisonic 24");
|
||||
case ambisonicACN25: return NEEDS_TRANS ("Ambisonic 25");
|
||||
case ambisonicACN26: return NEEDS_TRANS ("Ambisonic 26");
|
||||
case ambisonicACN27: return NEEDS_TRANS ("Ambisonic 27");
|
||||
case ambisonicACN28: return NEEDS_TRANS ("Ambisonic 28");
|
||||
case ambisonicACN29: return NEEDS_TRANS ("Ambisonic 29");
|
||||
case ambisonicACN30: return NEEDS_TRANS ("Ambisonic 30");
|
||||
case ambisonicACN31: return NEEDS_TRANS ("Ambisonic 31");
|
||||
case ambisonicACN32: return NEEDS_TRANS ("Ambisonic 32");
|
||||
case ambisonicACN33: return NEEDS_TRANS ("Ambisonic 33");
|
||||
case ambisonicACN34: return NEEDS_TRANS ("Ambisonic 34");
|
||||
case ambisonicACN35: return NEEDS_TRANS ("Ambisonic 35");
|
||||
case ambisonicACN36: return NEEDS_TRANS ("Ambisonic 36");
|
||||
case ambisonicACN37: return NEEDS_TRANS ("Ambisonic 37");
|
||||
case ambisonicACN38: return NEEDS_TRANS ("Ambisonic 38");
|
||||
case ambisonicACN39: return NEEDS_TRANS ("Ambisonic 39");
|
||||
case ambisonicACN40: return NEEDS_TRANS ("Ambisonic 40");
|
||||
case ambisonicACN41: return NEEDS_TRANS ("Ambisonic 41");
|
||||
case ambisonicACN42: return NEEDS_TRANS ("Ambisonic 42");
|
||||
case ambisonicACN43: return NEEDS_TRANS ("Ambisonic 43");
|
||||
case ambisonicACN44: return NEEDS_TRANS ("Ambisonic 44");
|
||||
case ambisonicACN45: return NEEDS_TRANS ("Ambisonic 45");
|
||||
case ambisonicACN46: return NEEDS_TRANS ("Ambisonic 46");
|
||||
case ambisonicACN47: return NEEDS_TRANS ("Ambisonic 47");
|
||||
case ambisonicACN48: return NEEDS_TRANS ("Ambisonic 48");
|
||||
case ambisonicACN49: return NEEDS_TRANS ("Ambisonic 49");
|
||||
case ambisonicACN50: return NEEDS_TRANS ("Ambisonic 50");
|
||||
case ambisonicACN51: return NEEDS_TRANS ("Ambisonic 51");
|
||||
case ambisonicACN52: return NEEDS_TRANS ("Ambisonic 52");
|
||||
case ambisonicACN53: return NEEDS_TRANS ("Ambisonic 53");
|
||||
case ambisonicACN54: return NEEDS_TRANS ("Ambisonic 54");
|
||||
case ambisonicACN55: return NEEDS_TRANS ("Ambisonic 55");
|
||||
case ambisonicACN56: return NEEDS_TRANS ("Ambisonic 56");
|
||||
case ambisonicACN57: return NEEDS_TRANS ("Ambisonic 57");
|
||||
case ambisonicACN58: return NEEDS_TRANS ("Ambisonic 58");
|
||||
case ambisonicACN59: return NEEDS_TRANS ("Ambisonic 59");
|
||||
case ambisonicACN60: return NEEDS_TRANS ("Ambisonic 60");
|
||||
case ambisonicACN61: return NEEDS_TRANS ("Ambisonic 61");
|
||||
case ambisonicACN62: return NEEDS_TRANS ("Ambisonic 62");
|
||||
case ambisonicACN63: return NEEDS_TRANS ("Ambisonic 63");
|
||||
case bottomFrontLeft: return NEEDS_TRANS ("Bottom Front Left");
|
||||
case bottomFrontCentre: return NEEDS_TRANS ("Bottom Front Centre");
|
||||
case bottomFrontRight: return NEEDS_TRANS ("Bottom Front Right");
|
||||
case proximityLeft: return NEEDS_TRANS ("Proximity Left");
|
||||
case proximityRight: return NEEDS_TRANS ("Proximity Right");
|
||||
case bottomSideLeft: return NEEDS_TRANS ("Bottom Side Left");
|
||||
case bottomSideRight: return NEEDS_TRANS ("Bottom Side Right");
|
||||
case bottomRearLeft: return NEEDS_TRANS ("Bottom Rear Left");
|
||||
case bottomRearCentre: return NEEDS_TRANS ("Bottom Rear Centre");
|
||||
case bottomRearRight: return NEEDS_TRANS ("Bottom Rear Right");
|
||||
case discreteChannel0:
|
||||
case unknown:
|
||||
default: break;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelType type)
|
||||
{
|
||||
if (type >= discreteChannel0)
|
||||
return String (type - discreteChannel0 + 1);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case left: return "L";
|
||||
case right: return "R";
|
||||
case centre: return "C";
|
||||
case LFE: return "Lfe";
|
||||
case leftSurround: return "Ls";
|
||||
case rightSurround: return "Rs";
|
||||
case leftCentre: return "Lc";
|
||||
case rightCentre: return "Rc";
|
||||
case centreSurround: return "Cs";
|
||||
case leftSurroundRear: return "Lrs";
|
||||
case rightSurroundRear: return "Rrs";
|
||||
case topMiddle: return "Tm";
|
||||
case topFrontLeft: return "Tfl";
|
||||
case topFrontCentre: return "Tfc";
|
||||
case topFrontRight: return "Tfr";
|
||||
case topRearLeft: return "Trl";
|
||||
case topRearCentre: return "Trc";
|
||||
case topRearRight: return "Trr";
|
||||
case wideLeft: return "Wl";
|
||||
case wideRight: return "Wr";
|
||||
case LFE2: return "Lfe2";
|
||||
case leftSurroundSide: return "Lss";
|
||||
case rightSurroundSide: return "Rss";
|
||||
case ambisonicACN0: return "ACN0";
|
||||
case ambisonicACN1: return "ACN1";
|
||||
case ambisonicACN2: return "ACN2";
|
||||
case ambisonicACN3: return "ACN3";
|
||||
case ambisonicACN4: return "ACN4";
|
||||
case ambisonicACN5: return "ACN5";
|
||||
case ambisonicACN6: return "ACN6";
|
||||
case ambisonicACN7: return "ACN7";
|
||||
case ambisonicACN8: return "ACN8";
|
||||
case ambisonicACN9: return "ACN9";
|
||||
case ambisonicACN10: return "ACN10";
|
||||
case ambisonicACN11: return "ACN11";
|
||||
case ambisonicACN12: return "ACN12";
|
||||
case ambisonicACN13: return "ACN13";
|
||||
case ambisonicACN14: return "ACN14";
|
||||
case ambisonicACN15: return "ACN15";
|
||||
case ambisonicACN16: return "ACN16";
|
||||
case ambisonicACN17: return "ACN17";
|
||||
case ambisonicACN18: return "ACN18";
|
||||
case ambisonicACN19: return "ACN19";
|
||||
case ambisonicACN20: return "ACN20";
|
||||
case ambisonicACN21: return "ACN21";
|
||||
case ambisonicACN22: return "ACN22";
|
||||
case ambisonicACN23: return "ACN23";
|
||||
case ambisonicACN24: return "ACN24";
|
||||
case ambisonicACN25: return "ACN25";
|
||||
case ambisonicACN26: return "ACN26";
|
||||
case ambisonicACN27: return "ACN27";
|
||||
case ambisonicACN28: return "ACN28";
|
||||
case ambisonicACN29: return "ACN29";
|
||||
case ambisonicACN30: return "ACN30";
|
||||
case ambisonicACN31: return "ACN31";
|
||||
case ambisonicACN32: return "ACN32";
|
||||
case ambisonicACN33: return "ACN33";
|
||||
case ambisonicACN34: return "ACN34";
|
||||
case ambisonicACN35: return "ACN35";
|
||||
case ambisonicACN36: return "ACN36";
|
||||
case ambisonicACN37: return "ACN37";
|
||||
case ambisonicACN38: return "ACN38";
|
||||
case ambisonicACN39: return "ACN39";
|
||||
case ambisonicACN40: return "ACN40";
|
||||
case ambisonicACN41: return "ACN41";
|
||||
case ambisonicACN42: return "ACN42";
|
||||
case ambisonicACN43: return "ACN43";
|
||||
case ambisonicACN44: return "ACN44";
|
||||
case ambisonicACN45: return "ACN45";
|
||||
case ambisonicACN46: return "ACN46";
|
||||
case ambisonicACN47: return "ACN47";
|
||||
case ambisonicACN48: return "ACN48";
|
||||
case ambisonicACN49: return "ACN49";
|
||||
case ambisonicACN50: return "ACN50";
|
||||
case ambisonicACN51: return "ACN51";
|
||||
case ambisonicACN52: return "ACN52";
|
||||
case ambisonicACN53: return "ACN53";
|
||||
case ambisonicACN54: return "ACN54";
|
||||
case ambisonicACN55: return "ACN55";
|
||||
case ambisonicACN56: return "ACN56";
|
||||
case ambisonicACN57: return "ACN57";
|
||||
case ambisonicACN58: return "ACN58";
|
||||
case ambisonicACN59: return "ACN59";
|
||||
case ambisonicACN60: return "ACN60";
|
||||
case ambisonicACN61: return "ACN61";
|
||||
case ambisonicACN62: return "ACN62";
|
||||
case ambisonicACN63: return "ACN63";
|
||||
case topSideLeft: return "Tsl";
|
||||
case topSideRight: return "Tsr";
|
||||
case bottomFrontLeft: return "Bfl";
|
||||
case bottomFrontCentre: return "Bfc";
|
||||
case bottomFrontRight: return "Bfr";
|
||||
case proximityLeft: return "Pl";
|
||||
case proximityRight: return "Pr";
|
||||
case bottomSideLeft: return "Bsl";
|
||||
case bottomSideRight: return "Bsr";
|
||||
case bottomRearLeft: return "Brl";
|
||||
case bottomRearCentre: return "Brc";
|
||||
case bottomRearRight: return "Brr";
|
||||
case discreteChannel0:
|
||||
case unknown:
|
||||
default: break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (const String& abbr)
|
||||
{
|
||||
if (abbr.length() > 0 && (abbr[0] >= '0' && abbr[0] <= '9'))
|
||||
return static_cast<AudioChannelSet::ChannelType> (static_cast<int> (discreteChannel0)
|
||||
+ abbr.getIntValue() - 1);
|
||||
|
||||
if (abbr == "L") return left;
|
||||
if (abbr == "R") return right;
|
||||
if (abbr == "C") return centre;
|
||||
if (abbr == "Lfe") return LFE;
|
||||
if (abbr == "Ls") return leftSurround;
|
||||
if (abbr == "Rs") return rightSurround;
|
||||
if (abbr == "Lc") return leftCentre;
|
||||
if (abbr == "Rc") return rightCentre;
|
||||
if (abbr == "Cs") return centreSurround;
|
||||
if (abbr == "Lrs") return leftSurroundRear;
|
||||
if (abbr == "Rrs") return rightSurroundRear;
|
||||
if (abbr == "Tm") return topMiddle;
|
||||
if (abbr == "Tfl") return topFrontLeft;
|
||||
if (abbr == "Tfc") return topFrontCentre;
|
||||
if (abbr == "Tfr") return topFrontRight;
|
||||
if (abbr == "Trl") return topRearLeft;
|
||||
if (abbr == "Trc") return topRearCentre;
|
||||
if (abbr == "Trr") return topRearRight;
|
||||
if (abbr == "Wl") return wideLeft;
|
||||
if (abbr == "Wr") return wideRight;
|
||||
if (abbr == "Lfe2") return LFE2;
|
||||
if (abbr == "Lss") return leftSurroundSide;
|
||||
if (abbr == "Rss") return rightSurroundSide;
|
||||
if (abbr == "W") return ambisonicW;
|
||||
if (abbr == "X") return ambisonicX;
|
||||
if (abbr == "Y") return ambisonicY;
|
||||
if (abbr == "Z") return ambisonicZ;
|
||||
if (abbr == "ACN0") return ambisonicACN0;
|
||||
if (abbr == "ACN1") return ambisonicACN1;
|
||||
if (abbr == "ACN2") return ambisonicACN2;
|
||||
if (abbr == "ACN3") return ambisonicACN3;
|
||||
if (abbr == "ACN4") return ambisonicACN4;
|
||||
if (abbr == "ACN5") return ambisonicACN5;
|
||||
if (abbr == "ACN6") return ambisonicACN6;
|
||||
if (abbr == "ACN7") return ambisonicACN7;
|
||||
if (abbr == "ACN8") return ambisonicACN8;
|
||||
if (abbr == "ACN9") return ambisonicACN9;
|
||||
if (abbr == "ACN10") return ambisonicACN10;
|
||||
if (abbr == "ACN11") return ambisonicACN11;
|
||||
if (abbr == "ACN12") return ambisonicACN12;
|
||||
if (abbr == "ACN13") return ambisonicACN13;
|
||||
if (abbr == "ACN14") return ambisonicACN14;
|
||||
if (abbr == "ACN15") return ambisonicACN15;
|
||||
if (abbr == "ACN16") return ambisonicACN16;
|
||||
if (abbr == "ACN17") return ambisonicACN17;
|
||||
if (abbr == "ACN18") return ambisonicACN18;
|
||||
if (abbr == "ACN19") return ambisonicACN19;
|
||||
if (abbr == "ACN20") return ambisonicACN20;
|
||||
if (abbr == "ACN21") return ambisonicACN21;
|
||||
if (abbr == "ACN22") return ambisonicACN22;
|
||||
if (abbr == "ACN23") return ambisonicACN23;
|
||||
if (abbr == "ACN24") return ambisonicACN24;
|
||||
if (abbr == "ACN25") return ambisonicACN25;
|
||||
if (abbr == "ACN26") return ambisonicACN26;
|
||||
if (abbr == "ACN27") return ambisonicACN27;
|
||||
if (abbr == "ACN28") return ambisonicACN28;
|
||||
if (abbr == "ACN29") return ambisonicACN29;
|
||||
if (abbr == "ACN30") return ambisonicACN30;
|
||||
if (abbr == "ACN31") return ambisonicACN31;
|
||||
if (abbr == "ACN32") return ambisonicACN32;
|
||||
if (abbr == "ACN33") return ambisonicACN33;
|
||||
if (abbr == "ACN34") return ambisonicACN34;
|
||||
if (abbr == "ACN35") return ambisonicACN35;
|
||||
if (abbr == "ACN36") return ambisonicACN36;
|
||||
if (abbr == "ACN37") return ambisonicACN37;
|
||||
if (abbr == "ACN38") return ambisonicACN38;
|
||||
if (abbr == "ACN39") return ambisonicACN39;
|
||||
if (abbr == "ACN40") return ambisonicACN40;
|
||||
if (abbr == "ACN41") return ambisonicACN41;
|
||||
if (abbr == "ACN42") return ambisonicACN42;
|
||||
if (abbr == "ACN43") return ambisonicACN43;
|
||||
if (abbr == "ACN44") return ambisonicACN44;
|
||||
if (abbr == "ACN45") return ambisonicACN45;
|
||||
if (abbr == "ACN46") return ambisonicACN46;
|
||||
if (abbr == "ACN47") return ambisonicACN47;
|
||||
if (abbr == "ACN48") return ambisonicACN48;
|
||||
if (abbr == "ACN49") return ambisonicACN49;
|
||||
if (abbr == "ACN50") return ambisonicACN50;
|
||||
if (abbr == "ACN51") return ambisonicACN51;
|
||||
if (abbr == "ACN52") return ambisonicACN52;
|
||||
if (abbr == "ACN53") return ambisonicACN53;
|
||||
if (abbr == "ACN54") return ambisonicACN54;
|
||||
if (abbr == "ACN55") return ambisonicACN55;
|
||||
if (abbr == "ACN56") return ambisonicACN56;
|
||||
if (abbr == "ACN57") return ambisonicACN57;
|
||||
if (abbr == "ACN58") return ambisonicACN58;
|
||||
if (abbr == "ACN59") return ambisonicACN59;
|
||||
if (abbr == "ACN60") return ambisonicACN60;
|
||||
if (abbr == "ACN61") return ambisonicACN61;
|
||||
if (abbr == "ACN62") return ambisonicACN62;
|
||||
if (abbr == "ACN63") return ambisonicACN63;
|
||||
if (abbr == "Tsl") return topSideLeft;
|
||||
if (abbr == "Tsr") return topSideRight;
|
||||
if (abbr == "Bfl") return bottomFrontLeft;
|
||||
if (abbr == "Bfc") return bottomFrontCentre;
|
||||
if (abbr == "Bfr") return bottomFrontRight;
|
||||
if (abbr == "Bsl") return bottomSideLeft;
|
||||
if (abbr == "Bsr") return bottomSideRight;
|
||||
if (abbr == "Brl") return bottomRearLeft;
|
||||
if (abbr == "Brc") return bottomRearCentre;
|
||||
if (abbr == "Brr") return bottomRearRight;
|
||||
return unknown;
|
||||
}
|
||||
|
||||
String AudioChannelSet::getSpeakerArrangementAsString() const
|
||||
{
|
||||
StringArray speakerTypes;
|
||||
|
||||
for (auto& speaker : getChannelTypes())
|
||||
{
|
||||
auto name = getAbbreviatedChannelTypeName (speaker);
|
||||
|
||||
if (name.isNotEmpty())
|
||||
speakerTypes.add (name);
|
||||
}
|
||||
|
||||
return speakerTypes.joinIntoString (" ");
|
||||
}
|
||||
|
||||
AudioChannelSet AudioChannelSet::fromAbbreviatedString (const String& str)
|
||||
{
|
||||
AudioChannelSet set;
|
||||
|
||||
for (auto& abbr : StringArray::fromTokens (str, true))
|
||||
{
|
||||
auto type = getChannelTypeFromAbbreviation (abbr);
|
||||
|
||||
if (type != unknown)
|
||||
set.addChannel (type);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
String AudioChannelSet::getDescription() const
|
||||
{
|
||||
if (isDiscreteLayout()) return "Discrete #" + String (size());
|
||||
if (*this == disabled()) return "Disabled";
|
||||
if (*this == mono()) return "Mono";
|
||||
if (*this == stereo()) return "Stereo";
|
||||
|
||||
if (*this == createLCR()) return "LCR";
|
||||
if (*this == createLRS()) return "LRS";
|
||||
if (*this == createLCRS()) return "LCRS";
|
||||
|
||||
if (*this == create5point0()) return "5.0 Surround";
|
||||
if (*this == create5point0point2()) return "5.0.2 Surround";
|
||||
if (*this == create5point0point4()) return "5.0.4 Surround";
|
||||
if (*this == create5point1()) return "5.1 Surround";
|
||||
if (*this == create5point1point2()) return "5.1.2 Surround";
|
||||
if (*this == create5point1point4()) return "5.1.4 Surround";
|
||||
if (*this == create6point0()) return "6.0 Surround";
|
||||
if (*this == create6point1()) return "6.1 Surround";
|
||||
if (*this == create6point0Music()) return "6.0 (Music) Surround";
|
||||
if (*this == create6point1Music()) return "6.1 (Music) Surround";
|
||||
if (*this == create7point0()) return "7.0 Surround";
|
||||
if (*this == create7point1()) return "7.1 Surround";
|
||||
if (*this == create7point0SDDS()) return "7.0 Surround SDDS";
|
||||
if (*this == create7point1SDDS()) return "7.1 Surround SDDS";
|
||||
if (*this == create7point0point2()) return "7.0.2 Surround";
|
||||
if (*this == create7point0point4()) return "7.0.4 Surround";
|
||||
if (*this == create7point0point6()) return "7.0.6 Surround";
|
||||
if (*this == create7point1point2()) return "7.1.2 Surround";
|
||||
if (*this == create7point1point4()) return "7.1.4 Surround";
|
||||
if (*this == create7point1point6()) return "7.1.6 Surround";
|
||||
if (*this == create9point0point4()) return "9.0.4 Surround";
|
||||
if (*this == create9point1point4()) return "9.1.4 Surround";
|
||||
if (*this == create9point0point6()) return "9.0.6 Surround";
|
||||
if (*this == create9point1point6()) return "9.1.6 Surround";
|
||||
|
||||
if (*this == quadraphonic()) return "Quadraphonic";
|
||||
if (*this == pentagonal()) return "Pentagonal";
|
||||
if (*this == hexagonal()) return "Hexagonal";
|
||||
if (*this == octagonal()) return "Octagonal";
|
||||
|
||||
// ambisonics
|
||||
{
|
||||
auto order = getAmbisonicOrder();
|
||||
|
||||
if (order >= 0)
|
||||
{
|
||||
String suffix;
|
||||
|
||||
switch (order)
|
||||
{
|
||||
case 1: suffix = "st"; break;
|
||||
case 2: suffix = "nd"; break;
|
||||
case 3: suffix = "rd"; break;
|
||||
default: suffix = "th"; break;
|
||||
}
|
||||
|
||||
return String (order) + suffix + " Order Ambisonics";
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool AudioChannelSet::isDiscreteLayout() const noexcept
|
||||
{
|
||||
const auto channelTypes = getChannelTypes();
|
||||
|
||||
return std::none_of (std::begin (channelTypes),
|
||||
std::end (channelTypes),
|
||||
[] (const auto& t) { return t < discreteChannel0; });
|
||||
}
|
||||
|
||||
int AudioChannelSet::size() const noexcept
|
||||
{
|
||||
return channels.countNumberOfSetBits();
|
||||
}
|
||||
|
||||
AudioChannelSet::ChannelType AudioChannelSet::getTypeOfChannel (int index) const noexcept
|
||||
{
|
||||
int bit = channels.findNextSetBit (0);
|
||||
|
||||
for (int i = 0; i < index && bit >= 0; ++i)
|
||||
bit = channels.findNextSetBit (bit + 1);
|
||||
|
||||
return static_cast<ChannelType> (bit);
|
||||
}
|
||||
|
||||
int AudioChannelSet::getChannelIndexForType (AudioChannelSet::ChannelType type) const noexcept
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
for (int bit = channels.findNextSetBit (0); bit >= 0; bit = channels.findNextSetBit (bit + 1))
|
||||
{
|
||||
if (static_cast<ChannelType> (bit) == type)
|
||||
return idx;
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Array<AudioChannelSet::ChannelType> AudioChannelSet::getChannelTypes() const
|
||||
{
|
||||
Array<ChannelType> result;
|
||||
|
||||
for (int bit = channels.findNextSetBit (0); bit >= 0; bit = channels.findNextSetBit (bit + 1))
|
||||
result.add (static_cast<ChannelType> (bit));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AudioChannelSet::addChannel (ChannelType newChannel)
|
||||
{
|
||||
const int bit = static_cast<int> (newChannel);
|
||||
jassert (bit >= 0 && bit < 1024);
|
||||
channels.setBit (bit);
|
||||
}
|
||||
|
||||
void AudioChannelSet::removeChannel (ChannelType newChannel)
|
||||
{
|
||||
const int bit = static_cast<int> (newChannel);
|
||||
jassert (bit >= 0 && bit < 1024);
|
||||
channels.clearBit (bit);
|
||||
}
|
||||
|
||||
AudioChannelSet AudioChannelSet::disabled() { return {}; }
|
||||
AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet ({ centre }); }
|
||||
AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ({ left, right }); }
|
||||
AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ({ left, right, centre }); }
|
||||
AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ({ left, right, surround }); }
|
||||
AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ({ left, right, centre, surround }); }
|
||||
AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround }); }
|
||||
AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround }); }
|
||||
AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround }); }
|
||||
AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, centreSurround }); }
|
||||
AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ({ left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); }
|
||||
AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ({ left, right, LFE, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); }
|
||||
AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); }
|
||||
AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre }); }
|
||||
AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); }
|
||||
AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre }); }
|
||||
AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ({ left, right, leftSurround, rightSurround }); }
|
||||
AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ({ left, right, centre, leftSurroundRear, rightSurroundRear }); }
|
||||
AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ({ left, right, centre, centreSurround, leftSurroundRear, rightSurroundRear }); }
|
||||
AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround, wideLeft, wideRight }); }
|
||||
AudioChannelSet AudioChannelSet::create5point0point2() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, topSideLeft, topSideRight }); }
|
||||
AudioChannelSet AudioChannelSet::create5point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight }); }
|
||||
AudioChannelSet AudioChannelSet::create5point0point4() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create5point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point0point4() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point0point6() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create7point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create9point0point4() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create9point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create9point0point6() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); }
|
||||
AudioChannelSet AudioChannelSet::create9point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); }
|
||||
|
||||
AudioChannelSet AudioChannelSet::ambisonic (int order)
|
||||
{
|
||||
jassert (isPositiveAndBelow (order, 8));
|
||||
|
||||
static constexpr std::pair<int, int> continuousRanges[] { { ambisonicACN0, ambisonicACN3 },
|
||||
{ ambisonicACN4, ambisonicACN35 },
|
||||
{ ambisonicACN36, ambisonicACN63 } };
|
||||
|
||||
AudioChannelSet set;
|
||||
|
||||
const auto setBits = [&set] (auto range, auto maxNumToSet)
|
||||
{
|
||||
const auto numToSet = std::min (maxNumToSet, range.second - range.first + 1);
|
||||
set.channels.setRange (range.first, numToSet, true);
|
||||
return numToSet;
|
||||
};
|
||||
|
||||
const auto numAmbisonicChannels = square (order + 1);
|
||||
|
||||
for (int rangeIdx = 0, bitsSet = 0; bitsSet < numAmbisonicChannels; ++rangeIdx)
|
||||
{
|
||||
bitsSet += setBits (continuousRanges[rangeIdx], numAmbisonicChannels - bitsSet);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
int AudioChannelSet::getAmbisonicOrder() const
|
||||
{
|
||||
auto ambisonicOrder = getAmbisonicOrderForNumChannels (size());
|
||||
|
||||
if (ambisonicOrder >= 0)
|
||||
return (*this == ambisonic (ambisonicOrder) ? ambisonicOrder : -1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioChannelSet AudioChannelSet::discreteChannels (int numChannels)
|
||||
{
|
||||
AudioChannelSet s;
|
||||
s.channels.setRange (discreteChannel0, numChannels, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
AudioChannelSet AudioChannelSet::canonicalChannelSet (int numChannels)
|
||||
{
|
||||
if (numChannels == 1) return AudioChannelSet::mono();
|
||||
if (numChannels == 2) return AudioChannelSet::stereo();
|
||||
if (numChannels == 3) return AudioChannelSet::createLCR();
|
||||
if (numChannels == 4) return AudioChannelSet::quadraphonic();
|
||||
if (numChannels == 5) return AudioChannelSet::create5point0();
|
||||
if (numChannels == 6) return AudioChannelSet::create5point1();
|
||||
if (numChannels == 7) return AudioChannelSet::create7point0();
|
||||
if (numChannels == 8) return AudioChannelSet::create7point1();
|
||||
|
||||
return discreteChannels (numChannels);
|
||||
}
|
||||
|
||||
AudioChannelSet AudioChannelSet::namedChannelSet (int numChannels)
|
||||
{
|
||||
if (numChannels == 1) return AudioChannelSet::mono();
|
||||
if (numChannels == 2) return AudioChannelSet::stereo();
|
||||
if (numChannels == 3) return AudioChannelSet::createLCR();
|
||||
if (numChannels == 4) return AudioChannelSet::quadraphonic();
|
||||
if (numChannels == 5) return AudioChannelSet::create5point0();
|
||||
if (numChannels == 6) return AudioChannelSet::create5point1();
|
||||
if (numChannels == 7) return AudioChannelSet::create7point0();
|
||||
if (numChannels == 8) return AudioChannelSet::create7point1();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int numChannels)
|
||||
{
|
||||
Array<AudioChannelSet> retval;
|
||||
|
||||
if (numChannels != 0)
|
||||
{
|
||||
retval.add (AudioChannelSet::discreteChannels (numChannels));
|
||||
|
||||
retval.addArray ([numChannels]() -> Array<AudioChannelSet>
|
||||
{
|
||||
switch (numChannels)
|
||||
{
|
||||
case 1:
|
||||
return { AudioChannelSet::mono() };
|
||||
case 2:
|
||||
return { AudioChannelSet::stereo() };
|
||||
case 3:
|
||||
return { AudioChannelSet::createLCR(),
|
||||
AudioChannelSet::createLRS() };
|
||||
case 4:
|
||||
return { AudioChannelSet::quadraphonic(),
|
||||
AudioChannelSet::createLCRS() };
|
||||
case 5:
|
||||
return { AudioChannelSet::create5point0(),
|
||||
AudioChannelSet::pentagonal() };
|
||||
case 6:
|
||||
return { AudioChannelSet::create5point1(),
|
||||
AudioChannelSet::create6point0(),
|
||||
AudioChannelSet::create6point0Music(),
|
||||
AudioChannelSet::hexagonal() };
|
||||
case 7:
|
||||
return { AudioChannelSet::create7point0(),
|
||||
AudioChannelSet::create7point0SDDS(),
|
||||
AudioChannelSet::create6point1(),
|
||||
AudioChannelSet::create6point1Music() };
|
||||
case 8:
|
||||
return { AudioChannelSet::create7point1(),
|
||||
AudioChannelSet::create7point1SDDS(),
|
||||
AudioChannelSet::octagonal(),
|
||||
AudioChannelSet::create5point1point2() };
|
||||
case 9:
|
||||
return { AudioChannelSet::create7point0point2() };
|
||||
case 10:
|
||||
return { AudioChannelSet::create5point1point4(),
|
||||
AudioChannelSet::create7point1point2() };
|
||||
case 11:
|
||||
return { AudioChannelSet::create7point0point4() };
|
||||
case 12:
|
||||
return { AudioChannelSet::create7point1point4() };
|
||||
case 14:
|
||||
return { AudioChannelSet::create7point1point6() };
|
||||
case 16:
|
||||
return { AudioChannelSet::create9point1point6() };
|
||||
}
|
||||
|
||||
return {};
|
||||
}());
|
||||
|
||||
auto order = getAmbisonicOrderForNumChannels (numChannels);
|
||||
if (order >= 0)
|
||||
retval.add (AudioChannelSet::ambisonic (order));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
AudioChannelSet JUCE_CALLTYPE AudioChannelSet::channelSetWithChannels (const Array<ChannelType>& channelArray)
|
||||
{
|
||||
AudioChannelSet set;
|
||||
|
||||
for (auto ch : channelArray)
|
||||
{
|
||||
jassert (! set.channels[static_cast<int> (ch)]);
|
||||
|
||||
set.addChannel (ch);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioChannelSet JUCE_CALLTYPE AudioChannelSet::fromWaveChannelMask (int32 dwChannelMask)
|
||||
{
|
||||
return AudioChannelSet (static_cast<uint32> ((dwChannelMask & ((1 << 18) - 1)) << 1));
|
||||
}
|
||||
|
||||
int32 AudioChannelSet::getWaveChannelMask() const noexcept
|
||||
{
|
||||
if (channels.getHighestBit() > topRearRight)
|
||||
return -1;
|
||||
|
||||
return (channels.toInteger() >> 1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels, int maxOrderToCheck)
|
||||
{
|
||||
for (auto i = 0; i <= maxOrderToCheck; ++i)
|
||||
if (numChannels == square (i + 1))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class AudioChannelSetUnitTest final : public UnitTest
|
||||
{
|
||||
public:
|
||||
AudioChannelSetUnitTest()
|
||||
: UnitTest ("AudioChannelSetUnitTest", UnitTestCategories::audio)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
auto max = AudioChannelSet::maxChannelsOfNamedLayout;
|
||||
|
||||
beginTest ("maxChannelsOfNamedLayout is non-discrete");
|
||||
expect (AudioChannelSet::channelSetsWithNumberOfChannels (max).size() >= 2);
|
||||
|
||||
beginTest ("channelSetsWithNumberOfChannels returns correct speaker count");
|
||||
{
|
||||
for (auto ch = 1; ch <= max; ++ch)
|
||||
{
|
||||
auto channelSets = AudioChannelSet::channelSetsWithNumberOfChannels (ch);
|
||||
|
||||
for (auto set : channelSets)
|
||||
expect (set.size() == ch);
|
||||
}
|
||||
}
|
||||
|
||||
beginTest ("Ambisonics");
|
||||
{
|
||||
uint64 mask = 0;
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN0);
|
||||
checkAmbisonic (mask, 0, "0th Order Ambisonics");
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN1) | (1ull << AudioChannelSet::ambisonicACN2) | (1ull << AudioChannelSet::ambisonicACN3);
|
||||
checkAmbisonic (mask, 1, "1st Order Ambisonics");
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN4) | (1ull << AudioChannelSet::ambisonicACN5) | (1ull << AudioChannelSet::ambisonicACN6)
|
||||
| (1ull << AudioChannelSet::ambisonicACN7) | (1ull << AudioChannelSet::ambisonicACN8);
|
||||
checkAmbisonic (mask, 2, "2nd Order Ambisonics");
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN9) | (1ull << AudioChannelSet::ambisonicACN10) | (1ull << AudioChannelSet::ambisonicACN11)
|
||||
| (1ull << AudioChannelSet::ambisonicACN12) | (1ull << AudioChannelSet::ambisonicACN13) | (1ull << AudioChannelSet::ambisonicACN14)
|
||||
| (1ull << AudioChannelSet::ambisonicACN15);
|
||||
checkAmbisonic (mask, 3, "3rd Order Ambisonics");
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN16) | (1ull << AudioChannelSet::ambisonicACN17) | (1ull << AudioChannelSet::ambisonicACN18)
|
||||
| (1ull << AudioChannelSet::ambisonicACN19) | (1ull << AudioChannelSet::ambisonicACN20) | (1ull << AudioChannelSet::ambisonicACN21)
|
||||
| (1ull << AudioChannelSet::ambisonicACN22) | (1ull << AudioChannelSet::ambisonicACN23) | (1ull << AudioChannelSet::ambisonicACN24);
|
||||
checkAmbisonic (mask, 4, "4th Order Ambisonics");
|
||||
|
||||
mask |= (1ull << AudioChannelSet::ambisonicACN25) | (1ull << AudioChannelSet::ambisonicACN26) | (1ull << AudioChannelSet::ambisonicACN27)
|
||||
| (1ull << AudioChannelSet::ambisonicACN28) | (1ull << AudioChannelSet::ambisonicACN29) | (1ull << AudioChannelSet::ambisonicACN30)
|
||||
| (1ull << AudioChannelSet::ambisonicACN31) | (1ull << AudioChannelSet::ambisonicACN32) | (1ull << AudioChannelSet::ambisonicACN33)
|
||||
| (1ull << AudioChannelSet::ambisonicACN34) | (1ull << AudioChannelSet::ambisonicACN35);
|
||||
checkAmbisonic (mask, 5, "5th Order Ambisonics");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void checkAmbisonic (uint64 mask, int order, const char* layoutName)
|
||||
{
|
||||
auto expected = AudioChannelSet::ambisonic (order);
|
||||
auto numChannels = expected.size();
|
||||
|
||||
expect (numChannels == BigInteger ((int64) mask).countNumberOfSetBits());
|
||||
expect (channelSetFromMask (mask) == expected);
|
||||
|
||||
expect (order == expected.getAmbisonicOrder());
|
||||
expect (expected.getDescription() == layoutName);
|
||||
|
||||
auto layouts = AudioChannelSet::channelSetsWithNumberOfChannels (numChannels);
|
||||
expect (layouts.contains (expected));
|
||||
|
||||
for (auto layout : layouts)
|
||||
expect (layout.getAmbisonicOrder() == (layout == expected ? order : -1));
|
||||
}
|
||||
|
||||
static AudioChannelSet channelSetFromMask (uint64 mask)
|
||||
{
|
||||
Array<AudioChannelSet::ChannelType> channels;
|
||||
for (int bit = 0; bit <= 62; ++bit)
|
||||
if ((mask & (1ull << bit)) != 0)
|
||||
channels.add (static_cast<AudioChannelSet::ChannelType> (bit));
|
||||
|
||||
return AudioChannelSet::channelSetWithChannels (channels);
|
||||
}
|
||||
};
|
||||
|
||||
static AudioChannelSetUnitTest audioChannelSetUnitTest;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a set of audio channel types.
|
||||
|
||||
For example, you might have a set of left + right channels, which is a stereo
|
||||
channel set. It is a collection of values from the AudioChannelSet::ChannelType
|
||||
enum, where each type may only occur once within the set.
|
||||
|
||||
The documentation below lists which AudioChannelSet corresponds to which native
|
||||
layouts used by AAX, VST2/VST3 and CoreAudio/AU. The layout tags in CoreAudio
|
||||
are particularly confusing. For example, the layout which is labeled as "7.1 SDDS"
|
||||
in Logic Pro, corresponds to CoreAudio/AU's kAudioChannelLayoutTag_DTS_7_0 tag, whereas
|
||||
AAX's DTS 7.1 Layout corresponds to CoreAudio/AU's
|
||||
kAudioChannelLayoutTag_MPEG_7_1_A format, etc. Please do not use the CoreAudio tag
|
||||
as an indication to the actual layout of the speakers.
|
||||
|
||||
@see Bus
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioChannelSet
|
||||
{
|
||||
public:
|
||||
/** Creates an empty channel set.
|
||||
You can call addChannel to add channels to the set.
|
||||
*/
|
||||
AudioChannelSet() = default;
|
||||
|
||||
/** Creates a zero-channel set which can be used to indicate that a
|
||||
bus is disabled. */
|
||||
static AudioChannelSet JUCE_CALLTYPE disabled();
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a one-channel mono set (centre).
|
||||
|
||||
Is equivalent to: kMonoAAX (VST), AAX_eStemFormat_Mono (AAX), kAudioChannelLayoutTag_Mono (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE mono();
|
||||
|
||||
|
||||
/** Creates a set containing a stereo set (left, right).
|
||||
|
||||
Is equivalent to: kStereo (VST), AAX_eStemFormat_Stereo (AAX), kAudioChannelLayoutTag_Stereo (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE stereo();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set containing an LCR set (left, right, centre).
|
||||
|
||||
Is equivalent to: k30Cine (VST), AAX_eStemFormat_LCR (AAX), kAudioChannelLayoutTag_MPEG_3_0_A (CoreAudio)
|
||||
|
||||
This format is referred to as "LRC" in Cubase.
|
||||
This format is referred to as "LCR" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE createLCR();
|
||||
|
||||
|
||||
/** Creates a set containing an LRS set (left, right, surround).
|
||||
|
||||
Is equivalent to: k30Music (VST), n/a (AAX), kAudioChannelLayoutTag_ITU_2_1 (CoreAudio)
|
||||
|
||||
This format is referred to as "LRS" in Cubase.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE createLRS();
|
||||
|
||||
|
||||
/** Creates a set containing an LCRS set (left, right, centre, surround).
|
||||
|
||||
Is equivalent to: k40Cine (VST), AAX_eStemFormat_LCRS (AAX), kAudioChannelLayoutTag_MPEG_4_0_A (CoreAudio)
|
||||
|
||||
This format is referred to as "LCRS (Pro Logic)" in Logic Pro.
|
||||
This format is referred to as "LRCS" in Cubase.
|
||||
This format is referred to as "LCRS" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE createLCRS();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set for a 5.0 surround setup (left, right, centre, leftSurround, rightSurround).
|
||||
|
||||
Is equivalent to: k50 (VST), AAX_eStemFormat_5_0 (AAX), kAudioChannelLayoutTag_MPEG_5_0_A (CoreAudio)
|
||||
|
||||
This format is referred to as "5.0" in Cubase.
|
||||
This format is referred to as "5.0" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point0();
|
||||
|
||||
|
||||
/** Creates a set for a 5.1 surround setup (left, right, centre, leftSurround, rightSurround, LFE).
|
||||
|
||||
Is equivalent to: k51 (VST), AAX_eStemFormat_5_1 (AAX), kAudioChannelLayoutTag_MPEG_5_1_A (CoreAudio)
|
||||
|
||||
This format is referred to as "5.1 (ITU 775)" in Logic Pro.
|
||||
This format is referred to as "5.1" in Cubase.
|
||||
This format is referred to as "5.1" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point1();
|
||||
|
||||
|
||||
/** Creates a set for a 6.0 Cine surround setup (left, right, centre, leftSurround, rightSurround, centreSurround).
|
||||
|
||||
Is equivalent to: k60Cine (VST), AAX_eStemFormat_6_0 (AAX), kAudioChannelLayoutTag_AudioUnit_6_0 (CoreAudio)
|
||||
|
||||
Logic Pro incorrectly uses this for the surround format labeled "6.1 (ES/EX)".
|
||||
This format is referred to as "6.0 Cine" in Cubase.
|
||||
This format is referred to as "6.0" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create6point0();
|
||||
|
||||
|
||||
/** Creates a set for a 6.1 Cine surround setup (left, right, centre, leftSurround, rightSurround, centreSurround, LFE).
|
||||
|
||||
Is equivalent to: k61Cine (VST), AAX_eStemFormat_6_1 (AAX), kAudioChannelLayoutTag_MPEG_6_1_A (CoreAudio)
|
||||
|
||||
This format is referred to as "6.1" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create6point1();
|
||||
|
||||
|
||||
/** Creates a set for a 6.0 Music surround setup (left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide).
|
||||
|
||||
Is equivalent to: k60Music (VST), n/a (AAX), kAudioChannelLayoutTag_DTS_6_0_A (CoreAudio)
|
||||
|
||||
This format is referred to as "6.0 Music" in Cubase.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create6point0Music();
|
||||
|
||||
|
||||
/** Creates a set for a 6.0 Music surround setup (left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide, LFE).
|
||||
|
||||
Is equivalent to: k61Music (VST), n/a (AAX), kAudioChannelLayoutTag_DTS_6_1_A (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create6point1Music();
|
||||
|
||||
|
||||
/** Creates a set for a DTS 7.0 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear).
|
||||
|
||||
Is equivalent to: k70Music (VST), AAX_eStemFormat_7_0_DTS (AAX), kAudioChannelLayoutTag_AudioUnit_7_0 (CoreAudio)
|
||||
|
||||
This format is referred to as "7.0" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point0();
|
||||
|
||||
|
||||
/** Creates a set for a SDDS 7.0 surround setup (left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre).
|
||||
|
||||
Is equivalent to: k70Cine (VST), AAX_eStemFormat_7_0_SDDS (AAX), kAudioChannelLayoutTag_AudioUnit_7_0_Front (CoreAudio)
|
||||
|
||||
This format is referred to as "7.0 SDDS" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point0SDDS();
|
||||
|
||||
|
||||
/** Creates a set for a DTS 7.1 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE).
|
||||
|
||||
Is equivalent to: k71CineSideFill (VST), AAX_eStemFormat_7_1_DTS (AAX), kAudioChannelLayoutTag_MPEG_7_1_C/kAudioChannelLayoutTag_ITU_3_4_1 (CoreAudio)
|
||||
|
||||
This format is referred to as "7.1 (3/4.1)" in Logic Pro.
|
||||
This format is referred to as "7.1" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1();
|
||||
|
||||
|
||||
/** Creates a set for a 7.1 surround setup (left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre, LFE).
|
||||
|
||||
Is equivalent to: k71Cine (VST), AAX_eStemFormat_7_1_SDDS (AAX), kAudioChannelLayoutTag_MPEG_7_1_A (CoreAudio)
|
||||
|
||||
This format is referred to as "7.1 (SDDS)" in Logic Pro.
|
||||
This format is referred to as "7.1 SDDS" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1SDDS();
|
||||
|
||||
/** Creates a set for a 5.0.2 surround setup (left, right, centre, leftSurround, rightSurround, topSideLeft, topSideRight).
|
||||
|
||||
Is equivalent to: AAX_eStemFormat_5_0_2 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point0point2();
|
||||
|
||||
/** Creates a set for a 5.1.2 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight).
|
||||
|
||||
Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_2 (CoreAudio).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point1point2();
|
||||
|
||||
/** Creates a set for a 5.0.4 surround setup (left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: AAX_eStemFormat_5_0_4 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point0point4();
|
||||
|
||||
/** Creates a set for a 5.1.4 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_4 (CoreAudio).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create5point1point4();
|
||||
|
||||
/** Creates a set for Dolby Atmos 7.0.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight).
|
||||
|
||||
Is equivalent to: n/a (VST), AAX_eStemFormat_7_0_2 (AAX), n/a (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point0point2();
|
||||
|
||||
/** Creates a set for Dolby Atmos 7.1.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topSideLeft, topSideRight).
|
||||
|
||||
Is equivalent to: k71_2 (VST), AAX_eStemFormat_7_1_2 (AAX), kAudioChannelLayoutTag_Atmos_7_1_2 (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1point2();
|
||||
|
||||
/** Creates a set for Dolby Atmos 7.0.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: n/a (VST), n/a (AAX), n/a (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point0point4();
|
||||
|
||||
/** Creates a set for Dolby Atmos 7.1.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: k71_4 (VST), n/a (AAX), kAudioChannelLayoutTag_Atmos_7_1_4 (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1point4();
|
||||
|
||||
/** Creates a set for 7.0.6 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: AAX_eStemFormat_7_0_6 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point0point6();
|
||||
|
||||
/** Creates a set for Dolby Atmos 7.1.6 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: k71_6 (VST), n/a (AAX), n/a (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1point6();
|
||||
|
||||
/** Creates a set for a 9.0.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: k90_4 (VST3), AAX_eStemFormat_9_0_4 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create9point0point4();
|
||||
|
||||
/** Creates a set for a 9.1.4 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: k91_4 (VST3), AAX_eStemFormat_9_1_4 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create9point1point4();
|
||||
|
||||
/** Creates a set for a 9.0.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
|
||||
|
||||
Is equivalent to: k90_6 (VST3), AAX_eStemFormat_9_0_6 (AAX).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create9point0point6();
|
||||
|
||||
/** Creates a set for a 9.1.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
|
||||
|
||||
Note that the VST3 layout arranges the front speakers "L Lc C Rc R", but the JUCE layout
|
||||
uses the arrangement "wideLeft left centre right wideRight". To maintain the relative
|
||||
positions of the speakers, the channels will be remapped accordingly. This means that the
|
||||
VST3 host's "L" channel will be received on a JUCE plugin's "wideLeft" channel, the
|
||||
"Lc" channel will be received on a JUCE plugin's "left" channel, and so on.
|
||||
|
||||
Is equivalent to: k91_6 (VST3), kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio).
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create9point1point6();
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set for quadraphonic surround setup (left, right, leftSurround, rightSurround)
|
||||
|
||||
Is equivalent to: k40Music (VST), AAX_eStemFormat_Quad (AAX), kAudioChannelLayoutTag_Quadraphonic (CoreAudio)
|
||||
|
||||
This format is referred to as "Quadraphonic" in Logic Pro.
|
||||
This format is referred to as "Quadro" in Cubase.
|
||||
This format is referred to as "Quad" in Pro Tools.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE quadraphonic();
|
||||
|
||||
|
||||
/** Creates a set for pentagonal surround setup (left, right, centre, leftSurroundRear, rightSurroundRear).
|
||||
|
||||
Is equivalent to: n/a (VST), n/a (AAX), kAudioChannelLayoutTag_Pentagonal (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE pentagonal();
|
||||
|
||||
|
||||
/** Creates a set for hexagonal surround setup (left, right, leftSurroundRear, rightSurroundRear, centre, surroundCentre).
|
||||
|
||||
Is equivalent to: n/a (VST), n/a (AAX), kAudioChannelLayoutTag_Hexagonal (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE hexagonal();
|
||||
|
||||
|
||||
/** Creates a set for octagonal surround setup (left, right, leftSurround, rightSurround, centre, centreSurround, wideLeft, wideRight).
|
||||
|
||||
Is equivalent to: n/a (VST), n/a (AAX), kAudioChannelLayoutTag_Octagonal (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE octagonal();
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set for ACN, SN3D normalised ambisonic surround setups with a given order.
|
||||
|
||||
Is equivalent to: kAmbiXXXOrderACN (VST), AAX_eStemFormat_Ambi_XXX_ACN (AAX), kAudioChannelLayoutTag_HOA_ACN_SN3D (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE ambisonic (int order = 1);
|
||||
|
||||
/** Returns the order of the ambisonic layout represented by this AudioChannelSet. If the
|
||||
AudioChannelSet is not an ambisonic layout, then this method will return -1.
|
||||
*/
|
||||
int getAmbisonicOrder() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a set of untyped discrete channels. */
|
||||
static AudioChannelSet JUCE_CALLTYPE discreteChannels (int numChannels);
|
||||
|
||||
/** Create a canonical channel set for a given number of channels.
|
||||
For example, numChannels = 1 will return mono, numChannels = 2 will return stereo, etc. */
|
||||
static AudioChannelSet JUCE_CALLTYPE canonicalChannelSet (int numChannels);
|
||||
|
||||
/** Create a channel set for a given number of channels which is non-discrete.
|
||||
If numChannels is larger than the number of channels of the surround format
|
||||
with the maximum amount of channels (currently 7.1 Surround), then this
|
||||
function returns an empty set.*/
|
||||
static AudioChannelSet JUCE_CALLTYPE namedChannelSet (int numChannels);
|
||||
|
||||
/** Return an array of channel sets which have a given number of channels */
|
||||
static Array<AudioChannelSet> JUCE_CALLTYPE channelSetsWithNumberOfChannels (int numChannels);
|
||||
|
||||
//==============================================================================
|
||||
/** Represents different audio channel types. */
|
||||
enum ChannelType
|
||||
{
|
||||
unknown = 0, /**< Unknown channel type. */
|
||||
|
||||
//==============================================================================
|
||||
left = 1, /**< L channel. */
|
||||
right = 2, /**< R channel. */
|
||||
centre = 3, /**< C channel. (Sometimes M for mono) */
|
||||
|
||||
//==============================================================================
|
||||
LFE = 4, /**< LFE channel. */
|
||||
leftSurround = 5, /**< Ls channel. */
|
||||
rightSurround = 6, /**< Rs channel. */
|
||||
leftCentre = 7, /**< Lc (AAX/VST), Lc used as Lss in AU for most layouts. */
|
||||
rightCentre = 8, /**< Rc (AAX/VST), Rc used as Rss in AU for most layouts. */
|
||||
centreSurround = 9, /**< Cs/S channel. */
|
||||
surround = centreSurround, /**< Same as Centre Surround channel. */
|
||||
leftSurroundSide = 10, /**< Lss (AXX), Side Left "Sl" (VST), Left Centre "LC" (AU) channel. */
|
||||
rightSurroundSide = 11, /**< Rss (AXX), Side right "Sr" (VST), Right Centre "Rc" (AU) channel. */
|
||||
topMiddle = 12, /**< Top Middle channel. */
|
||||
topFrontLeft = 13, /**< Top Front Left channel. */
|
||||
topFrontCentre = 14, /**< Top Front Centre channel. */
|
||||
topFrontRight = 15, /**< Top Front Right channel. */
|
||||
topRearLeft = 16, /**< Top Rear Left channel. */
|
||||
topRearCentre = 17, /**< Top Rear Centre channel. */
|
||||
topRearRight = 18, /**< Top Rear Right channel. */
|
||||
LFE2 = 19, /**< Second LFE channel. */
|
||||
leftSurroundRear = 20, /**< Lsr (AAX), Lcs (VST), Rls (AU) channel. */
|
||||
rightSurroundRear = 21, /**< Rsr (AAX), Rcs (VST), Rrs (AU) channel. */
|
||||
wideLeft = 22, /**< Wide Left channel. */
|
||||
wideRight = 23, /**< Wide Right channel. */
|
||||
|
||||
//==============================================================================
|
||||
// Used by Dolby Atmos 7.0.2 and 7.1.2
|
||||
topSideLeft = 28, /**< Lts (AAX), Tsl (VST), Ltm (AU) channel for Dolby Atmos. */
|
||||
topSideRight = 29, /**< Rts (AAX), Tsr (VST), Rtm (AU) channel for Dolby Atmos. */
|
||||
|
||||
//==============================================================================
|
||||
// Ambisonic ACN formats - all channels are SN3D normalised
|
||||
|
||||
// zero-th and first-order ambisonic ACN
|
||||
ambisonicACN0 = 24, /**< Zero-th ambisonic channel number 0. */
|
||||
ambisonicACN1 = 25, /**< First-order ambisonic channel number 1. */
|
||||
ambisonicACN2 = 26, /**< First-order ambisonic channel number 2. */
|
||||
ambisonicACN3 = 27, /**< First-order ambisonic channel number 3. */
|
||||
|
||||
// second-order ambisonic
|
||||
ambisonicACN4 = 30, /**< Second-order ambisonic channel number 4. */
|
||||
ambisonicACN5 = 31, /**< Second-order ambisonic channel number 5. */
|
||||
ambisonicACN6 = 32, /**< Second-order ambisonic channel number 6. */
|
||||
ambisonicACN7 = 33, /**< Second-order ambisonic channel number 7. */
|
||||
ambisonicACN8 = 34, /**< Second-order ambisonic channel number 8. */
|
||||
|
||||
// third-order ambisonic
|
||||
ambisonicACN9 = 35, /**< Third-order ambisonic channel number 9. */
|
||||
ambisonicACN10 = 36, /**< Third-order ambisonic channel number 10. */
|
||||
ambisonicACN11 = 37, /**< Third-order ambisonic channel number 11. */
|
||||
ambisonicACN12 = 38, /**< Third-order ambisonic channel number 12. */
|
||||
ambisonicACN13 = 39, /**< Third-order ambisonic channel number 13. */
|
||||
ambisonicACN14 = 40, /**< Third-order ambisonic channel number 14. */
|
||||
ambisonicACN15 = 41, /**< Third-order ambisonic channel number 15. */
|
||||
|
||||
// fourth-order ambisonic
|
||||
ambisonicACN16 = 42, /**< Fourth-order ambisonic channel number 16. */
|
||||
ambisonicACN17 = 43, /**< Fourth-order ambisonic channel number 17. */
|
||||
ambisonicACN18 = 44, /**< Fourth-order ambisonic channel number 18. */
|
||||
ambisonicACN19 = 45, /**< Fourth-order ambisonic channel number 19. */
|
||||
ambisonicACN20 = 46, /**< Fourth-order ambisonic channel number 20. */
|
||||
ambisonicACN21 = 47, /**< Fourth-order ambisonic channel number 21. */
|
||||
ambisonicACN22 = 48, /**< Fourth-order ambisonic channel number 22. */
|
||||
ambisonicACN23 = 49, /**< Fourth-order ambisonic channel number 23. */
|
||||
ambisonicACN24 = 50, /**< Fourth-order ambisonic channel number 24. */
|
||||
|
||||
// fifth-order ambisonic
|
||||
ambisonicACN25 = 51, /**< Fifth-order ambisonic channel number 25. */
|
||||
ambisonicACN26 = 52, /**< Fifth-order ambisonic channel number 26. */
|
||||
ambisonicACN27 = 53, /**< Fifth-order ambisonic channel number 27. */
|
||||
ambisonicACN28 = 54, /**< Fifth-order ambisonic channel number 28. */
|
||||
ambisonicACN29 = 55, /**< Fifth-order ambisonic channel number 29. */
|
||||
ambisonicACN30 = 56, /**< Fifth-order ambisonic channel number 30. */
|
||||
ambisonicACN31 = 57, /**< Fifth-order ambisonic channel number 31. */
|
||||
ambisonicACN32 = 58, /**< Fifth-order ambisonic channel number 32. */
|
||||
ambisonicACN33 = 59, /**< Fifth-order ambisonic channel number 33. */
|
||||
ambisonicACN34 = 60, /**< Fifth-order ambisonic channel number 34. */
|
||||
ambisonicACN35 = 61, /**< Fifth-order ambisonic channel number 35. */
|
||||
|
||||
//==============================================================================
|
||||
ambisonicW = ambisonicACN0, /**< Same as zero-th ambisonic channel number 0. */
|
||||
ambisonicX = ambisonicACN3, /**< Same as first-order ambisonic channel number 3. */
|
||||
ambisonicY = ambisonicACN1, /**< Same as first-order ambisonic channel number 1. */
|
||||
ambisonicZ = ambisonicACN2, /**< Same as first-order ambisonic channel number 2. */
|
||||
|
||||
//==============================================================================
|
||||
bottomFrontLeft = 62, /**< Bottom Front Left (Bfl) */
|
||||
bottomFrontCentre = 63, /**< Bottom Front Centre (Bfc) */
|
||||
bottomFrontRight = 64, /**< Bottom Front Right (Bfr) */
|
||||
|
||||
proximityLeft = 65, /**< Proximity Left (Pl) */
|
||||
proximityRight = 66, /**< Proximity Right (Pr) */
|
||||
|
||||
bottomSideLeft = 67, /**< Bottom Side Left (Bsl) */
|
||||
bottomSideRight = 68, /**< Bottom Side Right (Bsr) */
|
||||
bottomRearLeft = 69, /**< Bottom Rear Left (Brl) */
|
||||
bottomRearCentre = 70, /**< Bottom Rear Center (Brc) */
|
||||
bottomRearRight = 71, /**< Bottom Rear Right (Brr) */
|
||||
|
||||
//==============================================================================
|
||||
|
||||
// sixth-order ambisonic
|
||||
ambisonicACN36 = 72, /**< Sixth-order ambisonic channel number 36. */
|
||||
ambisonicACN37 = 73, /**< Sixth-order ambisonic channel number 37. */
|
||||
ambisonicACN38 = 74, /**< Sixth-order ambisonic channel number 38. */
|
||||
ambisonicACN39 = 75, /**< Sixth-order ambisonic channel number 39. */
|
||||
ambisonicACN40 = 76, /**< Sixth-order ambisonic channel number 40. */
|
||||
ambisonicACN41 = 77, /**< Sixth-order ambisonic channel number 41. */
|
||||
ambisonicACN42 = 78, /**< Sixth-order ambisonic channel number 42. */
|
||||
ambisonicACN43 = 79, /**< Sixth-order ambisonic channel number 43. */
|
||||
ambisonicACN44 = 80, /**< Sixth-order ambisonic channel number 44. */
|
||||
ambisonicACN45 = 81, /**< Sixth-order ambisonic channel number 45. */
|
||||
ambisonicACN46 = 82, /**< Sixth-order ambisonic channel number 46. */
|
||||
ambisonicACN47 = 83, /**< Sixth-order ambisonic channel number 47. */
|
||||
ambisonicACN48 = 84, /**< Sixth-order ambisonic channel number 48. */
|
||||
|
||||
// seventh-order ambisonic
|
||||
ambisonicACN49 = 85, /**< Seventh-order ambisonic channel number 49. */
|
||||
ambisonicACN50 = 86, /**< Seventh-order ambisonic channel number 50. */
|
||||
ambisonicACN51 = 87, /**< Seventh-order ambisonic channel number 51. */
|
||||
ambisonicACN52 = 88, /**< Seventh-order ambisonic channel number 52. */
|
||||
ambisonicACN53 = 89, /**< Seventh-order ambisonic channel number 53. */
|
||||
ambisonicACN54 = 90, /**< Seventh-order ambisonic channel number 54. */
|
||||
ambisonicACN55 = 91, /**< Seventh-order ambisonic channel number 55. */
|
||||
ambisonicACN56 = 92, /**< Seventh-order ambisonic channel number 56. */
|
||||
ambisonicACN57 = 93, /**< Seventh-order ambisonic channel number 57. */
|
||||
ambisonicACN58 = 94, /**< Seventh-order ambisonic channel number 58. */
|
||||
ambisonicACN59 = 95, /**< Seventh-order ambisonic channel number 59. */
|
||||
ambisonicACN60 = 96, /**< Seventh-order ambisonic channel number 60. */
|
||||
ambisonicACN61 = 97, /**< Seventh-order ambisonic channel number 61. */
|
||||
ambisonicACN62 = 98, /**< Seventh-order ambisonic channel number 62. */
|
||||
ambisonicACN63 = 99, /**< Seventh-order ambisonic channel number 63. */
|
||||
|
||||
//==============================================================================
|
||||
discreteChannel0 = 128 /**< Non-typed individual channels are indexed upwards from this value. */
|
||||
};
|
||||
|
||||
/** Returns the name of a given channel type. For example, this method may return "Surround Left". */
|
||||
static String JUCE_CALLTYPE getChannelTypeName (ChannelType);
|
||||
|
||||
/** Returns the abbreviated name of a channel type. For example, this method may return "Ls". */
|
||||
static String JUCE_CALLTYPE getAbbreviatedChannelTypeName (ChannelType);
|
||||
|
||||
/** Returns the channel type from an abbreviated name. */
|
||||
static ChannelType JUCE_CALLTYPE getChannelTypeFromAbbreviation (const String& abbreviation);
|
||||
|
||||
//==============================================================================
|
||||
enum
|
||||
{
|
||||
maxChannelsOfNamedLayout = 64
|
||||
};
|
||||
|
||||
/** Adds a channel to the set. */
|
||||
void addChannel (ChannelType newChannelType);
|
||||
|
||||
/** Removes a channel from the set. */
|
||||
void removeChannel (ChannelType newChannelType);
|
||||
|
||||
/** Returns the number of channels in the set. */
|
||||
int size() const noexcept;
|
||||
|
||||
/** Returns true if there are no channels in the set. */
|
||||
bool isDisabled() const noexcept { return size() == 0; }
|
||||
|
||||
/** Returns an array of all the types in this channel set. */
|
||||
Array<ChannelType> getChannelTypes() const;
|
||||
|
||||
/** Returns the type of one of the channels in the set, by index. */
|
||||
ChannelType getTypeOfChannel (int channelIndex) const noexcept;
|
||||
|
||||
/** Returns the index for a particular channel-type.
|
||||
Will return -1 if the this set does not contain a channel of this type. */
|
||||
int getChannelIndexForType (ChannelType type) const noexcept;
|
||||
|
||||
/** Returns a string containing a whitespace-separated list of speaker types
|
||||
corresponding to each channel. For example in a 5.1 arrangement,
|
||||
the string may be "L R C Lfe Ls Rs". If the speaker arrangement is unknown,
|
||||
the returned string will be empty.*/
|
||||
String getSpeakerArrangementAsString() const;
|
||||
|
||||
/** Returns an AudioChannelSet from a string returned by getSpeakerArrangementAsString
|
||||
|
||||
@see getSpeakerArrangementAsString */
|
||||
static AudioChannelSet fromAbbreviatedString (const String& set);
|
||||
|
||||
/** Returns the description of the current layout. For example, this method may return
|
||||
"Quadraphonic". Note that the returned string may not be unique. */
|
||||
String getDescription() const;
|
||||
|
||||
/** Returns if this is a channel layout made-up of discrete channels. */
|
||||
bool isDiscreteLayout() const noexcept;
|
||||
|
||||
/** Intersect two channel layouts. */
|
||||
void intersect (const AudioChannelSet& other) { channels &= other.channels; }
|
||||
|
||||
/** Creates a channel set for a list of channel types. This function will assert
|
||||
if you supply a duplicate channel.
|
||||
|
||||
Note that this method ignores the order in which the channels are given, i.e.
|
||||
two arrays with the same elements but in a different order will still result
|
||||
in the same channel set.
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE channelSetWithChannels (const Array<ChannelType>&);
|
||||
|
||||
//==============================================================================
|
||||
// Conversion between wave and juce channel layout identifiers
|
||||
|
||||
/** Create an AudioChannelSet from a WAVEFORMATEXTENSIBLE channelMask (typically used
|
||||
in .wav files). */
|
||||
static AudioChannelSet JUCE_CALLTYPE fromWaveChannelMask (int32 dwChannelMask);
|
||||
|
||||
/** Returns a WAVEFORMATEXTENSIBLE channelMask representation (typically used in .wav
|
||||
files) of the receiver.
|
||||
|
||||
Returns -1 if the receiver cannot be represented in a WAVEFORMATEXTENSIBLE channelMask
|
||||
representation.
|
||||
*/
|
||||
int32 getWaveChannelMask() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the ambisonic order that includes exactly numChannels, or -1 if no
|
||||
supported ambisonic order contains exactly numChannels.
|
||||
*/
|
||||
static int getAmbisonicOrderForNumChannels (int numChannels, int maxOrderToCheck = 7);
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const AudioChannelSet&) const noexcept;
|
||||
bool operator!= (const AudioChannelSet&) const noexcept;
|
||||
bool operator< (const AudioChannelSet&) const noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
BigInteger channels;
|
||||
|
||||
//==============================================================================
|
||||
explicit AudioChannelSet (uint32);
|
||||
explicit AudioChannelSet (const std::initializer_list<ChannelType>&);
|
||||
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
+635
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
*unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
*unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fffff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fffff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fffffff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
*unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
auto maxVal = (double) 0x7fffffff;
|
||||
auto intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
intData += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += destBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= destBytesPerSample;
|
||||
*unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
||||
|
||||
char* d = static_cast<char*> (dest);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<float*> (d) = source[i];
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
*unalignedPointerCast<uint32*> (d) = ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
|
||||
#endif
|
||||
|
||||
d += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
|
||||
{
|
||||
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
||||
|
||||
auto d = static_cast<char*> (dest);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
*unalignedPointerCast<float*> (d) = source[i];
|
||||
|
||||
#if JUCE_LITTLE_ENDIAN
|
||||
*unalignedPointerCast<uint32*> (d) = ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
|
||||
#endif
|
||||
|
||||
d += destBytesPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint16*> (intData));
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint16*> (intData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint16*> (intData));
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint16*> (intData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / (float) 0x7fffffff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint32*> (intData));
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint32*> (intData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / (float) 0x7fffffff;
|
||||
auto intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint32*> (intData));
|
||||
intData += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intData += srcBytesPerSample * numSamples;
|
||||
|
||||
for (int i = numSamples; --i >= 0;)
|
||||
{
|
||||
intData -= srcBytesPerSample;
|
||||
dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint32*> (intData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
auto s = static_cast<const char*> (source);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = *unalignedPointerCast<const float*> (s);
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
auto d = unalignedPointerCast<uint32*> (dest + i);
|
||||
*d = ByteOrder::swap (*d);
|
||||
#endif
|
||||
|
||||
s += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
|
||||
{
|
||||
auto s = static_cast<const char*> (source);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i] = *unalignedPointerCast<const float*> (s);
|
||||
|
||||
#if JUCE_LITTLE_ENDIAN
|
||||
auto d = unalignedPointerCast<uint32*> (dest + i);
|
||||
*d = ByteOrder::swap (*d);
|
||||
#endif
|
||||
|
||||
s += srcBytesPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples)
|
||||
{
|
||||
switch (destFormat)
|
||||
{
|
||||
case int16LE: convertFloatToInt16LE (source, dest, numSamples); break;
|
||||
case int16BE: convertFloatToInt16BE (source, dest, numSamples); break;
|
||||
case int24LE: convertFloatToInt24LE (source, dest, numSamples); break;
|
||||
case int24BE: convertFloatToInt24BE (source, dest, numSamples); break;
|
||||
case int32LE: convertFloatToInt32LE (source, dest, numSamples); break;
|
||||
case int32BE: convertFloatToInt32BE (source, dest, numSamples); break;
|
||||
case float32LE: convertFloatToFloat32LE (source, dest, numSamples); break;
|
||||
case float32BE: convertFloatToFloat32BE (source, dest, numSamples); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples)
|
||||
{
|
||||
switch (sourceFormat)
|
||||
{
|
||||
case int16LE: convertInt16LEToFloat (source, dest, numSamples); break;
|
||||
case int16BE: convertInt16BEToFloat (source, dest, numSamples); break;
|
||||
case int24LE: convertInt24LEToFloat (source, dest, numSamples); break;
|
||||
case int24BE: convertInt24BEToFloat (source, dest, numSamples); break;
|
||||
case int32LE: convertInt32LEToFloat (source, dest, numSamples); break;
|
||||
case int32BE: convertInt32BEToFloat (source, dest, numSamples); break;
|
||||
case float32LE: convertFloat32LEToFloat (source, dest, numSamples); break;
|
||||
case float32BE: convertFloat32BEToFloat (source, dest, numSamples); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
|
||||
{
|
||||
using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
|
||||
|
||||
AudioData::interleaveSamples (AudioData::NonInterleavedSource<Format> { source, numChannels },
|
||||
AudioData::InterleavedDest<Format> { dest, numChannels },
|
||||
numSamples);
|
||||
}
|
||||
|
||||
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
|
||||
{
|
||||
using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
|
||||
|
||||
AudioData::deinterleaveSamples (AudioData::InterleavedSource<Format> { source, numChannels },
|
||||
AudioData::NonInterleavedDest<Format> { dest, numChannels },
|
||||
numSamples);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class AudioConversionTests final : public UnitTest
|
||||
{
|
||||
public:
|
||||
AudioConversionTests()
|
||||
: UnitTest ("Audio data conversion", UnitTestCategories::audio)
|
||||
{}
|
||||
|
||||
template <class F1, class E1, class F2, class E2>
|
||||
struct Test5
|
||||
{
|
||||
static void test (UnitTest& unitTest, Random& r)
|
||||
{
|
||||
test (unitTest, false, r);
|
||||
test (unitTest, true, r);
|
||||
}
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
|
||||
static void test (UnitTest& unitTest, bool inPlace, Random& r)
|
||||
{
|
||||
const int numSamples = 2048;
|
||||
int32 original [(size_t) numSamples],
|
||||
converted[(size_t) numSamples],
|
||||
reversed [(size_t) numSamples];
|
||||
|
||||
{
|
||||
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
|
||||
bool clippingFailed = false;
|
||||
|
||||
for (int i = 0; i < numSamples / 2; ++i)
|
||||
{
|
||||
d.setAsFloat (r.nextFloat() * 2.2f - 1.1f);
|
||||
|
||||
if (! d.isFloatingPoint())
|
||||
clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed;
|
||||
|
||||
++d;
|
||||
d.setAsInt32 (r.nextInt());
|
||||
++d;
|
||||
}
|
||||
|
||||
unitTest.expect (! clippingFailed);
|
||||
}
|
||||
|
||||
// convert data from the source to dest format..
|
||||
std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
|
||||
AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
|
||||
conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
|
||||
|
||||
// ..and back again..
|
||||
conv.reset (new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
|
||||
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
|
||||
if (! inPlace)
|
||||
zeromem (reversed, sizeof (reversed));
|
||||
|
||||
conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
|
||||
|
||||
{
|
||||
int biggestDiff = 0;
|
||||
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original);
|
||||
AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed);
|
||||
|
||||
const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution()
|
||||
+ AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution();
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32()));
|
||||
++d1;
|
||||
++d2;
|
||||
}
|
||||
|
||||
unitTest.expect (biggestDiff <= errorMargin);
|
||||
}
|
||||
}
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
};
|
||||
|
||||
template <class F1, class E1, class FormatType>
|
||||
struct Test3
|
||||
{
|
||||
static void test (UnitTest& unitTest, Random& r)
|
||||
{
|
||||
Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r);
|
||||
Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r);
|
||||
}
|
||||
};
|
||||
|
||||
template <class FormatType, class Endianness>
|
||||
struct Test2
|
||||
{
|
||||
static void test (UnitTest& unitTest, Random& r)
|
||||
{
|
||||
Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r);
|
||||
Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r);
|
||||
Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r);
|
||||
Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r);
|
||||
Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r);
|
||||
Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r);
|
||||
}
|
||||
};
|
||||
|
||||
template <class FormatType>
|
||||
struct Test1
|
||||
{
|
||||
static void test (UnitTest& unitTest, Random& r)
|
||||
{
|
||||
Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r);
|
||||
Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r);
|
||||
}
|
||||
};
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
auto r = getRandom();
|
||||
beginTest ("Round-trip conversion: Int8");
|
||||
Test1 <AudioData::Int8>::test (*this, r);
|
||||
beginTest ("Round-trip conversion: Int16");
|
||||
Test1 <AudioData::Int16>::test (*this, r);
|
||||
beginTest ("Round-trip conversion: Int24");
|
||||
Test1 <AudioData::Int24>::test (*this, r);
|
||||
beginTest ("Round-trip conversion: Int32");
|
||||
Test1 <AudioData::Int32>::test (*this, r);
|
||||
beginTest ("Round-trip conversion: Float32");
|
||||
Test1 <AudioData::Float32>::test (*this, r);
|
||||
|
||||
using Format = AudioData::Format<AudioData::Float32, AudioData::NativeEndian>;
|
||||
|
||||
beginTest ("Interleaving");
|
||||
{
|
||||
constexpr auto numChannels = 4;
|
||||
constexpr auto numSamples = 512;
|
||||
|
||||
AudioBuffer<float> sourceBuffer { numChannels, numSamples },
|
||||
destBuffer { 1, numChannels * numSamples };
|
||||
|
||||
for (int ch = 0; ch < numChannels; ++ch)
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
sourceBuffer.setSample (ch, i, r.nextFloat());
|
||||
|
||||
AudioData::interleaveSamples (AudioData::NonInterleavedSource<Format> { sourceBuffer.getArrayOfReadPointers(), numChannels },
|
||||
AudioData::InterleavedDest<Format> { destBuffer.getWritePointer (0), numChannels },
|
||||
numSamples);
|
||||
|
||||
for (int ch = 0; ch < numChannels; ++ch)
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
expectEquals (destBuffer.getSample (0, ch + (i * numChannels)), sourceBuffer.getSample (ch, i));
|
||||
}
|
||||
|
||||
beginTest ("Deinterleaving");
|
||||
{
|
||||
constexpr auto numChannels = 4;
|
||||
constexpr auto numSamples = 512;
|
||||
|
||||
AudioBuffer<float> sourceBuffer { 1, numChannels * numSamples },
|
||||
destBuffer { numChannels, numSamples };
|
||||
|
||||
for (int ch = 0; ch < numChannels; ++ch)
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
sourceBuffer.setSample (0, ch + (i * numChannels), r.nextFloat());
|
||||
|
||||
AudioData::deinterleaveSamples (AudioData::InterleavedSource<Format> { sourceBuffer.getReadPointer (0), numChannels },
|
||||
AudioData::NonInterleavedDest<Format> { destBuffer.getArrayOfWritePointers(), numChannels },
|
||||
numSamples);
|
||||
|
||||
for (int ch = 0; ch < numChannels; ++ch)
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
expectEquals (sourceBuffer.getSample (0, ch + (i * numChannels)), destBuffer.getSample (ch, i));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AudioConversionTests audioConversionUnitTests;
|
||||
|
||||
#endif
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
+860
@@ -0,0 +1,860 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This class a container which holds all the classes pertaining to the AudioData::Pointer
|
||||
audio sample format class.
|
||||
|
||||
@see AudioData::Pointer.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioData
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
// These types can be used as the SampleFormat template parameter for the AudioData::Pointer class.
|
||||
|
||||
class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */
|
||||
class UInt8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit unsigned integer packed data format. */
|
||||
class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */
|
||||
class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */
|
||||
class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */
|
||||
class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */
|
||||
|
||||
//==============================================================================
|
||||
// These types can be used as the Endianness template parameter for the AudioData::Pointer class.
|
||||
|
||||
class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */
|
||||
class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */
|
||||
class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */
|
||||
|
||||
//==============================================================================
|
||||
// These types can be used as the InterleavingType template parameter for the AudioData::Pointer class.
|
||||
|
||||
class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */
|
||||
class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */
|
||||
|
||||
//==============================================================================
|
||||
// These types can be used as the Constness template parameter for the AudioData::Pointer class.
|
||||
|
||||
class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */
|
||||
class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */
|
||||
|
||||
#ifndef DOXYGEN
|
||||
//==============================================================================
|
||||
class BigEndian
|
||||
{
|
||||
public:
|
||||
template <class SampleFormatType> static float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatBE(); }
|
||||
template <class SampleFormatType> static void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); }
|
||||
template <class SampleFormatType> static int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32BE(); }
|
||||
template <class SampleFormatType> static void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); }
|
||||
template <class SourceType, class DestType> static void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromBE (source); }
|
||||
enum { isBigEndian = 1 };
|
||||
};
|
||||
|
||||
class LittleEndian
|
||||
{
|
||||
public:
|
||||
template <class SampleFormatType> static float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatLE(); }
|
||||
template <class SampleFormatType> static void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); }
|
||||
template <class SampleFormatType> static int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32LE(); }
|
||||
template <class SampleFormatType> static void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); }
|
||||
template <class SourceType, class DestType> static void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromLE (source); }
|
||||
enum { isBigEndian = 0 };
|
||||
};
|
||||
|
||||
#if JUCE_BIG_ENDIAN
|
||||
class NativeEndian : public BigEndian {};
|
||||
#else
|
||||
class NativeEndian : public LittleEndian {};
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class Int8
|
||||
{
|
||||
public:
|
||||
inline Int8 (void* d) noexcept : data (static_cast<int8*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { ++data; }
|
||||
inline void skip (int numSamples) noexcept { data += numSamples; }
|
||||
inline float getAsFloatLE() const noexcept { return (float) (*data * (1.0 / (1.0 + (double) maxValue))); }
|
||||
inline float getAsFloatBE() const noexcept { return getAsFloatLE(); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int) (*((uint8*) data) << 24); }
|
||||
inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); }
|
||||
inline void setAsInt32LE (int newValue) noexcept { *data = (int8) (newValue >> 24); }
|
||||
inline void setAsInt32BE (int newValue) noexcept { setAsInt32LE (newValue); }
|
||||
inline void clear() noexcept { *data = 0; }
|
||||
inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int8& source) noexcept { *data = *source.data; }
|
||||
|
||||
int8* data;
|
||||
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
||||
};
|
||||
|
||||
class UInt8
|
||||
{
|
||||
public:
|
||||
inline UInt8 (void* d) noexcept : data (static_cast<uint8*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { ++data; }
|
||||
inline void skip (int numSamples) noexcept { data += numSamples; }
|
||||
inline float getAsFloatLE() const noexcept { return (float) ((*data - 128) * (1.0 / (1.0 + (double) maxValue))); }
|
||||
inline float getAsFloatBE() const noexcept { return getAsFloatLE(); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + (double) maxValue))); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int) (((uint8) (*data - 128)) << 24); }
|
||||
inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); }
|
||||
inline void setAsInt32LE (int newValue) noexcept { *data = (uint8) (128 + (newValue >> 24)); }
|
||||
inline void setAsInt32BE (int newValue) noexcept { setAsInt32LE (newValue); }
|
||||
inline void clear() noexcept { *data = 128; }
|
||||
inline void clearMultiple (int num) noexcept { memset (data, 128, (size_t) num) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (UInt8& source) noexcept { *data = *source.data; }
|
||||
|
||||
uint8* data;
|
||||
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
||||
};
|
||||
|
||||
class Int16
|
||||
{
|
||||
public:
|
||||
inline Int16 (void* d) noexcept : data (static_cast<uint16*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { ++data; }
|
||||
inline void skip (int numSamples) noexcept { data += numSamples; }
|
||||
inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); }
|
||||
inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue)))); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue)))); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); }
|
||||
inline int32 getAsInt32BE() const noexcept { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); }
|
||||
inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); }
|
||||
inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); }
|
||||
inline void clear() noexcept { *data = 0; }
|
||||
inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int16& source) noexcept { *data = *source.data; }
|
||||
|
||||
uint16* data;
|
||||
enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
|
||||
};
|
||||
|
||||
class Int24
|
||||
{
|
||||
public:
|
||||
inline Int24 (void* d) noexcept : data (static_cast<char*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { data += 3; }
|
||||
inline void skip (int numSamples) noexcept { data += 3 * numSamples; }
|
||||
inline float getAsFloatLE() const noexcept { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + (double) maxValue))); }
|
||||
inline float getAsFloatBE() const noexcept { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + (double) maxValue))); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))), data); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + (double) maxValue))), data); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int32) (((unsigned int) ByteOrder::littleEndian24Bit (data)) << 8); }
|
||||
inline int32 getAsInt32BE() const noexcept { return (int32) (((unsigned int) ByteOrder::bigEndian24Bit (data)) << 8); }
|
||||
inline void setAsInt32LE (int32 newValue) noexcept { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); }
|
||||
inline void setAsInt32BE (int32 newValue) noexcept { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); }
|
||||
inline void clear() noexcept { data[0] = 0; data[1] = 0; data[2] = 0; }
|
||||
inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int24& source) noexcept { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; }
|
||||
|
||||
char* data;
|
||||
enum { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
|
||||
};
|
||||
|
||||
class Int32
|
||||
{
|
||||
public:
|
||||
inline Int32 (void* d) noexcept : data (static_cast<uint32*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { ++data; }
|
||||
inline void skip (int numSamples) noexcept { data += numSamples; }
|
||||
inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); }
|
||||
inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (int32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (int32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data); }
|
||||
inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data); }
|
||||
inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); }
|
||||
inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); }
|
||||
inline void clear() noexcept { *data = 0; }
|
||||
inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int32& source) noexcept { *data = *source.data; }
|
||||
|
||||
uint32* data;
|
||||
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
|
||||
};
|
||||
|
||||
/** A 32-bit integer type, of which only the bottom 24 bits are used. */
|
||||
class Int24in32 : public Int32
|
||||
{
|
||||
public:
|
||||
inline Int24in32 (void* d) noexcept : Int32 (d) {}
|
||||
|
||||
inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); }
|
||||
inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + (double) maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
||||
inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) ((double) maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
||||
inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data) << 8; }
|
||||
inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data) << 8; }
|
||||
inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue >> 8); }
|
||||
inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue >> 8); }
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
||||
inline void copyFromSameType (Int24in32& source) noexcept { *data = *source.data; }
|
||||
|
||||
enum { bytesPerSample = 4, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 };
|
||||
};
|
||||
|
||||
class Float32
|
||||
{
|
||||
public:
|
||||
inline Float32 (void* d) noexcept : data (static_cast<float*> (d)) {}
|
||||
|
||||
inline void advance() noexcept { ++data; }
|
||||
inline void skip (int numSamples) noexcept { data += numSamples; }
|
||||
#if JUCE_BIG_ENDIAN
|
||||
inline float getAsFloatBE() const noexcept { return *data; }
|
||||
inline void setAsFloatBE (float newValue) noexcept { *data = newValue; }
|
||||
inline float getAsFloatLE() const noexcept { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; }
|
||||
inline void setAsFloatLE (float newValue) noexcept { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); }
|
||||
#else
|
||||
inline float getAsFloatLE() const noexcept { return *data; }
|
||||
inline void setAsFloatLE (float newValue) noexcept { *data = newValue; }
|
||||
inline float getAsFloatBE() const noexcept { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; }
|
||||
inline void setAsFloatBE (float newValue) noexcept { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); }
|
||||
#endif
|
||||
inline int32 getAsInt32LE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatLE()) * (double) maxValue); }
|
||||
inline int32 getAsInt32BE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatBE()) * (double) maxValue); }
|
||||
inline void setAsInt32LE (int32 newValue) noexcept { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + (double) maxValue)))); }
|
||||
inline void setAsInt32BE (int32 newValue) noexcept { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + (double) maxValue)))); }
|
||||
inline void clear() noexcept { *data = 0; }
|
||||
inline void clearMultiple (int num) noexcept { zeromem (data, (size_t) (num * bytesPerSample)) ;}
|
||||
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsFloatLE (source.getAsFloat()); }
|
||||
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsFloatBE (source.getAsFloat()); }
|
||||
inline void copyFromSameType (Float32& source) noexcept { *data = *source.data; }
|
||||
|
||||
float* data;
|
||||
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class NonInterleaved
|
||||
{
|
||||
public:
|
||||
inline NonInterleaved() = default;
|
||||
inline NonInterleaved (const NonInterleaved&) = default;
|
||||
inline NonInterleaved (int) noexcept {}
|
||||
inline void copyFrom (const NonInterleaved&) noexcept {}
|
||||
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept { s.advance(); }
|
||||
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numSamples); }
|
||||
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) noexcept { s.clearMultiple (numSamples); }
|
||||
template <class SampleFormatType> static int getNumBytesBetweenSamples (const SampleFormatType&) noexcept { return SampleFormatType::bytesPerSample; }
|
||||
|
||||
enum { isInterleavedType = 0, numInterleavedChannels = 1 };
|
||||
};
|
||||
|
||||
class Interleaved
|
||||
{
|
||||
public:
|
||||
inline Interleaved() noexcept {}
|
||||
inline Interleaved (const Interleaved& other) = default;
|
||||
inline Interleaved (const int numInterleavedChans) noexcept : numInterleavedChannels (numInterleavedChans) {}
|
||||
inline void copyFrom (const Interleaved& other) noexcept { numInterleavedChannels = other.numInterleavedChannels; }
|
||||
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept { s.skip (numInterleavedChannels); }
|
||||
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numInterleavedChannels * numSamples); }
|
||||
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) noexcept { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } }
|
||||
template <class SampleFormatType> inline int getNumBytesBetweenSamples (const SampleFormatType&) const noexcept { return numInterleavedChannels * SampleFormatType::bytesPerSample; }
|
||||
int numInterleavedChannels = 1;
|
||||
enum { isInterleavedType = 1 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class NonConst
|
||||
{
|
||||
public:
|
||||
using VoidType = void;
|
||||
static void* toVoidPtr (VoidType* v) noexcept { return v; }
|
||||
enum { isConst = 0 };
|
||||
};
|
||||
|
||||
class Const
|
||||
{
|
||||
public:
|
||||
using VoidType = const void;
|
||||
static void* toVoidPtr (VoidType* v) noexcept { return const_cast<void*> (v); }
|
||||
enum { isConst = 1 };
|
||||
};
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A pointer to a block of audio data with a particular encoding.
|
||||
|
||||
This object can be used to read and write from blocks of encoded audio samples. To create one, you specify
|
||||
the audio format as a series of template parameters, e.g.
|
||||
@code
|
||||
// this creates a pointer for reading from a const array of 16-bit little-endian packed samples.
|
||||
AudioData::Pointer <AudioData::Int16,
|
||||
AudioData::LittleEndian,
|
||||
AudioData::NonInterleaved,
|
||||
AudioData::Const> pointer (someRawAudioData);
|
||||
|
||||
// These methods read the sample that is being pointed to
|
||||
float firstSampleAsFloat = pointer.getAsFloat();
|
||||
int32 firstSampleAsInt = pointer.getAsInt32();
|
||||
++pointer; // moves the pointer to the next sample.
|
||||
pointer += 3; // skips the next 3 samples.
|
||||
@endcode
|
||||
|
||||
The convertSamples() method lets you copy a range of samples from one format to another, automatically
|
||||
converting its format.
|
||||
|
||||
@see AudioData::Converter
|
||||
*/
|
||||
template <typename SampleFormat,
|
||||
typename Endianness,
|
||||
typename InterleavingType,
|
||||
typename Constness>
|
||||
class Pointer : private InterleavingType // (inherited for EBCO)
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a non-interleaved pointer from some raw data in the appropriate format.
|
||||
This constructor is only used if you've specified the AudioData::NonInterleaved option -
|
||||
for interleaved formats, use the constructor that also takes a number of channels.
|
||||
*/
|
||||
Pointer (typename Constness::VoidType* sourceData) noexcept
|
||||
: data (Constness::toVoidPtr (sourceData))
|
||||
{
|
||||
// If you're using interleaved data, call the other constructor! If you're using non-interleaved data,
|
||||
// you should pass NonInterleaved as the template parameter for the interleaving type!
|
||||
static_assert (InterleavingType::isInterleavedType == 0, "Incorrect constructor for interleaved data");
|
||||
}
|
||||
|
||||
/** Creates a pointer from some raw data in the appropriate format with the specified number of interleaved channels.
|
||||
For non-interleaved data, use the other constructor.
|
||||
*/
|
||||
Pointer (typename Constness::VoidType* sourceData, int numInterleaved) noexcept
|
||||
: InterleavingType (numInterleaved), data (Constness::toVoidPtr (sourceData))
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another pointer. */
|
||||
Pointer (const Pointer& other) noexcept
|
||||
: InterleavingType (other), data (other.data)
|
||||
{
|
||||
}
|
||||
|
||||
Pointer& operator= (const Pointer& other) noexcept
|
||||
{
|
||||
InterleavingType::operator= (other);
|
||||
data = other.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the value of the first sample as a floating point value.
|
||||
The value will be in the range -1.0 to 1.0 for integer formats. For floating point
|
||||
formats, the value could be outside that range, although -1 to 1 is the standard range.
|
||||
*/
|
||||
inline float getAsFloat() const noexcept { return Endianness::getAsFloat (data); }
|
||||
|
||||
/** Sets the value of the first sample as a floating point value.
|
||||
|
||||
(This method can only be used if the AudioData::NonConst option was used).
|
||||
The value should be in the range -1.0 to 1.0 - for integer formats, values outside that
|
||||
range will be clipped. For floating point formats, any value passed in here will be
|
||||
written directly, although -1 to 1 is the standard range.
|
||||
*/
|
||||
inline void setAsFloat (float newValue) noexcept
|
||||
{
|
||||
// trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
|
||||
static_assert (Constness::isConst == 0, "Attempt to write to a const pointer");
|
||||
Endianness::setAsFloat (data, newValue);
|
||||
}
|
||||
|
||||
/** Returns the value of the first sample as a 32-bit integer.
|
||||
The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be
|
||||
shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up
|
||||
by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will
|
||||
be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff.
|
||||
*/
|
||||
inline int32 getAsInt32() const noexcept { return Endianness::getAsInt32 (data); }
|
||||
|
||||
/** Sets the value of the first sample as a 32-bit integer.
|
||||
This will be mapped to the range of the format that is being written - see getAsInt32().
|
||||
*/
|
||||
inline void setAsInt32 (int32 newValue) noexcept
|
||||
{
|
||||
// trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
|
||||
static_assert (Constness::isConst == 0, "Attempt to write to a const pointer");
|
||||
Endianness::setAsInt32 (data, newValue);
|
||||
}
|
||||
|
||||
/** Moves the pointer along to the next sample. */
|
||||
inline Pointer& operator++() noexcept { advance(); return *this; }
|
||||
|
||||
/** Moves the pointer back to the previous sample. */
|
||||
inline Pointer& operator--() noexcept { this->advanceDataBy (data, -1); return *this; }
|
||||
|
||||
/** Adds a number of samples to the pointer's position. */
|
||||
Pointer& operator+= (int samplesToJump) noexcept { this->advanceDataBy (data, samplesToJump); return *this; }
|
||||
|
||||
/** Returns a new pointer with the specified offset from this pointer's position. */
|
||||
Pointer operator+ (int samplesToJump) const { return Pointer { *this } += samplesToJump; }
|
||||
|
||||
/** Writes a stream of samples into this pointer from another pointer.
|
||||
This will copy the specified number of samples, converting between formats appropriately.
|
||||
*/
|
||||
void convertSamples (Pointer source, int numSamples) const noexcept
|
||||
{
|
||||
// trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
|
||||
static_assert (Constness::isConst == 0, "Attempt to write to a const pointer");
|
||||
|
||||
for (Pointer dest (*this); --numSamples >= 0;)
|
||||
{
|
||||
dest.data.copyFromSameType (source.data);
|
||||
dest.advance();
|
||||
source.advance();
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes a stream of samples into this pointer from another pointer.
|
||||
This will copy the specified number of samples, converting between formats appropriately.
|
||||
*/
|
||||
template <class OtherPointerType>
|
||||
void convertSamples (OtherPointerType source, int numSamples) const noexcept
|
||||
{
|
||||
// trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead!
|
||||
static_assert (Constness::isConst == 0, "Attempt to write to a const pointer");
|
||||
|
||||
Pointer dest (*this);
|
||||
|
||||
if (source.getRawData() != getRawData() || source.getNumBytesBetweenSamples() >= getNumBytesBetweenSamples())
|
||||
{
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
Endianness::copyFrom (dest.data, source);
|
||||
dest.advance();
|
||||
++source;
|
||||
}
|
||||
}
|
||||
else // copy backwards if we're increasing the sample width..
|
||||
{
|
||||
dest += numSamples;
|
||||
source += numSamples;
|
||||
|
||||
while (--numSamples >= 0)
|
||||
Endianness::copyFrom ((--dest).data, --source);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a number of samples to zero. */
|
||||
void clearSamples (int numSamples) const noexcept
|
||||
{
|
||||
Pointer dest (*this);
|
||||
dest.clear (dest.data, numSamples);
|
||||
}
|
||||
|
||||
/** Scans a block of data, returning the lowest and highest levels as floats */
|
||||
Range<float> findMinAndMax (size_t numSamples) const noexcept
|
||||
{
|
||||
if (numSamples == 0)
|
||||
return Range<float>();
|
||||
|
||||
Pointer dest (*this);
|
||||
|
||||
if (isFloatingPoint())
|
||||
{
|
||||
float mn = dest.getAsFloat();
|
||||
dest.advance();
|
||||
float mx = mn;
|
||||
|
||||
while (--numSamples > 0)
|
||||
{
|
||||
const float v = dest.getAsFloat();
|
||||
dest.advance();
|
||||
|
||||
if (mx < v) mx = v;
|
||||
if (v < mn) mn = v;
|
||||
}
|
||||
|
||||
return Range<float> (mn, mx);
|
||||
}
|
||||
|
||||
int32 mn = dest.getAsInt32();
|
||||
dest.advance();
|
||||
int32 mx = mn;
|
||||
|
||||
while (--numSamples > 0)
|
||||
{
|
||||
const int v = dest.getAsInt32();
|
||||
dest.advance();
|
||||
|
||||
if (mx < v) mx = v;
|
||||
if (v < mn) mn = v;
|
||||
}
|
||||
|
||||
return Range<float> ((float) mn * (float) (1.0 / (1.0 + (double) Int32::maxValue)),
|
||||
(float) mx * (float) (1.0 / (1.0 + (double) Int32::maxValue)));
|
||||
}
|
||||
|
||||
/** Scans a block of data, returning the lowest and highest levels as floats */
|
||||
void findMinAndMax (size_t numSamples, float& minValue, float& maxValue) const noexcept
|
||||
{
|
||||
Range<float> r (findMinAndMax (numSamples));
|
||||
minValue = r.getStart();
|
||||
maxValue = r.getEnd();
|
||||
}
|
||||
|
||||
/** Returns true if the pointer is using a floating-point format. */
|
||||
static bool isFloatingPoint() noexcept { return (bool) SampleFormat::isFloat; }
|
||||
|
||||
/** Returns true if the format is big-endian. */
|
||||
static bool isBigEndian() noexcept { return (bool) Endianness::isBigEndian; }
|
||||
|
||||
/** Returns the number of bytes in each sample (ignoring the number of interleaved channels). */
|
||||
static int getBytesPerSample() noexcept { return (int) SampleFormat::bytesPerSample; }
|
||||
|
||||
/** Returns the number of interleaved channels in the format. */
|
||||
int getNumInterleavedChannels() const noexcept { return (int) this->numInterleavedChannels; }
|
||||
|
||||
/** Returns the number of bytes between the start address of each sample. */
|
||||
int getNumBytesBetweenSamples() const noexcept { return InterleavingType::getNumBytesBetweenSamples (data); }
|
||||
|
||||
/** Returns the accuracy of this format when represented as a 32-bit integer.
|
||||
This is the smallest number above 0 that can be represented in the sample format, converted to
|
||||
a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit,
|
||||
its resolution is 0x100.
|
||||
*/
|
||||
static int get32BitResolution() noexcept { return (int) SampleFormat::resolution; }
|
||||
|
||||
/** Returns a pointer to the underlying data. */
|
||||
const void* getRawData() const noexcept { return data.data; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
SampleFormat data;
|
||||
|
||||
inline void advance() noexcept { this->advanceData (data); }
|
||||
|
||||
Pointer operator++ (int); // private to force you to use the more efficient pre-increment!
|
||||
Pointer operator-- (int);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** A base class for objects that are used to convert between two different sample formats.
|
||||
|
||||
The AudioData::ConverterInstance implements this base class and can be templated, so
|
||||
you can create an instance that converts between two particular formats, and then
|
||||
store this in the abstract base class.
|
||||
|
||||
@see AudioData::ConverterInstance
|
||||
*/
|
||||
class Converter
|
||||
{
|
||||
public:
|
||||
virtual ~Converter() = default;
|
||||
|
||||
/** Converts a sequence of samples from the converter's source format into the dest format. */
|
||||
virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0;
|
||||
|
||||
/** Converts a sequence of samples from the converter's source format into the dest format.
|
||||
This method takes sub-channel indexes, which can be used with interleaved formats in order to choose a
|
||||
particular sub-channel of the data to be used.
|
||||
*/
|
||||
virtual void convertSamples (void* destSamples, int destSubChannel,
|
||||
const void* sourceSamples, int sourceSubChannel, int numSamples) const = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class that converts between two templated AudioData::Pointer types, and which
|
||||
implements the AudioData::Converter interface.
|
||||
|
||||
This can be used as a concrete instance of the AudioData::Converter abstract class.
|
||||
|
||||
@see AudioData::Converter
|
||||
*/
|
||||
template <class SourceSampleType, class DestSampleType>
|
||||
class ConverterInstance : public Converter
|
||||
{
|
||||
public:
|
||||
ConverterInstance (int numSourceChannels = 1, int numDestChannels = 1)
|
||||
: sourceChannels (numSourceChannels), destChannels (numDestChannels)
|
||||
{}
|
||||
|
||||
void convertSamples (void* dest, const void* source, int numSamples) const override
|
||||
{
|
||||
SourceSampleType s (source, sourceChannels);
|
||||
DestSampleType d (dest, destChannels);
|
||||
d.convertSamples (s, numSamples);
|
||||
}
|
||||
|
||||
void convertSamples (void* dest, int destSubChannel,
|
||||
const void* source, int sourceSubChannel, int numSamples) const override
|
||||
{
|
||||
jassert (destSubChannel < destChannels && sourceSubChannel < sourceChannels);
|
||||
|
||||
SourceSampleType s (addBytesToPointer (source, sourceSubChannel * SourceSampleType::getBytesPerSample()), sourceChannels);
|
||||
DestSampleType d (addBytesToPointer (dest, destSubChannel * DestSampleType::getBytesPerSample()), destChannels);
|
||||
d.convertSamples (s, numSamples);
|
||||
}
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE (ConverterInstance)
|
||||
|
||||
const int sourceChannels, destChannels;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** A struct that contains a SampleFormat and Endianness to be used with the source and
|
||||
destination types when calling the interleaveSamples() and deinterleaveSamples() helpers.
|
||||
|
||||
@see interleaveSamples, deinterleaveSamples
|
||||
*/
|
||||
template <typename DataFormatIn, typename EndiannessIn>
|
||||
struct Format
|
||||
{
|
||||
using DataFormat = DataFormatIn;
|
||||
using Endianness = EndiannessIn;
|
||||
};
|
||||
|
||||
private:
|
||||
template <bool IsInterleaved, bool IsConst, typename...>
|
||||
struct ChannelDataSubtypes;
|
||||
|
||||
template <bool IsInterleaved, bool IsConst, typename DataFormat, typename Endianness>
|
||||
struct ChannelDataSubtypes<IsInterleaved, IsConst, DataFormat, Endianness>
|
||||
{
|
||||
using ElementType = std::remove_pointer_t<decltype (DataFormat::data)>;
|
||||
using ChannelType = std::conditional_t<IsConst, const ElementType*, ElementType*>;
|
||||
using DataType = std::conditional_t<IsInterleaved, ChannelType, ChannelType const*>;
|
||||
using PointerType = Pointer<DataFormat,
|
||||
Endianness,
|
||||
std::conditional_t<IsInterleaved, Interleaved, NonInterleaved>,
|
||||
std::conditional_t<IsConst, Const, NonConst>>;
|
||||
};
|
||||
|
||||
template <bool IsInterleaved, bool IsConst, typename DataFormat, typename Endianness>
|
||||
struct ChannelDataSubtypes<IsInterleaved, IsConst, Format<DataFormat, Endianness>>
|
||||
{
|
||||
using Subtypes = ChannelDataSubtypes<IsInterleaved, IsConst, DataFormat, Endianness>;
|
||||
using DataType = typename Subtypes::DataType;
|
||||
using PointerType = typename Subtypes::PointerType;
|
||||
};
|
||||
|
||||
template <bool IsInterleaved, bool IsConst, typename... Format>
|
||||
struct ChannelData
|
||||
{
|
||||
using Subtypes = ChannelDataSubtypes<IsInterleaved, IsConst, Format...>;
|
||||
using DataType = typename Subtypes::DataType;
|
||||
using PointerType = typename Subtypes::PointerType;
|
||||
|
||||
DataType data;
|
||||
int channels;
|
||||
};
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** A sequence of interleaved samples used as the source for the deinterleaveSamples() method. */
|
||||
template <typename... Format> using InterleavedSource = ChannelData<true, true, Format...>;
|
||||
/** A sequence of interleaved samples used as the destination for the interleaveSamples() method. */
|
||||
template <typename... Format> using InterleavedDest = ChannelData<true, false, Format...>;
|
||||
/** A sequence of non-interleaved samples used as the source for the interleaveSamples() method. */
|
||||
template <typename... Format> using NonInterleavedSource = ChannelData<false, true, Format...>;
|
||||
/** A sequence of non-interleaved samples used as the destination for the deinterleaveSamples() method. */
|
||||
template <typename... Format> using NonInterleavedDest = ChannelData<false, false, Format...>;
|
||||
|
||||
/** A helper function for converting a sequence of samples from a non-interleaved source
|
||||
to an interleaved destination.
|
||||
|
||||
When calling this method you need to specify the source and destination data format and endianness
|
||||
from the AudioData SampleFormat and Endianness types and provide the data and number of channels
|
||||
for each. For example, to convert a floating-point stream of big endian samples to an interleaved,
|
||||
native endian stream of 16-bit integer samples you would do the following:
|
||||
|
||||
@code
|
||||
using SourceFormat = AudioData::Format<AudioData::Float32, AudioData::BigEndian>;
|
||||
using DestFormat = AudioData::Format<AudioData::Int16, AudioData::NativeEndian>;
|
||||
|
||||
AudioData::interleaveSamples (AudioData::NonInterleavedSource<SourceFormat> { sourceData, numSourceChannels },
|
||||
AudioData::InterleavedDest<DestFormat> { destData, numDestChannels },
|
||||
numSamples);
|
||||
@endcode
|
||||
*/
|
||||
template <typename... SourceFormat, typename... DestFormat>
|
||||
static void interleaveSamples (NonInterleavedSource<SourceFormat...> source,
|
||||
InterleavedDest<DestFormat...> dest,
|
||||
int numSamples)
|
||||
{
|
||||
using SourceType = typename decltype (source)::PointerType;
|
||||
using DestType = typename decltype (dest) ::PointerType;
|
||||
|
||||
for (int i = 0; i < dest.channels; ++i)
|
||||
{
|
||||
const DestType destType (addBytesToPointer (dest.data, i * DestType::getBytesPerSample()), dest.channels);
|
||||
|
||||
if (i < source.channels)
|
||||
{
|
||||
if (*source.data != nullptr)
|
||||
{
|
||||
destType.convertSamples (SourceType { *source.data }, numSamples);
|
||||
++source.data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
destType.clearSamples (numSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A helper function for converting a sequence of samples from an interleaved source
|
||||
to a non-interleaved destination.
|
||||
|
||||
When calling this method you need to specify the source and destination data format and endianness
|
||||
from the AudioData SampleFormat and Endianness types and provide the data and number of channels
|
||||
for each. For example, to convert a floating-point stream of big endian samples to an non-interleaved,
|
||||
native endian stream of 16-bit integer samples you would do the following:
|
||||
|
||||
@code
|
||||
using SourceFormat = AudioData::Format<AudioData::Float32, AudioData::BigEndian>;
|
||||
using DestFormat = AudioData::Format<AudioData::Int16, AudioData::NativeEndian>;
|
||||
|
||||
AudioData::deinterleaveSamples (AudioData::InterleavedSource<SourceFormat> { sourceData, numSourceChannels },
|
||||
AudioData::NonInterleavedDest<DestFormat> { destData, numDestChannels },
|
||||
numSamples);
|
||||
@endcode
|
||||
*/
|
||||
template <typename... SourceFormat, typename... DestFormat>
|
||||
static void deinterleaveSamples (InterleavedSource<SourceFormat...> source,
|
||||
NonInterleavedDest<DestFormat...> dest,
|
||||
int numSamples)
|
||||
{
|
||||
using SourceType = typename decltype (source)::PointerType;
|
||||
using DestType = typename decltype (dest) ::PointerType;
|
||||
|
||||
for (int i = 0; i < dest.channels; ++i)
|
||||
{
|
||||
if (auto* targetChan = dest.data[i])
|
||||
{
|
||||
const DestType destType (targetChan);
|
||||
|
||||
if (i < source.channels)
|
||||
destType.convertSamples (SourceType (addBytesToPointer (source.data, i * SourceType::getBytesPerSample()), source.channels), numSamples);
|
||||
else
|
||||
destType.clearSamples (numSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/**
|
||||
A set of routines to convert buffers of 32-bit floating point data to and from
|
||||
various integer formats.
|
||||
|
||||
Note that these functions are deprecated - the AudioData class provides a much more
|
||||
flexible set of conversion classes now.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class [[deprecated]] JUCE_API AudioDataConverters
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2);
|
||||
static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2);
|
||||
|
||||
static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3);
|
||||
static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3);
|
||||
|
||||
static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4);
|
||||
static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4);
|
||||
|
||||
static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4);
|
||||
static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4);
|
||||
|
||||
//==============================================================================
|
||||
static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2);
|
||||
static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2);
|
||||
|
||||
static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3);
|
||||
static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3);
|
||||
|
||||
static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4);
|
||||
static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4);
|
||||
|
||||
static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4);
|
||||
static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4);
|
||||
|
||||
//==============================================================================
|
||||
enum DataFormat
|
||||
{
|
||||
int16LE,
|
||||
int16BE,
|
||||
int24LE,
|
||||
int24BE,
|
||||
int32LE,
|
||||
int32BE,
|
||||
float32LE,
|
||||
float32BE,
|
||||
};
|
||||
|
||||
static void convertFloatToFormat (DataFormat destFormat,
|
||||
const float* source, void* dest, int numSamples);
|
||||
|
||||
static void convertFormatToFloat (DataFormat sourceFormat,
|
||||
const void* source, float* dest, int numSamples);
|
||||
|
||||
//==============================================================================
|
||||
static void interleaveSamples (const float** source, float* dest,
|
||||
int numSamples, int numChannels);
|
||||
|
||||
static void deinterleaveSamples (const float* source, float** dest,
|
||||
int numSamples, int numChannels);
|
||||
|
||||
private:
|
||||
AudioDataConverters();
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
AudioProcessLoadMeasurer::AudioProcessLoadMeasurer() = default;
|
||||
AudioProcessLoadMeasurer::~AudioProcessLoadMeasurer() = default;
|
||||
|
||||
void AudioProcessLoadMeasurer::reset()
|
||||
{
|
||||
reset (0, 0);
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::reset (double sampleRate, int blockSize)
|
||||
{
|
||||
const SpinLock::ScopedLockType lock (mutex);
|
||||
|
||||
cpuUsageProportion = 0;
|
||||
xruns = 0;
|
||||
|
||||
samplesPerBlock = blockSize;
|
||||
msPerSample = (sampleRate > 0.0 && blockSize > 0) ? 1000.0 / sampleRate : 0;
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::registerBlockRenderTime (double milliseconds)
|
||||
{
|
||||
const SpinLock::ScopedTryLockType lock (mutex);
|
||||
|
||||
if (lock.isLocked())
|
||||
registerRenderTimeLocked (milliseconds, samplesPerBlock);
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::registerRenderTime (double milliseconds, int numSamples)
|
||||
{
|
||||
const SpinLock::ScopedTryLockType lock (mutex);
|
||||
|
||||
if (lock.isLocked())
|
||||
registerRenderTimeLocked (milliseconds, numSamples);
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::registerRenderTimeLocked (double milliseconds, int numSamples)
|
||||
{
|
||||
if (approximatelyEqual (msPerSample, 0.0))
|
||||
return;
|
||||
|
||||
const auto maxMilliseconds = numSamples * msPerSample;
|
||||
const auto usedProportion = milliseconds / maxMilliseconds;
|
||||
const auto filterAmount = 0.2;
|
||||
const auto proportion = cpuUsageProportion.load();
|
||||
cpuUsageProportion = proportion + filterAmount * (usedProportion - proportion);
|
||||
|
||||
if (milliseconds > maxMilliseconds)
|
||||
++xruns;
|
||||
}
|
||||
|
||||
double AudioProcessLoadMeasurer::getLoadAsProportion() const { return jlimit (0.0, 1.0, cpuUsageProportion.load()); }
|
||||
double AudioProcessLoadMeasurer::getLoadAsPercentage() const { return 100.0 * getLoadAsProportion(); }
|
||||
|
||||
int AudioProcessLoadMeasurer::getXRunCount() const { return xruns; }
|
||||
|
||||
AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p)
|
||||
: ScopedTimer (p, p.samplesPerBlock)
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p, int numSamplesInBlock)
|
||||
: owner (p), startTime (Time::getMillisecondCounterHiRes()), samplesInBlock (numSamplesInBlock)
|
||||
{
|
||||
// numSamplesInBlock should never be zero. Did you remember to call AudioProcessLoadMeasurer::reset(),
|
||||
// passing the expected samples per block?
|
||||
jassert (numSamplesInBlock);
|
||||
}
|
||||
|
||||
AudioProcessLoadMeasurer::ScopedTimer::~ScopedTimer()
|
||||
{
|
||||
owner.registerRenderTime (Time::getMillisecondCounterHiRes() - startTime, samplesInBlock);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Maintains an ongoing measurement of the proportion of time which is being
|
||||
spent inside an audio callback.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessLoadMeasurer
|
||||
{
|
||||
public:
|
||||
/** */
|
||||
AudioProcessLoadMeasurer();
|
||||
|
||||
/** Destructor. */
|
||||
~AudioProcessLoadMeasurer();
|
||||
|
||||
//==============================================================================
|
||||
/** Resets the state. */
|
||||
void reset();
|
||||
|
||||
/** Resets the counter, in preparation for use with the given sample rate and block size. */
|
||||
void reset (double sampleRate, int blockSize);
|
||||
|
||||
/** Returns the current load as a proportion 0 to 1.0 */
|
||||
double getLoadAsProportion() const;
|
||||
|
||||
/** Returns the current load as a percentage 0 to 100.0 */
|
||||
double getLoadAsPercentage() const;
|
||||
|
||||
/** Returns the number of over- (or under-) runs recorded since the state was reset. */
|
||||
int getXRunCount() const;
|
||||
|
||||
//==============================================================================
|
||||
/** This class measures the time between its construction and destruction and
|
||||
adds it to an AudioProcessLoadMeasurer.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
{
|
||||
AudioProcessLoadMeasurer::ScopedTimer timer (myProcessLoadMeasurer);
|
||||
myCallback->doTheCallback();
|
||||
}
|
||||
@endcode
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct JUCE_API ScopedTimer
|
||||
{
|
||||
ScopedTimer (AudioProcessLoadMeasurer&);
|
||||
ScopedTimer (AudioProcessLoadMeasurer&, int numSamplesInBlock);
|
||||
~ScopedTimer();
|
||||
|
||||
private:
|
||||
AudioProcessLoadMeasurer& owner;
|
||||
double startTime;
|
||||
int samplesInBlock;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ScopedTimer)
|
||||
};
|
||||
|
||||
/** Can be called manually to add the time of a callback to the stats.
|
||||
Normally you probably would never call this - it's simpler and more robust to
|
||||
use a ScopedTimer to measure the time using an RAII pattern.
|
||||
*/
|
||||
void registerBlockRenderTime (double millisecondsTaken);
|
||||
|
||||
/** Can be called manually to add the time of a callback to the stats.
|
||||
Normally you probably would never call this - it's simpler and more robust to
|
||||
use a ScopedTimer to measure the time using an RAII pattern.
|
||||
*/
|
||||
void registerRenderTime (double millisecondsTaken, int numSamples);
|
||||
|
||||
private:
|
||||
void registerRenderTimeLocked (double, int);
|
||||
|
||||
SpinLock mutex;
|
||||
int samplesPerBlock = 0;
|
||||
double msPerSample = 0;
|
||||
std::atomic<double> cpuUsageProportion { 0 };
|
||||
std::atomic<int> xruns { 0 };
|
||||
};
|
||||
|
||||
|
||||
} // namespace juce
|
||||
+1320
File diff suppressed because it is too large
Load Diff
+1716
File diff suppressed because it is too large
Load Diff
+230
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#ifndef JUCE_SNAP_TO_ZERO
|
||||
#if JUCE_INTEL
|
||||
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0;
|
||||
#else
|
||||
#define JUCE_SNAP_TO_ZERO(n) ignoreUnused (n)
|
||||
#endif
|
||||
#endif
|
||||
class ScopedNoDenormals;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A collection of simple vector operations on arrays of floating point numbers,
|
||||
accelerated with SIMD instructions where possible, usually accessed from
|
||||
the FloatVectorOperations class.
|
||||
|
||||
@code
|
||||
float data[64];
|
||||
|
||||
// The following two function calls are equivalent:
|
||||
FloatVectorOperationsBase<float, int>::clear (data, 64);
|
||||
FloatVectorOperations::clear (data, 64);
|
||||
@endcode
|
||||
|
||||
@see FloatVectorOperations
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
template <typename FloatType, typename CountType>
|
||||
struct FloatVectorOperationsBase
|
||||
{
|
||||
/** Clears a vector of floating point numbers. */
|
||||
static void JUCE_CALLTYPE clear (FloatType* dest, CountType numValues) noexcept;
|
||||
|
||||
/** Copies a repeated value into a vector of floating point numbers. */
|
||||
static void JUCE_CALLTYPE fill (FloatType* dest, FloatType valueToFill, CountType numValues) noexcept;
|
||||
|
||||
/** Copies a vector of floating point numbers. */
|
||||
static void JUCE_CALLTYPE copy (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Copies a vector of floating point numbers, multiplying each value by a given multiplier */
|
||||
static void JUCE_CALLTYPE copyWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to the destination values. */
|
||||
static void JUCE_CALLTYPE add (FloatType* dest, FloatType amountToAdd, CountType numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to each source value and stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src, FloatType amount, CountType numValues) noexcept;
|
||||
|
||||
/** Adds the source values to the destination values. */
|
||||
static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE add (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Subtracts the source values from the destination values. */
|
||||
static void JUCE_CALLTYPE subtract (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE subtract (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Multiplies the destination values by the source values. */
|
||||
static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the destination values by a fixed multiplier. */
|
||||
static void JUCE_CALLTYPE multiply (FloatType* dest, FloatType multiplier, CountType numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src, FloatType multiplier, CountType num) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, negating each value. */
|
||||
static void JUCE_CALLTYPE negate (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, taking the absolute of each value. */
|
||||
static void JUCE_CALLTYPE abs (FloatType* dest, const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Each element of dest will be the minimum of the corresponding element of the source array and the given comp value. */
|
||||
static void JUCE_CALLTYPE min (FloatType* dest, const FloatType* src, FloatType comp, CountType num) noexcept;
|
||||
|
||||
/** Each element of dest will be the minimum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE min (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Each element of dest will be the maximum of the corresponding element of the source array and the given comp value. */
|
||||
static void JUCE_CALLTYPE max (FloatType* dest, const FloatType* src, FloatType comp, CountType num) noexcept;
|
||||
|
||||
/** Each element of dest will be the maximum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE max (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType num) noexcept;
|
||||
|
||||
/** Each element of dest is calculated by hard clipping the corresponding src element so that it is in the range specified by the arguments low and high. */
|
||||
static void JUCE_CALLTYPE clip (FloatType* dest, const FloatType* src, FloatType low, FloatType high, CountType num) noexcept;
|
||||
|
||||
/** Finds the minimum and maximum values in the given array. */
|
||||
static Range<FloatType> JUCE_CALLTYPE findMinAndMax (const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Finds the minimum value in the given array. */
|
||||
static FloatType JUCE_CALLTYPE findMinimum (const FloatType* src, CountType numValues) noexcept;
|
||||
|
||||
/** Finds the maximum value in the given array. */
|
||||
static FloatType JUCE_CALLTYPE findMaximum (const FloatType* src, CountType numValues) noexcept;
|
||||
};
|
||||
|
||||
#if ! DOXYGEN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename... Bases>
|
||||
struct NameForwarder : public Bases...
|
||||
{
|
||||
using Bases::clear...,
|
||||
Bases::fill...,
|
||||
Bases::copy...,
|
||||
Bases::copyWithMultiply...,
|
||||
Bases::add...,
|
||||
Bases::subtract...,
|
||||
Bases::addWithMultiply...,
|
||||
Bases::subtractWithMultiply...,
|
||||
Bases::multiply...,
|
||||
Bases::negate...,
|
||||
Bases::abs...,
|
||||
Bases::min...,
|
||||
Bases::max...,
|
||||
Bases::clip...,
|
||||
Bases::findMinAndMax...,
|
||||
Bases::findMinimum...,
|
||||
Bases::findMaximum...;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A collection of simple vector operations on arrays of floating point numbers,
|
||||
accelerated with SIMD instructions where possible and providing all methods
|
||||
from FloatVectorOperationsBase.
|
||||
|
||||
@see FloatVectorOperationsBase
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API FloatVectorOperations : public detail::NameForwarder<FloatVectorOperationsBase<float, int>,
|
||||
FloatVectorOperationsBase<float, size_t>,
|
||||
FloatVectorOperationsBase<double, int>,
|
||||
FloatVectorOperationsBase<double, size_t>>
|
||||
{
|
||||
public:
|
||||
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept;
|
||||
|
||||
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, size_t num) noexcept;
|
||||
|
||||
/** This method enables or disables the SSE/NEON flush-to-zero mode. */
|
||||
static void JUCE_CALLTYPE enableFlushToZeroMode (bool shouldEnable) noexcept;
|
||||
|
||||
/** On Intel CPUs, this method enables the SSE flush-to-zero and denormalised-are-zero modes.
|
||||
This effectively sets the DAZ and FZ bits of the MXCSR register. On arm CPUs this will
|
||||
enable flush to zero mode.
|
||||
It's a convenient thing to call before audio processing code where you really want to
|
||||
avoid denormalisation performance hits.
|
||||
*/
|
||||
static void JUCE_CALLTYPE disableDenormalisedNumberSupport (bool shouldDisable = true) noexcept;
|
||||
|
||||
/** This method returns true if denormals are currently disabled. */
|
||||
static bool JUCE_CALLTYPE areDenormalsDisabled() noexcept;
|
||||
|
||||
private:
|
||||
friend ScopedNoDenormals;
|
||||
|
||||
static intptr_t JUCE_CALLTYPE getFpStatusRegister() noexcept;
|
||||
static void JUCE_CALLTYPE setFpStatusRegister (intptr_t) noexcept;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helper class providing an RAII-based mechanism for temporarily disabling
|
||||
denormals on your CPU.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ScopedNoDenormals
|
||||
{
|
||||
public:
|
||||
ScopedNoDenormals() noexcept;
|
||||
~ScopedNoDenormals() noexcept;
|
||||
|
||||
private:
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
intptr_t fpsr;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Reference in New Issue
Block a user