@@ -463,6 +463,8 @@ AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet | |||
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) | |||
{ | |||
@@ -208,6 +208,18 @@ public: | |||
*/ | |||
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) | |||
@@ -44,13 +44,20 @@ void MemoryAudioSource::releaseResources() {} | |||
void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) | |||
{ | |||
if (buffer.getNumSamples() == 0) | |||
{ | |||
bufferToFill.clearActiveBufferRegion(); | |||
return; | |||
} | |||
auto& dst = *bufferToFill.buffer; | |||
auto channels = jmin (dst.getNumChannels(), buffer.getNumChannels()); | |||
auto max = 0, pos = 0; | |||
auto n = buffer.getNumSamples(), m = bufferToFill.numSamples; | |||
int max = 0, pos = 0; | |||
auto n = buffer.getNumSamples(); | |||
auto m = bufferToFill.numSamples; | |||
int i; | |||
for (i = position; (i < n || isCurrentlyLooping) && (pos < m); i += max) | |||
int i = position; | |||
for (; (i < n || isCurrentlyLooping) && (pos < m); i += max) | |||
{ | |||
max = jmin (m - pos, n - (i % n)); | |||
@@ -67,7 +74,7 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT | |||
if (pos < m) | |||
dst.clear (bufferToFill.startSample + pos, m - pos); | |||
position = (i % n); | |||
position = i; | |||
} | |||
//============================================================================== | |||
@@ -97,4 +104,158 @@ void MemoryAudioSource::setLooping (bool shouldLoop) | |||
isCurrentlyLooping = shouldLoop; | |||
} | |||
//============================================================================== | |||
//============================================================================== | |||
#if JUCE_UNIT_TESTS | |||
static bool operator== (const AudioBuffer<float>& a, const AudioBuffer<float>& b) | |||
{ | |||
if (a.getNumChannels() != b.getNumChannels()) | |||
return false; | |||
for (int channel = 0; channel < a.getNumChannels(); ++channel) | |||
{ | |||
auto* aPtr = a.getReadPointer (channel); | |||
auto* bPtr = b.getReadPointer (channel); | |||
if (std::vector<float> (aPtr, aPtr + a.getNumSamples()) | |||
!= std::vector<float> (bPtr, bPtr + b.getNumSamples())) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
struct MemoryAudioSourceTests : public UnitTest | |||
{ | |||
MemoryAudioSourceTests() : UnitTest ("MemoryAudioSource", UnitTestCategories::audio) {} | |||
void runTest() override | |||
{ | |||
constexpr int blockSize = 512; | |||
AudioBuffer<float> bufferToFill { 2, blockSize }; | |||
AudioSourceChannelInfo channelInfo { bufferToFill }; | |||
beginTest ("A zero-length buffer produces silence, whether or not looping is enabled"); | |||
{ | |||
for (const bool enableLooping : { false, true }) | |||
{ | |||
AudioBuffer<float> buffer; | |||
MemoryAudioSource source { buffer, true, false }; | |||
source.setLooping (enableLooping); | |||
source.prepareToPlay (blockSize, 44100.0); | |||
for (int i = 0; i < 2; ++i) | |||
{ | |||
play (source, channelInfo); | |||
expect (isSilent (bufferToFill)); | |||
} | |||
} | |||
} | |||
beginTest ("A short buffer without looping is played once and followed by silence"); | |||
{ | |||
auto buffer = getShortBuffer(); | |||
MemoryAudioSource source { buffer, true, false }; | |||
source.setLooping (false); | |||
source.prepareToPlay (blockSize, 44100.0); | |||
play (source, channelInfo); | |||
auto copy = buffer; | |||
copy.setSize (buffer.getNumChannels(), blockSize, true, true, false); | |||
expect (bufferToFill == copy); | |||
play (source, channelInfo); | |||
expect (isSilent (bufferToFill)); | |||
} | |||
beginTest ("A short buffer with looping is played multiple times"); | |||
{ | |||
auto buffer = getShortBuffer(); | |||
MemoryAudioSource source { buffer, true, false }; | |||
source.setLooping (true); | |||
source.prepareToPlay (blockSize, 44100.0); | |||
play (source, channelInfo); | |||
for (int sample = 0; sample < buffer.getNumSamples(); ++sample) | |||
expect (bufferToFill.getSample (0, sample + buffer.getNumSamples()) == buffer.getSample (0, sample)); | |||
expect (! isSilent (bufferToFill)); | |||
} | |||
beginTest ("A long buffer without looping is played once"); | |||
{ | |||
auto buffer = getLongBuffer(); | |||
MemoryAudioSource source { buffer, true, false }; | |||
source.setLooping (false); | |||
source.prepareToPlay (blockSize, 44100.0); | |||
play (source, channelInfo); | |||
auto copy = buffer; | |||
copy.setSize (buffer.getNumChannels(), blockSize, true, true, false); | |||
expect (bufferToFill == copy); | |||
for (int i = 0; i < 10; ++i) | |||
play (source, channelInfo); | |||
expect (isSilent (bufferToFill)); | |||
} | |||
beginTest ("A long buffer with looping is played multiple times"); | |||
{ | |||
auto buffer = getLongBuffer(); | |||
MemoryAudioSource source { buffer, true, false }; | |||
source.setLooping (true); | |||
source.prepareToPlay (blockSize, 44100.0); | |||
for (int i = 0; i < 100; ++i) | |||
{ | |||
play (source, channelInfo); | |||
expect (bufferToFill.getSample (0, 0) == buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); | |||
} | |||
} | |||
} | |||
static AudioBuffer<float> getTestBuffer (int length) | |||
{ | |||
AudioBuffer<float> buffer { 2, length }; | |||
for (int channel = 0; channel < buffer.getNumChannels(); ++channel) | |||
for (int sample = 0; sample < buffer.getNumSamples(); ++sample) | |||
buffer.setSample (channel, sample, jmap ((float) sample, 0.0f, (float) length, -1.0f, 1.0f)); | |||
return buffer; | |||
} | |||
static AudioBuffer<float> getShortBuffer() { return getTestBuffer (5); } | |||
static AudioBuffer<float> getLongBuffer() { return getTestBuffer (1000); } | |||
static void play (MemoryAudioSource& source, AudioSourceChannelInfo& info) | |||
{ | |||
info.clearActiveBufferRegion(); | |||
source.getNextAudioBlock (info); | |||
} | |||
static bool isSilent (const AudioBuffer<float>& b) | |||
{ | |||
for (int channel = 0; channel < b.getNumChannels(); ++channel) | |||
if (b.findMinMax (channel, 0, b.getNumSamples()) != Range<float>{}) | |||
return false; | |||
return true; | |||
} | |||
}; | |||
static MemoryAudioSourceTests memoryAudioSourceTests; | |||
#endif | |||
} // namespace juce |
@@ -675,6 +675,19 @@ public: | |||
return noErr; | |||
} | |||
#if defined (MAC_OS_X_VERSION_10_12) | |||
case kAudioUnitProperty_AUHostIdentifier: | |||
{ | |||
if (inDataSize < sizeof (AUHostVersionIdentifier)) | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
const auto* identifier = static_cast<const AUHostVersionIdentifier*> (inData); | |||
PluginHostType::hostIdReportedByWrapper = String::fromCFString (identifier->hostName); | |||
return noErr; | |||
} | |||
#endif | |||
default: break; | |||
} | |||
} | |||
@@ -612,6 +612,10 @@ public: | |||
{ | |||
centreWithSize (getWidth(), getHeight()); | |||
} | |||
if (auto* processor = getAudioProcessor()) | |||
if (auto* editor = processor->getActiveEditor()) | |||
setResizable (editor->isResizable(), false); | |||
#endif | |||
} | |||
@@ -927,11 +927,13 @@ public: | |||
{ | |||
if (auto* pluginInstance = getPluginInstance()) | |||
{ | |||
if (pluginInstance->hasEditor() && name != nullptr | |||
&& strcmp (name, Vst::ViewType::kEditor) == 0) | |||
{ | |||
const auto mayCreateEditor = pluginInstance->hasEditor() | |||
&& name != nullptr | |||
&& std::strcmp (name, Vst::ViewType::kEditor) == 0 | |||
&& pluginInstance->getActiveEditor() == nullptr; | |||
if (mayCreateEditor) | |||
return new JuceVST3Editor (*this, *pluginInstance); | |||
} | |||
} | |||
return nullptr; | |||
@@ -126,6 +126,5 @@ | |||
#define JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE (JUCE_IOS || JUCE_ANDROID) | |||
#endif | |||
#include "utility/juce_PluginHostType.h" | |||
#include "utility/juce_CreatePluginFilter.h" | |||
#include "VST/juce_VSTCallbackHandler.h" |
@@ -1,439 +0,0 @@ | |||
/* | |||
============================================================================== | |||
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. | |||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||
End User License Agreement: www.juce.com/juce-6-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
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 | |||
{ | |||
//============================================================================== | |||
/** | |||
A useful utility class to determine the host or DAW in which your plugin is | |||
loaded. | |||
Declare a PluginHostType object in your class to use it. | |||
@tags{Audio} | |||
*/ | |||
class PluginHostType | |||
{ | |||
public: | |||
//============================================================================== | |||
PluginHostType() : type (getHostType()) {} | |||
PluginHostType (const PluginHostType& other) = default; | |||
PluginHostType& operator= (const PluginHostType& other) = default; | |||
//============================================================================== | |||
/** Represents the host type and also its version for some hosts. */ | |||
enum HostType | |||
{ | |||
UnknownHost, /**< Represents an unknown host. */ | |||
AbletonLive6, /**< Represents Ableton Live 6. */ | |||
AbletonLive7, /**< Represents Ableton Live 7. */ | |||
AbletonLive8, /**< Represents Ableton Live 8. */ | |||
AbletonLive9, /**< Represents Ableton Live 9. */ | |||
AbletonLive10, /**< Represents Ableton Live 10. */ | |||
AbletonLiveGeneric, /**< Represents Ableton Live. */ | |||
AdobeAudition, /**< Represents Adobe Audition. */ | |||
AdobePremierePro, /**< Represents Adobe Premiere Pro. */ | |||
AppleGarageBand, /**< Represents Apple GarageBand. */ | |||
AppleLogic, /**< Represents Apple Logic Pro. */ | |||
AppleMainStage, /**< Represents Apple Main Stage. */ | |||
Ardour, /**< Represents Ardour. */ | |||
AvidProTools, /**< Represents Avid Pro Tools. */ | |||
BitwigStudio, /**< Represents Bitwig Studio. */ | |||
CakewalkSonar8, /**< Represents Cakewalk Sonar 8. */ | |||
CakewalkSonarGeneric, /**< Represents Cakewalk Sonar. */ | |||
CakewalkByBandlab, /**< Represents Cakewalk by Bandlab. */ | |||
DaVinciResolve, /**< Represents DaVinci Resolve. */ | |||
DigitalPerformer, /**< Represents Digital Performer. */ | |||
FinalCut, /**< Represents Apple Final Cut Pro. */ | |||
FruityLoops, /**< Represents Fruity Loops. */ | |||
JUCEPluginHost, /**< Represents the JUCE AudioPluginHost */ | |||
MagixSamplitude, /**< Represents Magix Samplitude. */ | |||
MagixSequoia, /**< Represents Magix Sequoia. */ | |||
MergingPyramix, /**< Represents Merging Pyramix. */ | |||
MuseReceptorGeneric, /**< Represents Muse Receptor. */ | |||
pluginval, /**< Represents pluginval. */ | |||
Reaper, /**< Represents Cockos Reaper. */ | |||
Reason, /**< Represents Reason. */ | |||
Renoise, /**< Represents Renoise. */ | |||
SADiE, /**< Represents SADiE. */ | |||
SteinbergCubase4, /**< Represents Steinberg Cubase 4. */ | |||
SteinbergCubase5, /**< Represents Steinberg Cubase 5. */ | |||
SteinbergCubase5Bridged, /**< Represents Steinberg Cubase 5 Bridged. */ | |||
SteinbergCubase6, /**< Represents Steinberg Cubase 6. */ | |||
SteinbergCubase7, /**< Represents Steinberg Cubase 7. */ | |||
SteinbergCubase8, /**< Represents Steinberg Cubase 8. */ | |||
SteinbergCubase8_5, /**< Represents Steinberg Cubase 8.5. */ | |||
SteinbergCubase9, /**< Represents Steinberg Cubase 9. */ | |||
SteinbergCubase9_5, /**< Represents Steinberg Cubase 9.5. */ | |||
SteinbergCubase10, /**< Represents Steinberg Cubase 10. */ | |||
SteinbergCubase10_5, /**< Represents Steinberg Cubase 10.5. */ | |||
SteinbergCubaseGeneric, /**< Represents Steinberg Cubase. */ | |||
SteinbergNuendo3, /**< Represents Steinberg Nuendo 3. */ | |||
SteinbergNuendo4, /**< Represents Steinberg Nuendo 4. */ | |||
SteinbergNuendo5, /**< Represents Steinberg Nuendo 5. */ | |||
SteinbergNuendoGeneric, /**< Represents Steinberg Nuendo. */ | |||
SteinbergWavelab5, /**< Represents Steinberg Wavelab 5. */ | |||
SteinbergWavelab6, /**< Represents Steinberg Wavelab 6. */ | |||
SteinbergWavelab7, /**< Represents Steinberg Wavelab 7. */ | |||
SteinbergWavelab8, /**< Represents Steinberg Wavelab 8. */ | |||
SteinbergWavelabGeneric, /**< Represents Steinberg Wavelab. */ | |||
SteinbergTestHost, /**< Represents Steinberg's VST3 Test Host. */ | |||
StudioOne, /**< Represents PreSonus Studio One. */ | |||
Tracktion3, /**< Represents Tracktion 3. */ | |||
TracktionGeneric, /**< Represents Tracktion. */ | |||
TracktionWaveform, /**< Represents Tracktion Waveform. */ | |||
VBVSTScanner, /**< Represents VB Audio VST Scanner. */ | |||
ViennaEnsemblePro, /**< Represents Vienna Ensemble Pro. */ | |||
WaveBurner /**< Represents Apple WaveBurner. */ | |||
}; | |||
HostType type; | |||
//============================================================================== | |||
/** Returns true if the host is any version of Ableton Live. */ | |||
bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 | |||
|| type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; } | |||
/** Returns true if the host is Adobe Audition. */ | |||
bool isAdobeAudition() const noexcept { return type == AdobeAudition; } | |||
/** Returns true if the host is Ardour. */ | |||
bool isArdour() const noexcept { return type == Ardour; } | |||
/** Returns true if the host is Bitwig Studio. */ | |||
bool isBitwigStudio() const noexcept { return type == BitwigStudio; } | |||
/** Returns true if the host is any version of Steinberg Cubase. */ | |||
bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6 | |||
|| type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9 | |||
|| type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubase10_5 || type == SteinbergCubaseGeneric; } | |||
/** Returns true if the host is Steinberg Cubase 7 or later. */ | |||
bool isCubase7orLater() const noexcept { return isCubase() && ! (type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase6); } | |||
/** Returns true if the host is Steinberg Cubase 5 Bridged. */ | |||
bool isCubaseBridged() const noexcept { return type == SteinbergCubase5Bridged; } | |||
/** Returns true if the host is DaVinci Resolve. */ | |||
bool isDaVinciResolve() const noexcept { return type == DaVinciResolve; } | |||
/** Returns true if the host is Digital Performer. */ | |||
bool isDigitalPerformer() const noexcept { return type == DigitalPerformer; } | |||
/** Returns true if the host is Apple Final Cut Pro. */ | |||
bool isFinalCut() const noexcept { return type == FinalCut; } | |||
/** Returns true if the host is Fruity Loops. */ | |||
bool isFruityLoops() const noexcept { return type == FruityLoops; } | |||
/** Returns true if the host is Apple GarageBand. */ | |||
bool isGarageBand() const noexcept { return type == AppleGarageBand; } | |||
/** Returns true if the host is the JUCE AudioPluginHost */ | |||
bool isJUCEPluginHost() const noexcept { return type == JUCEPluginHost; } | |||
/** Returns true if the host is Apple Logic Pro. */ | |||
bool isLogic() const noexcept { return type == AppleLogic; } | |||
/** Returns true if the host is Apple MainStage. */ | |||
bool isMainStage() const noexcept { return type == AppleMainStage; } | |||
/** Returns true if the host is any version of Steinberg Nuendo. */ | |||
bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; } | |||
/** Returns true if the host is pluginval. */ | |||
bool isPluginval() const noexcept { return type == pluginval; } | |||
/** Returns true if the host is Adobe Premiere Pro. */ | |||
bool isPremiere() const noexcept { return type == AdobePremierePro; } | |||
/** Returns true if the host is Avid Pro Tools. */ | |||
bool isProTools() const noexcept { return type == AvidProTools; } | |||
/** Returns true if the host is Merging Pyramix. */ | |||
bool isPyramix() const noexcept { return type == MergingPyramix; } | |||
/** Returns true if the host is Muse Receptor. */ | |||
bool isReceptor() const noexcept { return type == MuseReceptorGeneric; } | |||
/** Returns true if the host is Cockos Reaper. */ | |||
bool isReaper() const noexcept { return type == Reaper; } | |||
/** Returns true if the host is Reason. */ | |||
bool isReason() const noexcept { return type == Reason; } | |||
/** Returns true if the host is Renoise. */ | |||
bool isRenoise() const noexcept { return type == Renoise; } | |||
/** Returns true if the host is SADiE. */ | |||
bool isSADiE() const noexcept { return type == SADiE; } | |||
/** Returns true if the host is Magix Samplitude. */ | |||
bool isSamplitude() const noexcept { return type == MagixSamplitude; } | |||
/** Returns true if the host is Magix Sequoia. */ | |||
bool isSequoia() const noexcept { return type == MagixSequoia; } | |||
/** Returns true if the host is any version of Cakewalk Sonar. */ | |||
bool isSonar() const noexcept { return type == CakewalkSonar8 || type == CakewalkSonarGeneric || type == CakewalkByBandlab; } | |||
/** Returns true if the host is Steinberg's VST3 Test Host. */ | |||
bool isSteinbergTestHost() const noexcept { return type == SteinbergTestHost; } | |||
/** Returns true if the host is any product from Steinberg. */ | |||
bool isSteinberg() const noexcept { return isCubase() || isNuendo() || isWavelab() || isSteinbergTestHost(); } | |||
/** Returns true if the host is PreSonus Studio One. */ | |||
bool isStudioOne() const noexcept { return type == StudioOne; } | |||
/** Returns true if the host is any version of Tracktion. */ | |||
bool isTracktion() const noexcept { return type == Tracktion3 || type == TracktionGeneric || isTracktionWaveform(); } | |||
/** Returns true if the host is Tracktion Waveform. */ | |||
bool isTracktionWaveform() const noexcept { return type == TracktionWaveform; } | |||
/** Returns true if the host is VB Audio VST Scanner. */ | |||
bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; } | |||
/** Returns true if the host is Vienna Ensemble Pro. */ | |||
bool isViennaEnsemblePro() const noexcept { return type == ViennaEnsemblePro; } | |||
/** Returns true if the host is Apple WaveBurner. */ | |||
bool isWaveBurner() const noexcept { return type == WaveBurner; } | |||
/** Returns true if the host is any version of Steinberg WaveLab. */ | |||
bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; } | |||
/** Returns true if the host is Steinberg WaveLab 6 or below. */ | |||
bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; } | |||
//============================================================================== | |||
/** Returns a human-readable description of the host. */ | |||
const char* getHostDescription() const noexcept | |||
{ | |||
switch (type) | |||
{ | |||
case AbletonLive6: return "Ableton Live 6"; | |||
case AbletonLive7: return "Ableton Live 7"; | |||
case AbletonLive8: return "Ableton Live 8"; | |||
case AbletonLive9: return "Ableton Live 9"; | |||
case AbletonLive10: return "Ableton Live 10"; | |||
case AbletonLiveGeneric: return "Ableton Live"; | |||
case AdobeAudition: return "Adobe Audition"; | |||
case AdobePremierePro: return "Adobe Premiere"; | |||
case AppleGarageBand: return "Apple GarageBand"; | |||
case AppleLogic: return "Apple Logic"; | |||
case AppleMainStage: return "Apple MainStage"; | |||
case Ardour: return "Ardour"; | |||
case AvidProTools: return "ProTools"; | |||
case BitwigStudio: return "Bitwig Studio"; | |||
case CakewalkSonar8: return "Cakewalk Sonar 8"; | |||
case CakewalkSonarGeneric: return "Cakewalk Sonar"; | |||
case CakewalkByBandlab: return "Cakewalk by Bandlab"; | |||
case DaVinciResolve: return "DaVinci Resolve"; | |||
case DigitalPerformer: return "DigitalPerformer"; | |||
case FinalCut: return "Final Cut"; | |||
case FruityLoops: return "FruityLoops"; | |||
case JUCEPluginHost: return "JUCE AudioPluginHost"; | |||
case MagixSamplitude: return "Magix Samplitude"; | |||
case MagixSequoia: return "Magix Sequoia"; | |||
case pluginval: return "pluginval"; | |||
case MergingPyramix: return "Pyramix"; | |||
case MuseReceptorGeneric: return "Muse Receptor"; | |||
case Reaper: return "Reaper"; | |||
case Reason: return "Reason"; | |||
case Renoise: return "Renoise"; | |||
case SADiE: return "SADiE"; | |||
case SteinbergCubase4: return "Steinberg Cubase 4"; | |||
case SteinbergCubase5: return "Steinberg Cubase 5"; | |||
case SteinbergCubase5Bridged: return "Steinberg Cubase 5 Bridged"; | |||
case SteinbergCubase6: return "Steinberg Cubase 6"; | |||
case SteinbergCubase7: return "Steinberg Cubase 7"; | |||
case SteinbergCubase8: return "Steinberg Cubase 8"; | |||
case SteinbergCubase8_5: return "Steinberg Cubase 8.5"; | |||
case SteinbergCubase9: return "Steinberg Cubase 9"; | |||
case SteinbergCubase9_5: return "Steinberg Cubase 9.5"; | |||
case SteinbergCubase10: return "Steinberg Cubase 10"; | |||
case SteinbergCubase10_5: return "Steinberg Cubase 10.5"; | |||
case SteinbergCubaseGeneric: return "Steinberg Cubase"; | |||
case SteinbergNuendo3: return "Steinberg Nuendo 3"; | |||
case SteinbergNuendo4: return "Steinberg Nuendo 4"; | |||
case SteinbergNuendo5: return "Steinberg Nuendo 5"; | |||
case SteinbergNuendoGeneric: return "Steinberg Nuendo"; | |||
case SteinbergWavelab5: return "Steinberg Wavelab 5"; | |||
case SteinbergWavelab6: return "Steinberg Wavelab 6"; | |||
case SteinbergWavelab7: return "Steinberg Wavelab 7"; | |||
case SteinbergWavelab8: return "Steinberg Wavelab 8"; | |||
case SteinbergWavelabGeneric: return "Steinberg Wavelab"; | |||
case SteinbergTestHost: return "Steinberg TestHost"; | |||
case StudioOne: return "Studio One"; | |||
case Tracktion3: return "Tracktion 3"; | |||
case TracktionGeneric: return "Tracktion"; | |||
case TracktionWaveform: return "Tracktion Waveform"; | |||
case VBVSTScanner: return "VBVSTScanner"; | |||
case ViennaEnsemblePro: return "Vienna Ensemble Pro"; | |||
case WaveBurner: return "WaveBurner"; | |||
case UnknownHost: | |||
default: break; | |||
} | |||
return "Unknown"; | |||
} | |||
//============================================================================== | |||
/** Returns true if the plugin is connected with Inter-App Audio on iOS. */ | |||
bool isInterAppAudioConnected() const; | |||
/** Switches to the host application when Inter-App Audio is used on iOS. */ | |||
void switchToHostApplication() const; | |||
/** Gets the host app's icon when Inter-App Audio is used on iOS. */ | |||
Image getHostIcon (int size) const; | |||
//============================================================================== | |||
/** Returns the complete absolute path of the host application executable. */ | |||
static String getHostPath() | |||
{ | |||
return File::getSpecialLocation (File::hostApplicationPath).getFullPathName(); | |||
} | |||
//============================================================================== | |||
/** | |||
Returns the plug-in format via which the plug-in file was loaded. This value is | |||
identical to AudioProcessor::wrapperType of the main audio processor of this | |||
plug-in. This function is useful for code that does not have access to the | |||
plug-in's main audio processor. | |||
@see AudioProcessor::wrapperType | |||
*/ | |||
static AudioProcessor::WrapperType getPluginLoadedAs() noexcept { return jucePlugInClientCurrentWrapperType; } | |||
/** Returns true if the AudioProcessor instance is an AAX plug-in running in AudioSuite. */ | |||
static bool isInAAXAudioSuite (AudioProcessor&); | |||
//============================================================================== | |||
#ifndef DOXYGEN | |||
// @internal | |||
static AudioProcessor::WrapperType jucePlugInClientCurrentWrapperType; | |||
static std::function<bool (AudioProcessor&)> jucePlugInIsRunningInAudioSuiteFn; | |||
#endif | |||
private: | |||
static HostType getHostType() | |||
{ | |||
auto hostPath = getHostPath(); | |||
auto hostFilename = File (hostPath).getFileName(); | |||
#if JUCE_MAC | |||
if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut; | |||
if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut; | |||
if (hostPath.containsIgnoreCase ("Live 6")) return AbletonLive6; | |||
if (hostPath.containsIgnoreCase ("Live 7")) return AbletonLive7; | |||
if (hostPath.containsIgnoreCase ("Live 8")) return AbletonLive8; | |||
if (hostPath.containsIgnoreCase ("Live 9")) return AbletonLive9; | |||
if (hostPath.containsIgnoreCase ("Live 10")) return AbletonLive10; | |||
if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric; | |||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; | |||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; | |||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; | |||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; | |||
if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5; | |||
if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; | |||
if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4; | |||
if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5; | |||
if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6; | |||
if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7; | |||
if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8; | |||
if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5; | |||
if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9; | |||
if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5; | |||
if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10; | |||
if (hostPath.containsIgnoreCase ("Cubase 10.5.app")) return SteinbergCubase10_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; | |||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; | |||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; | |||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; | |||
if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner; | |||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; | |||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; | |||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason; | |||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; | |||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; | |||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; | |||
#elif JUCE_WINDOWS | |||
if (hostFilename.containsIgnoreCase ("Live 6")) return AbletonLive6; | |||
if (hostFilename.containsIgnoreCase ("Live 7")) return AbletonLive7; | |||
if (hostFilename.containsIgnoreCase ("Live 8")) return AbletonLive8; | |||
if (hostFilename.containsIgnoreCase ("Live 9")) return AbletonLive9; | |||
if (hostFilename.containsIgnoreCase ("Live 10")) return AbletonLive10; | |||
if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric; | |||
if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition; | |||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; | |||
if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools; | |||
if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8; | |||
if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric; | |||
if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab; | |||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; | |||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; | |||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; | |||
if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4; | |||
if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5; | |||
if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6; | |||
if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7; | |||
if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8; | |||
if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5; | |||
// Later version of Cubase scan plug-ins with a separate executable "vst2xscanner" | |||
if (hostFilename.containsIgnoreCase ("Cubase9.5.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase9.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9; | |||
if (hostFilename.containsIgnoreCase ("Cubase10.5.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 10.5")) return SteinbergCubase10_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase10.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10; | |||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; | |||
if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged; | |||
if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5; | |||
if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6; | |||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; | |||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; | |||
if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; | |||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; | |||
if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; | |||
if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; | |||
if (hostFilename.startsWith ("FL")) return FruityLoops; | |||
if (hostFilename.contains ("ilbridge.")) return FruityLoops; | |||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; | |||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; | |||
if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner; | |||
if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix; | |||
if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude; | |||
if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia; | |||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason; | |||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; | |||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; | |||
if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; | |||
#elif JUCE_LINUX | |||
if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
#elif JUCE_IOS | |||
#elif JUCE_ANDROID | |||
#else | |||
#error | |||
#endif | |||
return UnknownHost; | |||
} | |||
}; | |||
} // namespace juce |
@@ -34,9 +34,6 @@ | |||
namespace juce | |||
{ | |||
AudioProcessor::WrapperType PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_Undefined; | |||
std::function<bool (AudioProcessor&)> PluginHostType::jucePlugInIsRunningInAudioSuiteFn = nullptr; | |||
#if JucePlugin_Build_Unity | |||
bool juce_isRunningInUnity() { return PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Unity; } | |||
#endif | |||
@@ -146,67 +143,3 @@ std::function<bool (AudioProcessor&)> PluginHostType::jucePlugInIsRunningInAudio | |||
#endif | |||
} // namespace juce | |||
using namespace juce; | |||
//============================================================================== | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
extern bool JUCE_CALLTYPE juce_isInterAppAudioConnected(); | |||
extern void JUCE_CALLTYPE juce_switchToHostApplication(); | |||
extern Image JUCE_CALLTYPE juce_getIAAHostIcon (int); | |||
#endif | |||
bool PluginHostType::isInterAppAudioConnected() const | |||
{ | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone) | |||
return juce_isInterAppAudioConnected(); | |||
#endif | |||
return false; | |||
} | |||
void PluginHostType::switchToHostApplication() const | |||
{ | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone) | |||
juce_switchToHostApplication(); | |||
#endif | |||
} | |||
bool PluginHostType::isInAAXAudioSuite (AudioProcessor& processor) | |||
{ | |||
#if JucePlugin_Build_AAX | |||
if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX | |||
&& jucePlugInIsRunningInAudioSuiteFn != nullptr) | |||
{ | |||
return jucePlugInIsRunningInAudioSuiteFn (processor); | |||
} | |||
#endif | |||
ignoreUnused (processor); | |||
return false; | |||
} | |||
namespace juce { | |||
extern Image JUCE_API getIconFromApplication (const String&, const int); | |||
Image PluginHostType::getHostIcon (int size) const | |||
{ | |||
ignoreUnused (size); | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (isInterAppAudioConnected()) | |||
return juce_getIAAHostIcon (size); | |||
#endif | |||
#if JUCE_MAC | |||
String bundlePath (getHostPath().upToLastOccurrenceOf (".app", true, true)); | |||
return getIconFromApplication (bundlePath, size); | |||
#endif | |||
return Image(); | |||
} | |||
} |
@@ -499,17 +499,11 @@ public: | |||
float normaliseParamValue (float scaledValue) const noexcept | |||
{ | |||
if (discrete) | |||
return scaledValue / (getNumSteps() - 1); | |||
return (scaledValue - minValue) / range; | |||
} | |||
float scaleParamValue (float normalisedValue) const noexcept | |||
{ | |||
if (discrete) | |||
return normalisedValue * (getNumSteps() - 1); | |||
return minValue + (range * normalisedValue); | |||
} | |||
@@ -1223,23 +1217,33 @@ public: | |||
} | |||
//============================================================================== | |||
int getNumPrograms() override | |||
struct ScopedFactoryPresets | |||
{ | |||
CFArrayRef presets; | |||
UInt32 sz = sizeof (CFArrayRef); | |||
int num = 0; | |||
ScopedFactoryPresets (AudioUnit& au) | |||
{ | |||
UInt32 sz = sizeof (CFArrayRef); | |||
if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, | |||
kAudioUnitScope_Global, 0, &presets, &sz) == noErr) | |||
AudioUnitGetProperty (au, kAudioUnitProperty_FactoryPresets, | |||
kAudioUnitScope_Global, 0, &presets, &sz); | |||
} | |||
~ScopedFactoryPresets() | |||
{ | |||
if (presets != nullptr) | |||
{ | |||
num = (int) CFArrayGetCount (presets); | |||
CFRelease (presets); | |||
} | |||
} | |||
return num; | |||
CFArrayRef presets = nullptr; | |||
}; | |||
int getNumPrograms() override | |||
{ | |||
ScopedFactoryPresets factoryPresets { audioUnit }; | |||
if (factoryPresets.presets != nullptr) | |||
return (int) CFArrayGetCount (factoryPresets.presets); | |||
return 0; | |||
} | |||
int getCurrentProgram() override | |||
@@ -1256,33 +1260,26 @@ public: | |||
void setCurrentProgram (int newIndex) override | |||
{ | |||
AUPreset current; | |||
current.presetNumber = newIndex; | |||
ScopedFactoryPresets factoryPresets { audioUnit }; | |||
CFArrayRef presets; | |||
UInt32 sz = sizeof (CFArrayRef); | |||
if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, | |||
kAudioUnitScope_Global, 0, &presets, &sz) == noErr) | |||
if (factoryPresets.presets != nullptr | |||
&& newIndex < (int) CFArrayGetCount (factoryPresets.presets)) | |||
{ | |||
if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, newIndex)) | |||
current.presetName = p->presetName; | |||
AUPreset current; | |||
current.presetNumber = newIndex; | |||
CFRelease (presets); | |||
} | |||
if (auto* p = static_cast<const AUPreset*> (CFArrayGetValueAtIndex (factoryPresets.presets, newIndex))) | |||
current.presetName = p->presetName; | |||
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset, | |||
kAudioUnitScope_Global, 0, ¤t, sizeof (AUPreset)); | |||
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset, | |||
kAudioUnitScope_Global, 0, ¤t, sizeof (AUPreset)); | |||
sendAllParametersChangedEvents(); | |||
sendAllParametersChangedEvents(); | |||
} | |||
} | |||
const String getProgramName (int index) override | |||
{ | |||
String s; | |||
CFArrayRef presets; | |||
UInt32 sz = sizeof (CFArrayRef); | |||
if (index == -1) | |||
{ | |||
AUPreset current; | |||
@@ -1294,27 +1291,20 @@ public: | |||
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_PresentPreset, | |||
kAudioUnitScope_Global, 0, ¤t, &prstsz); | |||
s = String::fromCFString (current.presetName); | |||
return String::fromCFString (current.presetName); | |||
} | |||
else if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, | |||
kAudioUnitScope_Global, 0, &presets, &sz) == noErr) | |||
ScopedFactoryPresets factoryPresets { audioUnit }; | |||
if (factoryPresets.presets != nullptr) | |||
{ | |||
for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i) | |||
{ | |||
if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i)) | |||
{ | |||
for (CFIndex i = 0; i < CFArrayGetCount (factoryPresets.presets); ++i) | |||
if (auto* p = static_cast<const AUPreset*> (CFArrayGetValueAtIndex (factoryPresets.presets, i))) | |||
if (p->presetNumber == index) | |||
{ | |||
s = String::fromCFString (p->presetName); | |||
break; | |||
} | |||
} | |||
} | |||
CFRelease (presets); | |||
return String::fromCFString (p->presetName); | |||
} | |||
return s; | |||
return {}; | |||
} | |||
void changeProgramName (int /*index*/, const String& /*newName*/) override | |||
@@ -1471,7 +1461,7 @@ public: | |||
info.defaultValue, | |||
(info.flags & kAudioUnitParameterFlag_NonRealTime) == 0, | |||
isDiscrete, | |||
isDiscrete ? (int) (info.maxValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps(), | |||
isDiscrete ? (int) (info.maxValue - info.minValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps(), | |||
isBoolean, | |||
label, | |||
(info.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0); | |||
@@ -266,31 +266,33 @@ static Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const Audio | |||
{ | |||
using namespace Steinberg::Vst::SpeakerArr; | |||
if (channels == AudioChannelSet::disabled()) return kEmpty; | |||
else if (channels == AudioChannelSet::mono()) return kMono; | |||
else if (channels == AudioChannelSet::stereo()) return kStereo; | |||
else if (channels == AudioChannelSet::createLCR()) return k30Cine; | |||
else if (channels == AudioChannelSet::createLRS()) return k30Music; | |||
else if (channels == AudioChannelSet::createLCRS()) return k40Cine; | |||
else if (channels == AudioChannelSet::create5point0()) return k50; | |||
else if (channels == AudioChannelSet::create5point1()) return k51; | |||
else if (channels == AudioChannelSet::create6point0()) return k60Cine; | |||
else if (channels == AudioChannelSet::create6point1()) return k61Cine; | |||
else if (channels == AudioChannelSet::create6point0Music()) return k60Music; | |||
else if (channels == AudioChannelSet::create6point1Music()) return k61Music; | |||
else if (channels == AudioChannelSet::create7point0()) return k70Music; | |||
else if (channels == AudioChannelSet::create7point0SDDS()) return k70Cine; | |||
else if (channels == AudioChannelSet::create7point1()) return k71CineSideFill; | |||
else if (channels == AudioChannelSet::create7point1SDDS()) return k71Cine; | |||
else if (channels == AudioChannelSet::ambisonic()) return kAmbi1stOrderACN; | |||
else if (channels == AudioChannelSet::quadraphonic()) return k40Music; | |||
else if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe); | |||
else if (channels == AudioChannelSet::create7point1point2()) return k71_2; | |||
else if (channels == AudioChannelSet::ambisonic (0)) return (1ull << 20); | |||
else if (channels == AudioChannelSet::ambisonic (1)) return (1ull << 20) | (1ull << 21) | (1ull << 22) | (1ull << 23); | |||
if (channels == AudioChannelSet::disabled()) return kEmpty; | |||
if (channels == AudioChannelSet::mono()) return kMono; | |||
if (channels == AudioChannelSet::stereo()) return kStereo; | |||
if (channels == AudioChannelSet::createLCR()) return k30Cine; | |||
if (channels == AudioChannelSet::createLRS()) return k30Music; | |||
if (channels == AudioChannelSet::createLCRS()) return k40Cine; | |||
if (channels == AudioChannelSet::create5point0()) return k50; | |||
if (channels == AudioChannelSet::create5point1()) return k51; | |||
if (channels == AudioChannelSet::create6point0()) return k60Cine; | |||
if (channels == AudioChannelSet::create6point1()) return k61Cine; | |||
if (channels == AudioChannelSet::create6point0Music()) return k60Music; | |||
if (channels == AudioChannelSet::create6point1Music()) return k61Music; | |||
if (channels == AudioChannelSet::create7point0()) return k70Music; | |||
if (channels == AudioChannelSet::create7point0SDDS()) return k70Cine; | |||
if (channels == AudioChannelSet::create7point1()) return k71CineSideFill; | |||
if (channels == AudioChannelSet::create7point1SDDS()) return k71Cine; | |||
if (channels == AudioChannelSet::ambisonic()) return kAmbi1stOrderACN; | |||
if (channels == AudioChannelSet::quadraphonic()) return k40Music; | |||
if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe); | |||
if (channels == AudioChannelSet::create7point1point2()) return k71_2; | |||
if (channels == AudioChannelSet::create7point0point4()) return k71_4 & ~(Steinberg::Vst::kSpeakerLfe); | |||
if (channels == AudioChannelSet::create7point1point4()) return k71_4; | |||
if (channels == AudioChannelSet::ambisonic (0)) return (1ull << 20); | |||
if (channels == AudioChannelSet::ambisonic (1)) return (1ull << 20) | (1ull << 21) | (1ull << 22) | (1ull << 23); | |||
#if VST_VERSION >= 0x030608 | |||
else if (channels == AudioChannelSet::ambisonic (2)) return kAmbi2cdOrderACN; | |||
else if (channels == AudioChannelSet::ambisonic (3)) return kAmbi3rdOrderACN; | |||
if (channels == AudioChannelSet::ambisonic (2)) return kAmbi2cdOrderACN; | |||
if (channels == AudioChannelSet::ambisonic (3)) return kAmbi3rdOrderACN; | |||
#endif | |||
Steinberg::Vst::SpeakerArrangement result = 0; | |||
@@ -307,32 +309,36 @@ static AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst::Speak | |||
{ | |||
using namespace Steinberg::Vst::SpeakerArr; | |||
if (arr == kEmpty) return AudioChannelSet::disabled(); | |||
else if (arr == kMono) return AudioChannelSet::mono(); | |||
else if (arr == kStereo) return AudioChannelSet::stereo(); | |||
else if (arr == k30Cine) return AudioChannelSet::createLCR(); | |||
else if (arr == k30Music) return AudioChannelSet::createLRS(); | |||
else if (arr == k40Cine) return AudioChannelSet::createLCRS(); | |||
else if (arr == k50) return AudioChannelSet::create5point0(); | |||
else if (arr == k51) return AudioChannelSet::create5point1(); | |||
else if (arr == k60Cine) return AudioChannelSet::create6point0(); | |||
else if (arr == k61Cine) return AudioChannelSet::create6point1(); | |||
else if (arr == k60Music) return AudioChannelSet::create6point0Music(); | |||
else if (arr == k61Music) return AudioChannelSet::create6point1Music(); | |||
else if (arr == k70Music) return AudioChannelSet::create7point0(); | |||
else if (arr == k70Cine) return AudioChannelSet::create7point0SDDS(); | |||
else if (arr == k71CineSideFill) return AudioChannelSet::create7point1(); | |||
else if (arr == k71Cine) return AudioChannelSet::create7point1SDDS(); | |||
else if (arr == kAmbi1stOrderACN) return AudioChannelSet::ambisonic(); | |||
else if (arr == k40Music) return AudioChannelSet::quadraphonic(); | |||
else if (arr == k71_2) return AudioChannelSet::create7point1point2(); | |||
else if (arr == (k71_2 & ~(Steinberg::Vst::kSpeakerLfe))) return AudioChannelSet::create7point0point2(); | |||
else if (arr == (1 << 20)) return AudioChannelSet::ambisonic (0); | |||
else if (arr == ((1 << 20) | (1 << 21) | (1 << 22) | (1 << 23))) return AudioChannelSet::ambisonic (1); | |||
#if VST_VERSION >= 0x030608 | |||
else if (arr == kAmbi2cdOrderACN) return AudioChannelSet::ambisonic (2); | |||
else if (arr == kAmbi3rdOrderACN) return AudioChannelSet::ambisonic (3); | |||
#endif | |||
switch (arr) | |||
{ | |||
case kEmpty: return AudioChannelSet::disabled(); | |||
case kMono: return AudioChannelSet::mono(); | |||
case kStereo: return AudioChannelSet::stereo(); | |||
case k30Cine: return AudioChannelSet::createLCR(); | |||
case k30Music: return AudioChannelSet::createLRS(); | |||
case k40Cine: return AudioChannelSet::createLCRS(); | |||
case k50: return AudioChannelSet::create5point0(); | |||
case k51: return AudioChannelSet::create5point1(); | |||
case k60Cine: return AudioChannelSet::create6point0(); | |||
case k61Cine: return AudioChannelSet::create6point1(); | |||
case k60Music: return AudioChannelSet::create6point0Music(); | |||
case k61Music: return AudioChannelSet::create6point1Music(); | |||
case k70Music: return AudioChannelSet::create7point0(); | |||
case k70Cine: return AudioChannelSet::create7point0SDDS(); | |||
case k71CineSideFill: return AudioChannelSet::create7point1(); | |||
case k71Cine: return AudioChannelSet::create7point1SDDS(); | |||
case k40Music: return AudioChannelSet::quadraphonic(); | |||
case k71_2: return AudioChannelSet::create7point1point2(); | |||
case k71_2 & ~(Steinberg::Vst::kSpeakerLfe): return AudioChannelSet::create7point0point2(); | |||
case k71_4: return AudioChannelSet::create7point1point4(); | |||
case k71_4 & ~(Steinberg::Vst::kSpeakerLfe): return AudioChannelSet::create7point0point4(); | |||
case (1 << 20): return AudioChannelSet::ambisonic (0); | |||
case kAmbi1stOrderACN: return AudioChannelSet::ambisonic (1); | |||
#if VST_VERSION >= 0x030608 | |||
case kAmbi2cdOrderACN: return AudioChannelSet::ambisonic (2); | |||
case kAmbi3rdOrderACN: return AudioChannelSet::ambisonic (3); | |||
#endif | |||
} | |||
AudioChannelSet result; | |||
@@ -253,3 +253,4 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone | |||
#include "utilities/juce_AudioParameterChoice.cpp" | |||
#include "utilities/juce_ParameterAttachments.cpp" | |||
#include "utilities/juce_AudioProcessorValueTreeState.cpp" | |||
#include "utilities/juce_PluginHostType.cpp" |
@@ -142,3 +142,4 @@ | |||
#include "utilities/juce_AudioParameterChoice.h" | |||
#include "utilities/juce_ParameterAttachments.h" | |||
#include "utilities/juce_AudioProcessorValueTreeState.h" | |||
#include "utilities/juce_PluginHostType.h" |
@@ -0,0 +1,309 @@ | |||
/* | |||
============================================================================== | |||
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. | |||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||
End User License Agreement: www.juce.com/juce-6-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
DISCLAIMED. | |||
============================================================================== | |||
*/ | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
bool JUCE_CALLTYPE juce_isInterAppAudioConnected(); | |||
void JUCE_CALLTYPE juce_switchToHostApplication(); | |||
juce::Image JUCE_CALLTYPE juce_getIAAHostIcon (int); | |||
#endif | |||
namespace juce | |||
{ | |||
Image JUCE_API getIconFromApplication (const String&, const int); | |||
AudioProcessor::WrapperType PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_Undefined; | |||
std::function<bool (AudioProcessor&)> PluginHostType::jucePlugInIsRunningInAudioSuiteFn = nullptr; | |||
String PluginHostType::hostIdReportedByWrapper; | |||
bool PluginHostType::isInterAppAudioConnected() const | |||
{ | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone) | |||
return juce_isInterAppAudioConnected(); | |||
#endif | |||
return false; | |||
} | |||
void PluginHostType::switchToHostApplication() const | |||
{ | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone) | |||
juce_switchToHostApplication(); | |||
#endif | |||
} | |||
bool PluginHostType::isInAAXAudioSuite (AudioProcessor& processor) | |||
{ | |||
#if JucePlugin_Build_AAX | |||
if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_AAX | |||
&& jucePlugInIsRunningInAudioSuiteFn != nullptr) | |||
{ | |||
return jucePlugInIsRunningInAudioSuiteFn (processor); | |||
} | |||
#endif | |||
ignoreUnused (processor); | |||
return false; | |||
} | |||
Image PluginHostType::getHostIcon (int size) const | |||
{ | |||
ignoreUnused (size); | |||
#if JucePlugin_Enable_IAA && JucePlugin_Build_Standalone && JUCE_IOS && (! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP) | |||
if (isInterAppAudioConnected()) | |||
return juce_getIAAHostIcon (size); | |||
#endif | |||
#if JUCE_MAC | |||
String bundlePath (getHostPath().upToLastOccurrenceOf (".app", true, true)); | |||
return getIconFromApplication (bundlePath, size); | |||
#endif | |||
return Image(); | |||
} | |||
const char* PluginHostType::getHostDescription() const noexcept | |||
{ | |||
switch (type) | |||
{ | |||
case AbletonLive6: return "Ableton Live 6"; | |||
case AbletonLive7: return "Ableton Live 7"; | |||
case AbletonLive8: return "Ableton Live 8"; | |||
case AbletonLive9: return "Ableton Live 9"; | |||
case AbletonLive10: return "Ableton Live 10"; | |||
case AbletonLiveGeneric: return "Ableton Live"; | |||
case AdobeAudition: return "Adobe Audition"; | |||
case AdobePremierePro: return "Adobe Premiere"; | |||
case AppleGarageBand: return "Apple GarageBand"; | |||
case AppleLogic: return "Apple Logic"; | |||
case AppleMainStage: return "Apple MainStage"; | |||
case Ardour: return "Ardour"; | |||
case AvidProTools: return "ProTools"; | |||
case BitwigStudio: return "Bitwig Studio"; | |||
case CakewalkSonar8: return "Cakewalk Sonar 8"; | |||
case CakewalkSonarGeneric: return "Cakewalk Sonar"; | |||
case CakewalkByBandlab: return "Cakewalk by Bandlab"; | |||
case DaVinciResolve: return "DaVinci Resolve"; | |||
case DigitalPerformer: return "DigitalPerformer"; | |||
case FinalCut: return "Final Cut"; | |||
case FruityLoops: return "FruityLoops"; | |||
case JUCEPluginHost: return "JUCE AudioPluginHost"; | |||
case MagixSamplitude: return "Magix Samplitude"; | |||
case MagixSequoia: return "Magix Sequoia"; | |||
case pluginval: return "pluginval"; | |||
case MergingPyramix: return "Pyramix"; | |||
case MuseReceptorGeneric: return "Muse Receptor"; | |||
case Reaper: return "Reaper"; | |||
case Reason: return "Reason"; | |||
case Renoise: return "Renoise"; | |||
case SADiE: return "SADiE"; | |||
case SteinbergCubase4: return "Steinberg Cubase 4"; | |||
case SteinbergCubase5: return "Steinberg Cubase 5"; | |||
case SteinbergCubase5Bridged: return "Steinberg Cubase 5 Bridged"; | |||
case SteinbergCubase6: return "Steinberg Cubase 6"; | |||
case SteinbergCubase7: return "Steinberg Cubase 7"; | |||
case SteinbergCubase8: return "Steinberg Cubase 8"; | |||
case SteinbergCubase8_5: return "Steinberg Cubase 8.5"; | |||
case SteinbergCubase9: return "Steinberg Cubase 9"; | |||
case SteinbergCubase9_5: return "Steinberg Cubase 9.5"; | |||
case SteinbergCubase10: return "Steinberg Cubase 10"; | |||
case SteinbergCubase10_5: return "Steinberg Cubase 10.5"; | |||
case SteinbergCubaseGeneric: return "Steinberg Cubase"; | |||
case SteinbergNuendo3: return "Steinberg Nuendo 3"; | |||
case SteinbergNuendo4: return "Steinberg Nuendo 4"; | |||
case SteinbergNuendo5: return "Steinberg Nuendo 5"; | |||
case SteinbergNuendoGeneric: return "Steinberg Nuendo"; | |||
case SteinbergWavelab5: return "Steinberg Wavelab 5"; | |||
case SteinbergWavelab6: return "Steinberg Wavelab 6"; | |||
case SteinbergWavelab7: return "Steinberg Wavelab 7"; | |||
case SteinbergWavelab8: return "Steinberg Wavelab 8"; | |||
case SteinbergWavelabGeneric: return "Steinberg Wavelab"; | |||
case SteinbergTestHost: return "Steinberg TestHost"; | |||
case StudioOne: return "Studio One"; | |||
case Tracktion3: return "Tracktion 3"; | |||
case TracktionGeneric: return "Tracktion"; | |||
case TracktionWaveform: return "Tracktion Waveform"; | |||
case VBVSTScanner: return "VBVSTScanner"; | |||
case ViennaEnsemblePro: return "Vienna Ensemble Pro"; | |||
case WaveBurner: return "WaveBurner"; | |||
case UnknownHost: | |||
default: break; | |||
} | |||
return "Unknown"; | |||
} | |||
PluginHostType::HostType PluginHostType::getHostType() | |||
{ | |||
auto hostPath = getHostPath(); | |||
auto hostFilename = File (hostPath).getFileName(); | |||
#if JUCE_MAC | |||
if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut; | |||
if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut; | |||
if (hostPath.containsIgnoreCase ("Live 6")) return AbletonLive6; | |||
if (hostPath.containsIgnoreCase ("Live 7")) return AbletonLive7; | |||
if (hostPath.containsIgnoreCase ("Live 8")) return AbletonLive8; | |||
if (hostPath.containsIgnoreCase ("Live 9")) return AbletonLive9; | |||
if (hostPath.containsIgnoreCase ("Live 10")) return AbletonLive10; | |||
if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric; | |||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; | |||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; | |||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; | |||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; | |||
if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4; | |||
if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5; | |||
if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; | |||
if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4; | |||
if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5; | |||
if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6; | |||
if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7; | |||
if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8; | |||
if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5; | |||
if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9; | |||
if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5; | |||
if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10; | |||
if (hostPath.containsIgnoreCase ("Cubase 10.5.app")) return SteinbergCubase10_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; | |||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; | |||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; | |||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; | |||
if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner; | |||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; | |||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; | |||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason; | |||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; | |||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; | |||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; | |||
if (hostIdReportedByWrapper == "com.apple.logic.pro") return AppleLogic; | |||
if (hostIdReportedByWrapper == "com.apple.garageband") return AppleGarageBand; | |||
if (hostIdReportedByWrapper == "com.apple.mainstage") return AppleMainStage; | |||
const auto procName = nsStringToJuce ([[NSRunningApplication currentApplication] localizedName]); | |||
const auto matchesInOrder = [&] (const StringArray& strings) | |||
{ | |||
return procName.matchesWildcard ("AUHostingService*(" + strings.joinIntoString ("*") + ")", false); | |||
}; | |||
// Depending on localization settings, spaces are not always plain ascii spaces | |||
if (matchesInOrder ({ "Logic", "Pro" })) return AppleLogic; | |||
if (matchesInOrder ({ "GarageBand" })) return AppleGarageBand; | |||
if (matchesInOrder ({ "MainStage" })) return AppleMainStage; | |||
if (matchesInOrder ({ "Final", "Cut", "Pro" })) return FinalCut; | |||
#elif JUCE_WINDOWS | |||
if (hostFilename.containsIgnoreCase ("Live 6")) return AbletonLive6; | |||
if (hostFilename.containsIgnoreCase ("Live 7")) return AbletonLive7; | |||
if (hostFilename.containsIgnoreCase ("Live 8")) return AbletonLive8; | |||
if (hostFilename.containsIgnoreCase ("Live 9")) return AbletonLive9; | |||
if (hostFilename.containsIgnoreCase ("Live 10")) return AbletonLive10; | |||
if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric; | |||
if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition; | |||
if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; | |||
if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools; | |||
if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8; | |||
if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric; | |||
if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab; | |||
if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; | |||
if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; | |||
if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; | |||
if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4; | |||
if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5; | |||
if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6; | |||
if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7; | |||
if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8; | |||
if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5; | |||
// Later version of Cubase scan plug-ins with a separate executable "vst2xscanner" | |||
if (hostFilename.containsIgnoreCase ("Cubase9.5.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase9.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9; | |||
if (hostFilename.containsIgnoreCase ("Cubase10.5.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 10.5")) return SteinbergCubase10_5; | |||
if (hostFilename.containsIgnoreCase ("Cubase10.exe") | |||
|| hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10; | |||
if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; | |||
if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged; | |||
if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5; | |||
if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6; | |||
if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; | |||
if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; | |||
if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; | |||
if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; | |||
if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; | |||
if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; | |||
if (hostFilename.startsWith ("FL")) return FruityLoops; | |||
if (hostFilename.contains ("ilbridge.")) return FruityLoops; | |||
if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; | |||
if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; | |||
if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner; | |||
if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix; | |||
if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude; | |||
if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia; | |||
if (hostFilename.containsIgnoreCase ("Reason")) return Reason; | |||
if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; | |||
if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; | |||
if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; | |||
#elif JUCE_LINUX | |||
if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour; | |||
if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; | |||
if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; | |||
if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; | |||
if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; | |||
if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; | |||
#elif JUCE_IOS | |||
#elif JUCE_ANDROID | |||
#else | |||
#error | |||
#endif | |||
return UnknownHost; | |||
} | |||
} // namespace juce |
@@ -0,0 +1,242 @@ | |||
/* | |||
============================================================================== | |||
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. | |||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||
End User License Agreement: www.juce.com/juce-6-licence | |||
Privacy Policy: www.juce.com/juce-privacy-policy | |||
Or: You may also use this code under the terms of the GPL v3 (see | |||
www.gnu.org/licenses). | |||
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 | |||
{ | |||
//============================================================================== | |||
/** | |||
A useful utility class to determine the host or DAW in which your plugin is | |||
loaded. | |||
Declare a PluginHostType object in your class to use it. | |||
@tags{Audio} | |||
*/ | |||
class PluginHostType | |||
{ | |||
public: | |||
//============================================================================== | |||
PluginHostType() : type (getHostType()) {} | |||
PluginHostType (const PluginHostType& other) = default; | |||
PluginHostType& operator= (const PluginHostType& other) = default; | |||
//============================================================================== | |||
/** Represents the host type and also its version for some hosts. */ | |||
enum HostType | |||
{ | |||
UnknownHost, /**< Represents an unknown host. */ | |||
AbletonLive6, /**< Represents Ableton Live 6. */ | |||
AbletonLive7, /**< Represents Ableton Live 7. */ | |||
AbletonLive8, /**< Represents Ableton Live 8. */ | |||
AbletonLive9, /**< Represents Ableton Live 9. */ | |||
AbletonLive10, /**< Represents Ableton Live 10. */ | |||
AbletonLiveGeneric, /**< Represents Ableton Live. */ | |||
AdobeAudition, /**< Represents Adobe Audition. */ | |||
AdobePremierePro, /**< Represents Adobe Premiere Pro. */ | |||
AppleGarageBand, /**< Represents Apple GarageBand. */ | |||
AppleLogic, /**< Represents Apple Logic Pro. */ | |||
AppleMainStage, /**< Represents Apple Main Stage. */ | |||
Ardour, /**< Represents Ardour. */ | |||
AvidProTools, /**< Represents Avid Pro Tools. */ | |||
BitwigStudio, /**< Represents Bitwig Studio. */ | |||
CakewalkSonar8, /**< Represents Cakewalk Sonar 8. */ | |||
CakewalkSonarGeneric, /**< Represents Cakewalk Sonar. */ | |||
CakewalkByBandlab, /**< Represents Cakewalk by Bandlab. */ | |||
DaVinciResolve, /**< Represents DaVinci Resolve. */ | |||
DigitalPerformer, /**< Represents Digital Performer. */ | |||
FinalCut, /**< Represents Apple Final Cut Pro. */ | |||
FruityLoops, /**< Represents Fruity Loops. */ | |||
JUCEPluginHost, /**< Represents the JUCE AudioPluginHost */ | |||
MagixSamplitude, /**< Represents Magix Samplitude. */ | |||
MagixSequoia, /**< Represents Magix Sequoia. */ | |||
MergingPyramix, /**< Represents Merging Pyramix. */ | |||
MuseReceptorGeneric, /**< Represents Muse Receptor. */ | |||
pluginval, /**< Represents pluginval. */ | |||
Reaper, /**< Represents Cockos Reaper. */ | |||
Reason, /**< Represents Reason. */ | |||
Renoise, /**< Represents Renoise. */ | |||
SADiE, /**< Represents SADiE. */ | |||
SteinbergCubase4, /**< Represents Steinberg Cubase 4. */ | |||
SteinbergCubase5, /**< Represents Steinberg Cubase 5. */ | |||
SteinbergCubase5Bridged, /**< Represents Steinberg Cubase 5 Bridged. */ | |||
SteinbergCubase6, /**< Represents Steinberg Cubase 6. */ | |||
SteinbergCubase7, /**< Represents Steinberg Cubase 7. */ | |||
SteinbergCubase8, /**< Represents Steinberg Cubase 8. */ | |||
SteinbergCubase8_5, /**< Represents Steinberg Cubase 8.5. */ | |||
SteinbergCubase9, /**< Represents Steinberg Cubase 9. */ | |||
SteinbergCubase9_5, /**< Represents Steinberg Cubase 9.5. */ | |||
SteinbergCubase10, /**< Represents Steinberg Cubase 10. */ | |||
SteinbergCubase10_5, /**< Represents Steinberg Cubase 10.5. */ | |||
SteinbergCubaseGeneric, /**< Represents Steinberg Cubase. */ | |||
SteinbergNuendo3, /**< Represents Steinberg Nuendo 3. */ | |||
SteinbergNuendo4, /**< Represents Steinberg Nuendo 4. */ | |||
SteinbergNuendo5, /**< Represents Steinberg Nuendo 5. */ | |||
SteinbergNuendoGeneric, /**< Represents Steinberg Nuendo. */ | |||
SteinbergWavelab5, /**< Represents Steinberg Wavelab 5. */ | |||
SteinbergWavelab6, /**< Represents Steinberg Wavelab 6. */ | |||
SteinbergWavelab7, /**< Represents Steinberg Wavelab 7. */ | |||
SteinbergWavelab8, /**< Represents Steinberg Wavelab 8. */ | |||
SteinbergWavelabGeneric, /**< Represents Steinberg Wavelab. */ | |||
SteinbergTestHost, /**< Represents Steinberg's VST3 Test Host. */ | |||
StudioOne, /**< Represents PreSonus Studio One. */ | |||
Tracktion3, /**< Represents Tracktion 3. */ | |||
TracktionGeneric, /**< Represents Tracktion. */ | |||
TracktionWaveform, /**< Represents Tracktion Waveform. */ | |||
VBVSTScanner, /**< Represents VB Audio VST Scanner. */ | |||
ViennaEnsemblePro, /**< Represents Vienna Ensemble Pro. */ | |||
WaveBurner /**< Represents Apple WaveBurner. */ | |||
}; | |||
HostType type; | |||
//============================================================================== | |||
/** Returns true if the host is any version of Ableton Live. */ | |||
bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 | |||
|| type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; } | |||
/** Returns true if the host is Adobe Audition. */ | |||
bool isAdobeAudition() const noexcept { return type == AdobeAudition; } | |||
/** Returns true if the host is Ardour. */ | |||
bool isArdour() const noexcept { return type == Ardour; } | |||
/** Returns true if the host is Bitwig Studio. */ | |||
bool isBitwigStudio() const noexcept { return type == BitwigStudio; } | |||
/** Returns true if the host is any version of Steinberg Cubase. */ | |||
bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6 | |||
|| type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9 | |||
|| type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubase10_5 || type == SteinbergCubaseGeneric; } | |||
/** Returns true if the host is Steinberg Cubase 7 or later. */ | |||
bool isCubase7orLater() const noexcept { return isCubase() && ! (type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase6); } | |||
/** Returns true if the host is Steinberg Cubase 5 Bridged. */ | |||
bool isCubaseBridged() const noexcept { return type == SteinbergCubase5Bridged; } | |||
/** Returns true if the host is DaVinci Resolve. */ | |||
bool isDaVinciResolve() const noexcept { return type == DaVinciResolve; } | |||
/** Returns true if the host is Digital Performer. */ | |||
bool isDigitalPerformer() const noexcept { return type == DigitalPerformer; } | |||
/** Returns true if the host is Apple Final Cut Pro. */ | |||
bool isFinalCut() const noexcept { return type == FinalCut; } | |||
/** Returns true if the host is Fruity Loops. */ | |||
bool isFruityLoops() const noexcept { return type == FruityLoops; } | |||
/** Returns true if the host is Apple GarageBand. */ | |||
bool isGarageBand() const noexcept { return type == AppleGarageBand; } | |||
/** Returns true if the host is the JUCE AudioPluginHost */ | |||
bool isJUCEPluginHost() const noexcept { return type == JUCEPluginHost; } | |||
/** Returns true if the host is Apple Logic Pro. */ | |||
bool isLogic() const noexcept { return type == AppleLogic; } | |||
/** Returns true if the host is Apple MainStage. */ | |||
bool isMainStage() const noexcept { return type == AppleMainStage; } | |||
/** Returns true if the host is any version of Steinberg Nuendo. */ | |||
bool isNuendo() const noexcept { return type == SteinbergNuendo3 || type == SteinbergNuendo4 || type == SteinbergNuendo5 || type == SteinbergNuendoGeneric; } | |||
/** Returns true if the host is pluginval. */ | |||
bool isPluginval() const noexcept { return type == pluginval; } | |||
/** Returns true if the host is Adobe Premiere Pro. */ | |||
bool isPremiere() const noexcept { return type == AdobePremierePro; } | |||
/** Returns true if the host is Avid Pro Tools. */ | |||
bool isProTools() const noexcept { return type == AvidProTools; } | |||
/** Returns true if the host is Merging Pyramix. */ | |||
bool isPyramix() const noexcept { return type == MergingPyramix; } | |||
/** Returns true if the host is Muse Receptor. */ | |||
bool isReceptor() const noexcept { return type == MuseReceptorGeneric; } | |||
/** Returns true if the host is Cockos Reaper. */ | |||
bool isReaper() const noexcept { return type == Reaper; } | |||
/** Returns true if the host is Reason. */ | |||
bool isReason() const noexcept { return type == Reason; } | |||
/** Returns true if the host is Renoise. */ | |||
bool isRenoise() const noexcept { return type == Renoise; } | |||
/** Returns true if the host is SADiE. */ | |||
bool isSADiE() const noexcept { return type == SADiE; } | |||
/** Returns true if the host is Magix Samplitude. */ | |||
bool isSamplitude() const noexcept { return type == MagixSamplitude; } | |||
/** Returns true if the host is Magix Sequoia. */ | |||
bool isSequoia() const noexcept { return type == MagixSequoia; } | |||
/** Returns true if the host is any version of Cakewalk Sonar. */ | |||
bool isSonar() const noexcept { return type == CakewalkSonar8 || type == CakewalkSonarGeneric || type == CakewalkByBandlab; } | |||
/** Returns true if the host is Steinberg's VST3 Test Host. */ | |||
bool isSteinbergTestHost() const noexcept { return type == SteinbergTestHost; } | |||
/** Returns true if the host is any product from Steinberg. */ | |||
bool isSteinberg() const noexcept { return isCubase() || isNuendo() || isWavelab() || isSteinbergTestHost(); } | |||
/** Returns true if the host is PreSonus Studio One. */ | |||
bool isStudioOne() const noexcept { return type == StudioOne; } | |||
/** Returns true if the host is any version of Tracktion. */ | |||
bool isTracktion() const noexcept { return type == Tracktion3 || type == TracktionGeneric || isTracktionWaveform(); } | |||
/** Returns true if the host is Tracktion Waveform. */ | |||
bool isTracktionWaveform() const noexcept { return type == TracktionWaveform; } | |||
/** Returns true if the host is VB Audio VST Scanner. */ | |||
bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; } | |||
/** Returns true if the host is Vienna Ensemble Pro. */ | |||
bool isViennaEnsemblePro() const noexcept { return type == ViennaEnsemblePro; } | |||
/** Returns true if the host is Apple WaveBurner. */ | |||
bool isWaveBurner() const noexcept { return type == WaveBurner; } | |||
/** Returns true if the host is any version of Steinberg WaveLab. */ | |||
bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; } | |||
/** Returns true if the host is Steinberg WaveLab 6 or below. */ | |||
bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; } | |||
//============================================================================== | |||
/** Returns a human-readable description of the host. */ | |||
const char* getHostDescription() const noexcept; | |||
//============================================================================== | |||
/** Returns true if the plugin is connected with Inter-App Audio on iOS. */ | |||
bool isInterAppAudioConnected() const; | |||
/** Switches to the host application when Inter-App Audio is used on iOS. */ | |||
void switchToHostApplication() const; | |||
/** Gets the host app's icon when Inter-App Audio is used on iOS. */ | |||
Image getHostIcon (int size) const; | |||
//============================================================================== | |||
/** Returns the complete absolute path of the host application executable. */ | |||
static String getHostPath() | |||
{ | |||
return File::getSpecialLocation (File::hostApplicationPath).getFullPathName(); | |||
} | |||
//============================================================================== | |||
/** | |||
Returns the plug-in format via which the plug-in file was loaded. This value is | |||
identical to AudioProcessor::wrapperType of the main audio processor of this | |||
plug-in. This function is useful for code that does not have access to the | |||
plug-in's main audio processor. | |||
@see AudioProcessor::wrapperType | |||
*/ | |||
static AudioProcessor::WrapperType getPluginLoadedAs() noexcept { return jucePlugInClientCurrentWrapperType; } | |||
/** Returns true if the AudioProcessor instance is an AAX plug-in running in AudioSuite. */ | |||
static bool isInAAXAudioSuite (AudioProcessor&); | |||
//============================================================================== | |||
#ifndef DOXYGEN | |||
// @internal | |||
static AudioProcessor::WrapperType jucePlugInClientCurrentWrapperType; | |||
static std::function<bool (AudioProcessor&)> jucePlugInIsRunningInAudioSuiteFn; | |||
static String hostIdReportedByWrapper; | |||
#endif | |||
private: | |||
static HostType getHostType(); | |||
}; | |||
} // namespace juce |
@@ -781,6 +781,8 @@ private: | |||
if (wantsNormalise == Convolution::Normalise::yes) | |||
normaliseImpulseResponse (resampled); | |||
else | |||
resampled.applyGain ((float) (originalSampleRate / processSpec.sampleRate)); | |||
const auto currentLatency = jmax (processSpec.maximumBlockSize, (uint32) latency.latencyInSamples); | |||
const auto maxBufferSize = shouldBeZeroLatency ? static_cast<int> (processSpec.maximumBlockSize) | |||
@@ -514,6 +514,9 @@ public: | |||
AudioBuffer<float> result (original.getNumChannels(), finalSize); | |||
resamplingSource.getNextAudioBlock ({ &result, 0, result.getNumSamples() }); | |||
result.applyGain ((float) resampleRatio); | |||
return result; | |||
}(); | |||
@@ -550,10 +553,10 @@ public: | |||
const auto ramp = makeRamp (static_cast<int> (spec.maximumBlockSize) * 8); | |||
using BlockSize = decltype (spec.maximumBlockSize); | |||
for (auto latency : { /*static_cast<BlockSize> (0), | |||
for (auto latency : { static_cast<BlockSize> (0), | |||
spec.maximumBlockSize / 3, | |||
spec.maximumBlockSize, | |||
spec.maximumBlockSize * 2, */ | |||
spec.maximumBlockSize * 2, | |||
static_cast<BlockSize> (spec.maximumBlockSize * 2.5) }) | |||
{ | |||
testConvolution (spec, | |||
@@ -1288,6 +1288,7 @@ PopupMenu::Options LookAndFeel_V2::getOptionsForComboBoxPopupMenu (ComboBox& box | |||
{ | |||
return PopupMenu::Options().withTargetComponent (&box) | |||
.withItemThatMustBeVisible (box.getSelectedId()) | |||
.withInitiallySelectedItem (box.getSelectedId()) | |||
.withMinimumWidth (box.getWidth()) | |||
.withMaximumNumColumns (1) | |||
.withStandardItemHeight (label.getHeight()); | |||
@@ -252,12 +252,19 @@ struct MenuWindow : public Component | |||
setOpaque (lf.findColour (PopupMenu::backgroundColourId).isOpaque() | |||
|| ! Desktop::canUseSemiTransparentWindows()); | |||
const auto initialSelectedId = options.getInitiallySelectedItemId(); | |||
for (int i = 0; i < menu.items.size(); ++i) | |||
{ | |||
auto& item = menu.items.getReference (i); | |||
if (i + 1 < menu.items.size() || ! item.isSeparator) | |||
items.add (new ItemComponent (item, options, *this)); | |||
{ | |||
auto* child = items.add (new ItemComponent (item, options, *this)); | |||
if (initialSelectedId != 0 && item.itemID == initialSelectedId) | |||
setCurrentlyHighlightedChild (child); | |||
} | |||
} | |||
auto targetArea = options.getTargetScreenArea() / scaleFactor; | |||
@@ -1239,7 +1246,7 @@ private: | |||
{ | |||
if (globalMousePos != lastMousePos || timeNow > lastMouseMoveTime + 350) | |||
{ | |||
const bool isMouseOver = window.reallyContains (localMousePos, true); | |||
const auto isMouseOver = window.reallyContains (localMousePos, true); | |||
if (isMouseOver) | |||
window.hasBeenOver = true; | |||
@@ -1279,7 +1286,12 @@ private: | |||
window.activeSubMenu->hide (nullptr, true); | |||
if (! isMouseOver) | |||
{ | |||
if (! window.hasBeenOver) | |||
return; | |||
itemUnderMouse = nullptr; | |||
} | |||
window.setCurrentlyHighlightedChild (itemUnderMouse); | |||
} | |||
@@ -1751,10 +1763,16 @@ PopupMenu::Options::Options() | |||
targetArea.setPosition (Desktop::getMousePosition()); | |||
} | |||
template <typename Member, typename Item> | |||
static PopupMenu::Options with (PopupMenu::Options options, Member&& member, Item&& item) | |||
{ | |||
options.*member = std::forward<Item> (item); | |||
return options; | |||
} | |||
PopupMenu::Options PopupMenu::Options::withTargetComponent (Component* comp) const | |||
{ | |||
Options o (*this); | |||
o.targetComponent = comp; | |||
auto o = with (*this, &Options::targetComponent, comp); | |||
if (comp != nullptr) | |||
o.targetArea = comp->getScreenBounds(); | |||
@@ -1769,66 +1787,54 @@ PopupMenu::Options PopupMenu::Options::withTargetComponent (Component& comp) con | |||
PopupMenu::Options PopupMenu::Options::withTargetScreenArea (Rectangle<int> area) const | |||
{ | |||
Options o (*this); | |||
o.targetArea = area; | |||
return o; | |||
return with (*this, &Options::targetArea, area); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withDeletionCheck (Component& comp) const | |||
{ | |||
Options o (*this); | |||
o.componentToWatchForDeletion = ∁ | |||
o.isWatchingForDeletion = true; | |||
return o; | |||
return with (with (*this, &Options::isWatchingForDeletion, true), | |||
&Options::componentToWatchForDeletion, | |||
&comp); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withMinimumWidth (int w) const | |||
{ | |||
Options o (*this); | |||
o.minWidth = w; | |||
return o; | |||
return with (*this, &Options::minWidth, w); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withMinimumNumColumns (int cols) const | |||
{ | |||
Options o (*this); | |||
o.minColumns = cols; | |||
return o; | |||
return with (*this, &Options::minColumns, cols); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withMaximumNumColumns (int cols) const | |||
{ | |||
Options o (*this); | |||
o.maxColumns = cols; | |||
return o; | |||
return with (*this, &Options::maxColumns, cols); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withStandardItemHeight (int height) const | |||
{ | |||
Options o (*this); | |||
o.standardHeight = height; | |||
return o; | |||
return with (*this, &Options::standardHeight, height); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withItemThatMustBeVisible (int idOfItemToBeVisible) const | |||
{ | |||
Options o (*this); | |||
o.visibleItemID = idOfItemToBeVisible; | |||
return o; | |||
return with (*this, &Options::visibleItemID, idOfItemToBeVisible); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withParentComponent (Component* parent) const | |||
{ | |||
Options o (*this); | |||
o.parentComponent = parent; | |||
return o; | |||
return with (*this, &Options::parentComponent, parent); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withPreferredPopupDirection (PopupDirection direction) const | |||
{ | |||
Options o (*this); | |||
o.preferredPopupDirection = direction; | |||
return o; | |||
return with (*this, &Options::preferredPopupDirection, direction); | |||
} | |||
PopupMenu::Options PopupMenu::Options::withInitiallySelectedItem (int idOfItemToBeSelected) const | |||
{ | |||
return with (*this, &Options::initiallySelectedItemId, idOfItemToBeSelected); | |||
} | |||
Component* PopupMenu::createWindow (const Options& options, | |||
@@ -470,6 +470,7 @@ public: | |||
Options withItemThatMustBeVisible (int idOfItemToBeVisible) const; | |||
Options withParentComponent (Component* parentComponent) const; | |||
Options withPreferredPopupDirection (PopupDirection direction) const; | |||
Options withInitiallySelectedItem (int idOfItemToBeSelected) const; | |||
//============================================================================== | |||
Component* getParentComponent() const noexcept { return parentComponent; } | |||
@@ -482,6 +483,7 @@ public: | |||
int getStandardItemHeight() const noexcept { return standardHeight; } | |||
int getItemThatMustBeVisible() const noexcept { return visibleItemID; } | |||
PopupDirection getPreferredPopupDirection() const noexcept { return preferredPopupDirection; } | |||
int getInitiallySelectedItemId() const noexcept { return initiallySelectedItemId; } | |||
private: | |||
//============================================================================== | |||
@@ -489,7 +491,7 @@ public: | |||
Component* targetComponent = nullptr; | |||
Component* parentComponent = nullptr; | |||
WeakReference<Component> componentToWatchForDeletion; | |||
int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0; | |||
int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0, initiallySelectedItemId = 0; | |||
bool isWatchingForDeletion = false; | |||
PopupDirection preferredPopupDirection = PopupDirection::downwards; | |||
}; | |||
@@ -41,6 +41,9 @@ public: | |||
// it's dangerous to create a window on a thread other than the message thread. | |||
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED | |||
if (! XWindowSystem::getInstance()->isX11Available()) | |||
return; | |||
if (isAlwaysOnTop) | |||
++numAlwaysOnTopPeers; | |||
@@ -80,8 +83,13 @@ public: | |||
//============================================================================== | |||
void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override | |||
{ | |||
bounds = newBounds.withSize (jmax (1, newBounds.getWidth()), | |||
jmax (1, newBounds.getHeight())); | |||
const auto correctedNewBounds = newBounds.withSize (jmax (1, newBounds.getWidth()), | |||
jmax (1, newBounds.getHeight())); | |||
if (bounds == correctedNewBounds && fullScreen == isNowFullScreen) | |||
return; | |||
bounds = correctedNewBounds; | |||
updateScaleFactorFromNewBounds (bounds, false); | |||
@@ -262,12 +270,14 @@ public: | |||
//============================================================================== | |||
void repaint (const Rectangle<int>& area) override | |||
{ | |||
repainter->repaint (area.getIntersection (bounds.withZeroOrigin())); | |||
if (repainter != nullptr) | |||
repainter->repaint (area.getIntersection (bounds.withZeroOrigin())); | |||
} | |||
void performAnyPendingRepaintsNow() override | |||
{ | |||
repainter->performAnyPendingRepaintsNow(); | |||
if (repainter != nullptr) | |||
repainter->performAnyPendingRepaintsNow(); | |||
} | |||
void setIcon (const Image& newIcon) override | |||
@@ -69,7 +69,7 @@ public: | |||
} | |||
} | |||
~Win32NativeFileChooser() | |||
~Win32NativeFileChooser() override | |||
{ | |||
signalThreadShouldExit(); | |||
waitForThreadToExit (-1); | |||
@@ -105,7 +105,7 @@ public: | |||
shouldCancel = true; | |||
if (auto hwnd = nativeDialogRef.get()) | |||
EndDialog (hwnd, 0); | |||
PostMessage (hwnd, WM_CLOSE, 0, 0); | |||
} | |||
Component* getCustomComponent() { return customComponent.get(); } | |||
@@ -237,25 +237,24 @@ private: | |||
ScopedLock lock (owner.deletingDialog); | |||
if (hwnd != nullptr) | |||
if (owner.shouldCancel) | |||
d->Close (S_FALSE); | |||
else if (hwnd != nullptr) | |||
owner.nativeDialogRef = hwnd; | |||
return owner.shouldCancel ? S_FALSE : S_OK; | |||
return S_OK; | |||
} | |||
JUCE_COMRESULT OnFolderChanging (IFileDialog*, IShellItem*) override { return S_OK; } | |||
JUCE_COMRESULT OnFileOk (IFileDialog*) override { return S_OK; } | |||
JUCE_COMRESULT OnFolderChange (IFileDialog*) override { return S_OK; } | |||
JUCE_COMRESULT OnSelectionChange (IFileDialog*) override { return S_OK; } | |||
JUCE_COMRESULT OnShareViolation (IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override { return S_OK; } | |||
JUCE_COMRESULT OnOverwrite (IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) override { return S_OK; } | |||
JUCE_COMRESULT OnFolderChanging (IFileDialog*, IShellItem*) override { return E_NOTIMPL; } | |||
JUCE_COMRESULT OnFileOk (IFileDialog*) override { return E_NOTIMPL; } | |||
JUCE_COMRESULT OnFolderChange (IFileDialog*) override { return E_NOTIMPL; } | |||
JUCE_COMRESULT OnSelectionChange (IFileDialog*) override { return E_NOTIMPL; } | |||
JUCE_COMRESULT OnShareViolation (IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override { return E_NOTIMPL; } | |||
JUCE_COMRESULT OnOverwrite (IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) override { return E_NOTIMPL; } | |||
Win32NativeFileChooser& owner; | |||
}; | |||
DWORD cookie = 0; | |||
dialog.Advise (new Events { *this }, &cookie); | |||
{ | |||
ScopedLock lock (deletingDialog); | |||
@@ -263,7 +262,20 @@ private: | |||
return false; | |||
} | |||
const auto result = dialog.Show (async ? nullptr : static_cast<HWND> (owner->getWindowHandle())) == S_OK; | |||
const auto result = [&] | |||
{ | |||
struct ScopedAdvise | |||
{ | |||
ScopedAdvise (IFileDialog& d, Events& events) : dialog (d) { dialog.Advise (&events, &cookie); } | |||
~ScopedAdvise() { dialog.Unadvise (cookie); } | |||
IFileDialog& dialog; | |||
DWORD cookie = 0; | |||
}; | |||
Events events { *this }; | |||
ScopedAdvise scope { dialog, events }; | |||
return dialog.Show (async ? nullptr : static_cast<HWND> (owner->getWindowHandle())) == S_OK; | |||
}(); | |||
ScopedLock lock (deletingDialog); | |||
nativeDialogRef = nullptr; | |||
@@ -483,8 +495,14 @@ private: | |||
void run() override | |||
{ | |||
// IUnknown_GetWindow will only succeed when instantiated in a single-thread apartment | |||
CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED); | |||
struct ScopedCoInitialize | |||
{ | |||
// IUnknown_GetWindow will only succeed when instantiated in a single-thread apartment | |||
ScopedCoInitialize() { CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); } | |||
~ScopedCoInitialize() { CoUninitialize(); } | |||
}; | |||
ScopedCoInitialize scope; | |||
auto resultsCopy = openDialog (true); | |||
auto safeOwner = owner; | |||
@@ -2033,7 +2033,7 @@ bool XWindowSystem::canUseARGBImages() const | |||
X11Symbols::getInstance()->xDefaultVisual (display, X11Symbols::getInstance()->xDefaultScreen (display)), | |||
24, ZPixmap, nullptr, &segmentinfo, 64, 64); | |||
canUseARGB = (testImage->bits_per_pixel == 32); | |||
canUseARGB = testImage != nullptr && testImage->bits_per_pixel == 32; | |||
X11Symbols::getInstance()->xDestroyImage (testImage); | |||
} | |||
else | |||
@@ -3067,7 +3067,7 @@ bool XWindowSystem::initialiseXDisplay() | |||
if (! displayVisuals->isValid()) | |||
{ | |||
Logger::outputDebugString ("ERROR: System doesn't support 32, 24 or 16 bit RGB display.\n"); | |||
Process::terminate(); | |||
return false; | |||
} | |||
// Setup input event handler | |||
@@ -164,6 +164,8 @@ public: | |||
::Display* getDisplay() { return display; } | |||
XWindowSystemUtilities::Atoms& getAtoms() { return atoms; } | |||
bool isX11Available() const noexcept { return xIsAvailable; } | |||
//============================================================================== | |||
void handleWindowMessage (LinuxComponentPeer*, XEvent&) const; | |||
bool isParentWindowOf (::Window, ::Window possibleChild) const; | |||
@@ -105,7 +105,7 @@ public: | |||
XSetWindowAttributes swa; | |||
swa.colormap = colourMap; | |||
swa.border_pixel = 0; | |||
swa.event_mask = ExposureMask | StructureNotifyMask; | |||
swa.event_mask = embeddedWindowEventMask; | |||
auto glBounds = component.getTopLevelComponent() | |||
->getLocalArea (&component, component.getLocalBounds()); | |||
@@ -141,9 +141,18 @@ public: | |||
if (embeddedWindow != 0) | |||
{ | |||
XWindowSystemUtilities::ScopedXLock xLock; | |||
X11Symbols::getInstance()->xUnmapWindow (display, embeddedWindow); | |||
X11Symbols::getInstance()->xDestroyWindow (display, embeddedWindow); | |||
X11Symbols::getInstance()->xSync (display, False); | |||
XEvent event; | |||
while (X11Symbols::getInstance()->xCheckWindowEvent (display, | |||
embeddedWindow, | |||
embeddedWindowEventMask, | |||
&event) == True) | |||
{ | |||
} | |||
} | |||
} | |||
@@ -255,6 +264,8 @@ public: | |||
struct Locker { Locker (NativeContext&) {} }; | |||
private: | |||
static constexpr int embeddedWindowEventMask = ExposureMask | StructureNotifyMask; | |||
Component& component; | |||
GLXContext renderContext = {}; | |||
Window embeddedWindow = {}; | |||