git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
725
deps/juce/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp
vendored
Normal file
725
deps/juce/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp
vendored
Normal file
@ -0,0 +1,725 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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 Array<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 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 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;
|
||||
}
|
||||
|
||||
if (type >= ambisonicACN4 && type <= ambisonicACN35)
|
||||
return "ACN" + String (type - ambisonicACN4 + 4);
|
||||
|
||||
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 == "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 == create5point1()) return "5.1 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 == create7point1point2()) return "7.1.2 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
|
||||
{
|
||||
for (auto& speaker : getChannelTypes())
|
||||
if (speaker <= ambisonicACN35)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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 (1u << centre); }
|
||||
AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ((1u << left) | (1u << right)); }
|
||||
AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre)); }
|
||||
AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << surround)); }
|
||||
AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << surround)); }
|
||||
AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround)); }
|
||||
AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround)); }
|
||||
AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
|
||||
AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
|
||||
AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
|
||||
AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
|
||||
AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
|
||||
AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
|
||||
AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
|
||||
AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
|
||||
AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround)); }
|
||||
AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
|
||||
AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
|
||||
AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround) | (1u << wideLeft) | (1u << wideRight)); }
|
||||
AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
|
||||
AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
|
||||
AudioChannelSet AudioChannelSet::create7point0point4() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topFrontLeft) | (1u << topFrontRight) | (1u << topRearLeft) | (1u << topRearRight)); }
|
||||
AudioChannelSet AudioChannelSet::create7point1point4() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topFrontLeft) | (1u << topFrontRight) | (1u << topRearLeft) | (1u << topRearRight)); }
|
||||
|
||||
AudioChannelSet AudioChannelSet::ambisonic (int order)
|
||||
{
|
||||
jassert (isPositiveAndBelow (order, 6));
|
||||
|
||||
if (order == 0)
|
||||
return AudioChannelSet ((uint32) (1 << ambisonicACN0));
|
||||
|
||||
AudioChannelSet set ((1u << ambisonicACN0) | (1u << ambisonicACN1) | (1u << ambisonicACN2) | (1u << ambisonicACN3));
|
||||
|
||||
auto numAmbisonicChannels = (order + 1) * (order + 1);
|
||||
set.channels.setRange (ambisonicACN4, numAmbisonicChannels - 4, true);
|
||||
|
||||
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));
|
||||
|
||||
if (numChannels == 1)
|
||||
{
|
||||
retval.add (AudioChannelSet::mono());
|
||||
}
|
||||
else if (numChannels == 2)
|
||||
{
|
||||
retval.add (AudioChannelSet::stereo());
|
||||
}
|
||||
else if (numChannels == 3)
|
||||
{
|
||||
retval.add (AudioChannelSet::createLCR());
|
||||
retval.add (AudioChannelSet::createLRS());
|
||||
}
|
||||
else if (numChannels == 4)
|
||||
{
|
||||
retval.add (AudioChannelSet::quadraphonic());
|
||||
retval.add (AudioChannelSet::createLCRS());
|
||||
}
|
||||
else if (numChannels == 5)
|
||||
{
|
||||
retval.add (AudioChannelSet::create5point0());
|
||||
retval.add (AudioChannelSet::pentagonal());
|
||||
}
|
||||
else if (numChannels == 6)
|
||||
{
|
||||
retval.add (AudioChannelSet::create5point1());
|
||||
retval.add (AudioChannelSet::create6point0());
|
||||
retval.add (AudioChannelSet::create6point0Music());
|
||||
retval.add (AudioChannelSet::hexagonal());
|
||||
}
|
||||
else if (numChannels == 7)
|
||||
{
|
||||
retval.add (AudioChannelSet::create7point0());
|
||||
retval.add (AudioChannelSet::create7point0SDDS());
|
||||
retval.add (AudioChannelSet::create6point1());
|
||||
retval.add (AudioChannelSet::create6point1Music());
|
||||
}
|
||||
else if (numChannels == 8)
|
||||
{
|
||||
retval.add (AudioChannelSet::create7point1());
|
||||
retval.add (AudioChannelSet::create7point1SDDS());
|
||||
retval.add (AudioChannelSet::octagonal());
|
||||
}
|
||||
|
||||
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 JUCE_CALLTYPE AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels)
|
||||
{
|
||||
auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f;
|
||||
auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne)));
|
||||
|
||||
if (ambisonicOrder > 5)
|
||||
return -1;
|
||||
|
||||
return (static_cast<float> (ambisonicOrder) == sqrtMinusOne ? ambisonicOrder : -1);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class AudioChannelSetUnitTest : 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
|
496
deps/juce/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
vendored
Normal file
496
deps/juce/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
vendored
Normal file
@ -0,0 +1,496 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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 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), n/a (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), n/a (CoreAudio)
|
||||
*/
|
||||
static AudioChannelSet JUCE_CALLTYPE create7point1point4();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** 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) channel for Dolby Atmos. */
|
||||
topSideRight = 29, /**< Rts (AAX), Tsr (VST) 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) */
|
||||
|
||||
//==============================================================================
|
||||
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 = 36
|
||||
};
|
||||
|
||||
/** 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;
|
||||
|
||||
//==============================================================================
|
||||
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 Array<ChannelType>&);
|
||||
|
||||
//==============================================================================
|
||||
static int JUCE_CALLTYPE getAmbisonicOrderForNumChannels (int);
|
||||
};
|
||||
|
||||
} // namespace juce
|
604
deps/juce/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp
vendored
Normal file
604
deps/juce/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp
vendored
Normal file
@ -0,0 +1,604 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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)
|
||||
{
|
||||
for (int chan = 0; chan < numChannels; ++chan)
|
||||
{
|
||||
auto i = chan;
|
||||
auto src = source [chan];
|
||||
|
||||
for (int j = 0; j < numSamples; ++j)
|
||||
{
|
||||
dest [i] = src [j];
|
||||
i += numChannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
|
||||
{
|
||||
for (int chan = 0; chan < numChannels; ++chan)
|
||||
{
|
||||
auto i = chan;
|
||||
auto dst = dest [chan];
|
||||
|
||||
for (int j = 0; j < numSamples; ++j)
|
||||
{
|
||||
dst [j] = source [i];
|
||||
i += numChannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class AudioConversionTests : 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);
|
||||
}
|
||||
};
|
||||
|
||||
static AudioConversionTests audioConversionUnitTests;
|
||||
|
||||
#endif
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
719
deps/juce/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h
vendored
Normal file
719
deps/juce/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h
vendored
Normal file
@ -0,0 +1,719 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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 (const 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; }
|
||||
|
||||
/** 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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#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
|
87
deps/juce/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp
vendored
Normal file
87
deps/juce/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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)
|
||||
{
|
||||
cpuUsageProportion = 0;
|
||||
xruns = 0;
|
||||
|
||||
if (sampleRate > 0.0 && blockSize > 0)
|
||||
{
|
||||
msPerSample = 1000.0 / sampleRate;
|
||||
timeToCpuScale = (msPerSample > 0.0) ? (1.0 / msPerSample) : 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
msPerSample = 0;
|
||||
timeToCpuScale = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::registerBlockRenderTime (double milliseconds)
|
||||
{
|
||||
registerRenderTime (milliseconds, samplesPerBlock);
|
||||
}
|
||||
|
||||
void AudioProcessLoadMeasurer::registerRenderTime (double milliseconds, int numSamples)
|
||||
{
|
||||
const auto maxMilliseconds = numSamples * msPerSample;
|
||||
const auto usedProportion = milliseconds / maxMilliseconds;
|
||||
const auto filterAmount = 0.2;
|
||||
cpuUsageProportion += filterAmount * (usedProportion - cpuUsageProportion);
|
||||
|
||||
if (milliseconds > maxMilliseconds)
|
||||
++xruns;
|
||||
}
|
||||
|
||||
double AudioProcessLoadMeasurer::getLoadAsProportion() const { return jlimit (0.0, 1.0, cpuUsageProportion); }
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessLoadMeasurer::ScopedTimer::~ScopedTimer()
|
||||
{
|
||||
owner.registerRenderTime (Time::getMillisecondCounterHiRes() - startTime, samplesInBlock);
|
||||
}
|
||||
|
||||
} // namespace juce
|
104
deps/juce/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h
vendored
Normal file
104
deps/juce/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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:
|
||||
double cpuUsageProportion = 0, timeToCpuScale = 0, msPerSample = 0;
|
||||
int xruns = 0, samplesPerBlock = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace juce
|
1296
deps/juce/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
vendored
Normal file
1296
deps/juce/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1305
deps/juce/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
vendored
Normal file
1305
deps/juce/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
257
deps/juce/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
vendored
Normal file
257
deps/juce/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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 floats, accelerated with
|
||||
SIMD instructions where possible.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API FloatVectorOperations
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Clears a vector of floats. */
|
||||
static void JUCE_CALLTYPE clear (float* dest, int numValues) noexcept;
|
||||
|
||||
/** Clears a vector of doubles. */
|
||||
static void JUCE_CALLTYPE clear (double* dest, int numValues) noexcept;
|
||||
|
||||
/** Copies a repeated value into a vector of floats. */
|
||||
static void JUCE_CALLTYPE fill (float* dest, float valueToFill, int numValues) noexcept;
|
||||
|
||||
/** Copies a repeated value into a vector of doubles. */
|
||||
static void JUCE_CALLTYPE fill (double* dest, double valueToFill, int numValues) noexcept;
|
||||
|
||||
/** Copies a vector of floats. */
|
||||
static void JUCE_CALLTYPE copy (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Copies a vector of doubles. */
|
||||
static void JUCE_CALLTYPE copy (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Copies a vector of floats, multiplying each value by a given multiplier */
|
||||
static void JUCE_CALLTYPE copyWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
|
||||
|
||||
/** Copies a vector of doubles, multiplying each value by a given multiplier */
|
||||
static void JUCE_CALLTYPE copyWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to the destination values. */
|
||||
static void JUCE_CALLTYPE add (float* dest, float amountToAdd, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to the destination values. */
|
||||
static void JUCE_CALLTYPE add (double* dest, double amountToAdd, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to each source value and stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE add (float* dest, const float* src, float amount, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to each source value and stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE add (double* dest, const double* src, double amount, int numValues) noexcept;
|
||||
|
||||
/** Adds the source values to the destination values. */
|
||||
static void JUCE_CALLTYPE add (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Adds the source values to the destination values. */
|
||||
static void JUCE_CALLTYPE add (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE add (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE add (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Subtracts the source values from the destination values. */
|
||||
static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Subtracts the source values from the destination values. */
|
||||
static void JUCE_CALLTYPE subtract (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE subtract (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE subtract (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the corresponding source2 value, then subtracts it to the destination value. */
|
||||
static void JUCE_CALLTYPE subtractWithMultiply (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies the destination values by the source values. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Multiplies the destination values by the source values. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, const float* src1, const float* src2, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src1, const double* src2, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the destination values by a fixed multiplier. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, float multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the destination values by a fixed multiplier. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, double multiplier, int 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 (float* dest, const float* src, float multiplier, int num) noexcept;
|
||||
|
||||
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src, double multiplier, int num) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, negating each value. */
|
||||
static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, negating each value. */
|
||||
static void JUCE_CALLTYPE negate (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, taking the absolute of each value. */
|
||||
static void JUCE_CALLTYPE abs (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, taking the absolute of each value. */
|
||||
static void JUCE_CALLTYPE abs (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Converts a stream of integers to floats, multiplying each one by the given multiplier. */
|
||||
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int 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 (float* dest, const float* src, float comp, int num) 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 (double* dest, const double* src, double comp, int num) noexcept;
|
||||
|
||||
/** Each element of dest will be the minimum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE min (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Each element of dest will be the minimum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE min (double* dest, const double* src1, const double* src2, int 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 (float* dest, const float* src, float comp, int 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 (double* dest, const double* src, double comp, int num) noexcept;
|
||||
|
||||
/** Each element of dest will be the maximum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE max (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Each element of dest will be the maximum of the corresponding source1 and source2 values. */
|
||||
static void JUCE_CALLTYPE max (double* dest, const double* src1, const double* src2, int 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 (float* dest, const float* src, float low, float high, int 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 (double* dest, const double* src, double low, double high, int num) noexcept;
|
||||
|
||||
/** Finds the minimum and maximum values in the given array. */
|
||||
static Range<float> JUCE_CALLTYPE findMinAndMax (const float* src, int numValues) noexcept;
|
||||
|
||||
/** Finds the minimum and maximum values in the given array. */
|
||||
static Range<double> JUCE_CALLTYPE findMinAndMax (const double* src, int numValues) noexcept;
|
||||
|
||||
/** Finds the minimum value in the given array. */
|
||||
static float JUCE_CALLTYPE findMinimum (const float* src, int numValues) noexcept;
|
||||
|
||||
/** Finds the minimum value in the given array. */
|
||||
static double JUCE_CALLTYPE findMinimum (const double* src, int numValues) noexcept;
|
||||
|
||||
/** Finds the maximum value in the given array. */
|
||||
static float JUCE_CALLTYPE findMaximum (const float* src, int numValues) noexcept;
|
||||
|
||||
/** Finds the maximum value in the given array. */
|
||||
static double JUCE_CALLTYPE findMaximum (const double* src, int numValues) 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 || defined (__arm64__) || defined (__aarch64__))
|
||||
intptr_t fpsr;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user