mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Plugin Client: Remove unnecessary wrapper files
This commit is contained in:
parent
22c8f0fe7e
commit
33ef4a86f4
31 changed files with 16454 additions and 16805 deletions
|
|
@ -313,7 +313,6 @@ endfunction()
|
|||
|
||||
function(_juce_add_plugin_wrapper_target format path out_path)
|
||||
_juce_module_sources("${path}" "${out_path}" out_var headers)
|
||||
list(FILTER out_var EXCLUDE REGEX "/juce_audio_plugin_client_utils.cpp$")
|
||||
set(target_name juce_audio_plugin_client_${format})
|
||||
|
||||
_juce_add_interface_library("${target_name}" ${out_var})
|
||||
|
|
@ -452,16 +451,6 @@ function(juce_add_module module_path)
|
|||
_juce_add_plugin_wrapper_target(${kind} "${module_path}" "${base_path}")
|
||||
endforeach()
|
||||
|
||||
set(utils_source
|
||||
"${base_path}/${module_name}/juce_audio_plugin_client_utils.cpp")
|
||||
add_library(juce_audio_plugin_client_utils INTERFACE)
|
||||
target_sources(juce_audio_plugin_client_utils INTERFACE "${utils_source}")
|
||||
|
||||
if(JUCE_ARG_ALIAS_NAMESPACE)
|
||||
add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_audio_plugin_client_utils
|
||||
ALIAS juce_audio_plugin_client_utils)
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE all_module_files
|
||||
CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE
|
||||
RELATIVE "${module_parent_path}"
|
||||
|
|
|
|||
|
|
@ -1211,7 +1211,7 @@ endfunction()
|
|||
function(_juce_configure_plugin_targets target)
|
||||
_juce_set_output_name(${target} $<TARGET_PROPERTY:${target},JUCE_PRODUCT_NAME>_SharedCode)
|
||||
|
||||
target_link_libraries(${target} PRIVATE juce::juce_audio_plugin_client_utils)
|
||||
target_link_libraries(${target} PRIVATE juce::juce_audio_plugin_client)
|
||||
|
||||
get_target_property(enabled_formats ${target} JUCE_FORMATS)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h>
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", "-Wgnu-zero-variadic-macro-arguments", "-Wmissing-prototypes")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100)
|
||||
|
||||
#include <ARA_Library/PlugIn/ARAPlug.cpp>
|
||||
#include <ARA_Library/Dispatch/ARAPlugInDispatch.cpp>
|
||||
#include <ARA_Library/Utilities/ARAPitchInterpretation.cpp>
|
||||
#include <ARA_Library/Utilities/ARAChannelArrangement.cpp>
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_WindowsHooks.h>
|
||||
|
||||
#include <juce_audio_devices/juce_audio_devices.h>
|
||||
#include <juce_gui_extra/juce_gui_extra.h>
|
||||
#include <juce_audio_utils/juce_audio_utils.h>
|
||||
|
||||
// You can set this flag in your build if you need to specify a different
|
||||
// standalone JUCEApplication class for your app to use. If you don't
|
||||
// set it then by default we'll just create a simple one as below.
|
||||
#if ! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP
|
||||
|
||||
#include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class StandaloneFilterApp : public JUCEApplication
|
||||
{
|
||||
public:
|
||||
StandaloneFilterApp()
|
||||
{
|
||||
PropertiesFile::Options options;
|
||||
|
||||
options.applicationName = getApplicationName();
|
||||
options.filenameSuffix = ".settings";
|
||||
options.osxLibrarySubFolder = "Application Support";
|
||||
#if JUCE_LINUX || JUCE_BSD
|
||||
options.folderName = "~/.config";
|
||||
#else
|
||||
options.folderName = "";
|
||||
#endif
|
||||
|
||||
appProperties.setStorageParameters (options);
|
||||
}
|
||||
|
||||
const String getApplicationName() override { return CharPointer_UTF8 (JucePlugin_Name); }
|
||||
const String getApplicationVersion() override { return JucePlugin_VersionString; }
|
||||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
void anotherInstanceStarted (const String&) override {}
|
||||
|
||||
virtual StandaloneFilterWindow* createWindow()
|
||||
{
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
StandalonePluginHolder::PluginInOuts channels[] = { JucePlugin_PreferredChannelConfigurations };
|
||||
#endif
|
||||
|
||||
return new StandaloneFilterWindow (getApplicationName(),
|
||||
LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId),
|
||||
appProperties.getUserSettings(),
|
||||
false, {}, nullptr
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
, juce::Array<StandalonePluginHolder::PluginInOuts> (channels, juce::numElementsInArray (channels))
|
||||
#else
|
||||
, {}
|
||||
#endif
|
||||
#if JUCE_DONT_AUTO_OPEN_MIDI_DEVICES_ON_MOBILE
|
||||
, false
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String&) override
|
||||
{
|
||||
mainWindow.reset (createWindow());
|
||||
|
||||
#if JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE
|
||||
Desktop::getInstance().setKioskModeComponent (mainWindow.get(), false);
|
||||
#endif
|
||||
|
||||
mainWindow->setVisible (true);
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
mainWindow = nullptr;
|
||||
appProperties.saveIfNeeded();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
if (mainWindow.get() != nullptr)
|
||||
mainWindow->pluginHolder->savePluginState();
|
||||
|
||||
if (ModalComponentManager::getInstance()->cancelAllModalComponents())
|
||||
{
|
||||
Timer::callAfterDelay (100, []()
|
||||
{
|
||||
if (auto app = JUCEApplicationBase::getInstance())
|
||||
app->systemRequestedQuit();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
quit();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ApplicationProperties appProperties;
|
||||
std::unique_ptr<StandaloneFilterWindow> mainWindow;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#if JucePlugin_Build_Standalone && JUCE_IOS
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
|
||||
|
||||
using namespace juce;
|
||||
|
||||
bool JUCE_CALLTYPE juce_isInterAppAudioConnected()
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
return holder->isInterAppAudioConnected();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE juce_switchToHostApplication()
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
holder->switchToHostApplication();
|
||||
}
|
||||
|
||||
Image JUCE_CALLTYPE juce_getIAAHostIcon (int size)
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
return holder->getIAAHostIcon (size);
|
||||
|
||||
return Image();
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,774 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#if JucePlugin_Build_Unity
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
|
||||
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#endif
|
||||
|
||||
#include "juce_UnityPluginInterface.h"
|
||||
|
||||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
|
||||
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
|
||||
extern createUnityPeerFunctionType juce_createUnityPeerFn;
|
||||
|
||||
//==============================================================================
|
||||
class UnityPeer : public ComponentPeer,
|
||||
public AsyncUpdater
|
||||
{
|
||||
public:
|
||||
UnityPeer (Component& ed)
|
||||
: ComponentPeer (ed, 0),
|
||||
mouseWatcher (*this)
|
||||
{
|
||||
getEditor().setResizable (false, false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> getBounds() const override { return bounds; }
|
||||
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); }
|
||||
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); }
|
||||
|
||||
using ComponentPeer::localToGlobal;
|
||||
using ComponentPeer::globalToLocal;
|
||||
|
||||
StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); }
|
||||
|
||||
void setBounds (const Rectangle<int>& newBounds, bool) override
|
||||
{
|
||||
bounds = newBounds;
|
||||
mouseWatcher.setBoundsToWatch (bounds);
|
||||
}
|
||||
|
||||
bool contains (Point<int> localPos, bool) const override
|
||||
{
|
||||
if (isPositiveAndBelow (localPos.getX(), getBounds().getWidth())
|
||||
&& isPositiveAndBelow (localPos.getY(), getBounds().getHeight()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
fillPixels();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorEditor& getEditor() { return *dynamic_cast<AudioProcessorEditor*> (&getComponent()); }
|
||||
|
||||
void setPixelDataHandle (uint8* handle, int width, int height)
|
||||
{
|
||||
pixelData = handle;
|
||||
|
||||
textureWidth = width;
|
||||
textureHeight = height;
|
||||
|
||||
renderImage = Image (new UnityBitmapImage (pixelData, width, height));
|
||||
}
|
||||
|
||||
// N.B. This is NOT an efficient way to do this and you shouldn't use this method in your own code.
|
||||
// It works for our purposes here but a much more efficient way would be to use a GL texture.
|
||||
void fillPixels()
|
||||
{
|
||||
if (pixelData == nullptr)
|
||||
return;
|
||||
|
||||
LowLevelGraphicsSoftwareRenderer renderer (renderImage);
|
||||
renderer.addTransform (AffineTransform::verticalFlip ((float) getComponent().getHeight()));
|
||||
|
||||
handlePaint (renderer);
|
||||
|
||||
for (int i = 0; i < textureWidth * textureHeight * 4; i += 4)
|
||||
{
|
||||
auto r = pixelData[i + 2];
|
||||
auto g = pixelData[i + 1];
|
||||
auto b = pixelData[i + 0];
|
||||
|
||||
pixelData[i + 0] = r;
|
||||
pixelData[i + 1] = g;
|
||||
pixelData[i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardMouseEvent (Point<float> position, ModifierKeys mods)
|
||||
{
|
||||
ModifierKeys::currentModifiers = mods;
|
||||
|
||||
handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::defaultPressure,
|
||||
juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
|
||||
}
|
||||
|
||||
void forwardKeyPress (int code, String name, ModifierKeys mods)
|
||||
{
|
||||
ModifierKeys::currentModifiers = mods;
|
||||
|
||||
handleKeyPress (getKeyPress (code, name));
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct UnityBitmapImage : public ImagePixelData
|
||||
{
|
||||
UnityBitmapImage (uint8* data, int w, int h)
|
||||
: ImagePixelData (Image::PixelFormat::ARGB, w, h),
|
||||
imageData (data),
|
||||
lineStride (width * pixelStride)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageType> createType() const override
|
||||
{
|
||||
return std::make_unique<SoftwareImageType>();
|
||||
}
|
||||
|
||||
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
|
||||
{
|
||||
return std::make_unique<LowLevelGraphicsSoftwareRenderer> (Image (this));
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, [[maybe_unused]] Image::BitmapData::ReadWriteMode mode) override
|
||||
{
|
||||
const auto offset = (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride;
|
||||
bitmap.data = imageData + offset;
|
||||
bitmap.size = (size_t) (lineStride * height) - offset;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
ImagePixelData::Ptr clone() override
|
||||
{
|
||||
auto im = new UnityBitmapImage (imageData, width, height);
|
||||
|
||||
for (int i = 0; i < height; ++i)
|
||||
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
uint8* imageData;
|
||||
int pixelStride = 4, lineStride;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityBitmapImage)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct MouseWatcher : public Timer
|
||||
{
|
||||
MouseWatcher (ComponentPeer& o) : owner (o) {}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
auto pos = Desktop::getMousePosition();
|
||||
|
||||
if (boundsToWatch.contains (pos) && pos != lastMousePos)
|
||||
{
|
||||
auto ms = Desktop::getInstance().getMainMouseSource();
|
||||
|
||||
if (! ms.getCurrentModifiers().isLeftButtonDown())
|
||||
owner.handleMouseEvent (juce::MouseInputSource::mouse, owner.globalToLocal (pos.toFloat()), {},
|
||||
juce::MouseInputSource::defaultPressure, juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
|
||||
|
||||
lastMousePos = pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setBoundsToWatch (Rectangle<int> b)
|
||||
{
|
||||
if (boundsToWatch != b)
|
||||
boundsToWatch = b;
|
||||
|
||||
startTimer (250);
|
||||
}
|
||||
|
||||
ComponentPeer& owner;
|
||||
Rectangle<int> boundsToWatch;
|
||||
Point<int> lastMousePos;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
KeyPress getKeyPress (int keyCode, String name)
|
||||
{
|
||||
if (keyCode >= 32 && keyCode <= 64)
|
||||
return { keyCode, ModifierKeys::currentModifiers, juce::juce_wchar (keyCode) };
|
||||
|
||||
if (keyCode >= 91 && keyCode <= 122)
|
||||
return { keyCode, ModifierKeys::currentModifiers, name[0] };
|
||||
|
||||
if (keyCode >= 256 && keyCode <= 265)
|
||||
return { juce::KeyPress::numberPad0 + (keyCode - 256), ModifierKeys::currentModifiers, juce::String (keyCode - 256).getCharPointer()[0] };
|
||||
|
||||
if (keyCode == 8) return { juce::KeyPress::backspaceKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 127) return { juce::KeyPress::deleteKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 9) return { juce::KeyPress::tabKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 13) return { juce::KeyPress::returnKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 27) return { juce::KeyPress::escapeKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 32) return { juce::KeyPress::spaceKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 266) return { juce::KeyPress::numberPadDecimalPoint, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 267) return { juce::KeyPress::numberPadDivide, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 268) return { juce::KeyPress::numberPadMultiply, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 269) return { juce::KeyPress::numberPadSubtract, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 270) return { juce::KeyPress::numberPadAdd, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 272) return { juce::KeyPress::numberPadEquals, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 273) return { juce::KeyPress::upKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 274) return { juce::KeyPress::downKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 275) return { juce::KeyPress::rightKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 276) return { juce::KeyPress::leftKey, ModifierKeys::currentModifiers, {} };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> bounds;
|
||||
MouseWatcher mouseWatcher;
|
||||
|
||||
uint8* pixelData = nullptr;
|
||||
int textureWidth, textureHeight;
|
||||
Image renderImage;
|
||||
|
||||
//==============================================================================
|
||||
void setMinimised (bool) override {}
|
||||
bool isMinimised() const override { return false; }
|
||||
void setFullScreen (bool) override {}
|
||||
bool isFullScreen() const override { return false; }
|
||||
bool setAlwaysOnTop (bool) override { return false; }
|
||||
void toFront (bool) override {}
|
||||
void toBehind (ComponentPeer*) override {}
|
||||
bool isFocused() const override { return true; }
|
||||
void grabFocus() override {}
|
||||
void* getNativeHandle() const override { return nullptr; }
|
||||
OptionalBorderSize getFrameSizeIfPresent() const override { return {}; }
|
||||
BorderSize<int> getFrameSize() const override { return {}; }
|
||||
void setVisible (bool) override {}
|
||||
void setTitle (const String&) override {}
|
||||
void setIcon (const Image&) override {}
|
||||
void textInputRequired (Point<int>, TextInputTarget&) override {}
|
||||
void setAlpha (float) override {}
|
||||
void performAnyPendingRepaintsNow() override {}
|
||||
void repaint (const Rectangle<int>&) override {}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer)
|
||||
};
|
||||
|
||||
static ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); }
|
||||
|
||||
//==============================================================================
|
||||
class AudioProcessorUnityWrapper
|
||||
{
|
||||
public:
|
||||
AudioProcessorUnityWrapper (bool isTemporary)
|
||||
{
|
||||
pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_Unity);
|
||||
|
||||
if (! isTemporary && pluginInstance->hasEditor())
|
||||
{
|
||||
pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded());
|
||||
pluginInstanceEditor->setVisible (true);
|
||||
detail::PluginUtilities::addToDesktop (*pluginInstanceEditor, nullptr);
|
||||
}
|
||||
|
||||
juceParameters.update (*pluginInstance, false);
|
||||
}
|
||||
|
||||
~AudioProcessorUnityWrapper()
|
||||
{
|
||||
if (pluginInstanceEditor != nullptr)
|
||||
{
|
||||
pluginInstanceEditor->removeFromDesktop();
|
||||
|
||||
PopupMenu::dismissAllActiveMenus();
|
||||
pluginInstanceEditor->processor.editorBeingDeleted (pluginInstanceEditor.get());
|
||||
pluginInstanceEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void create (UnityAudioEffectState* state)
|
||||
{
|
||||
// only supported in Unity plugin API > 1.0
|
||||
if (state->structSize >= sizeof (UnityAudioEffectState))
|
||||
samplesPerBlock = static_cast<int> (state->dspBufferSize);
|
||||
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
short configs[][2] = { JucePlugin_PreferredChannelConfigurations };
|
||||
const int numConfigs = sizeof (configs) / sizeof (short[2]);
|
||||
|
||||
jassertquiet (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
|
||||
|
||||
pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], state->sampleRate, samplesPerBlock);
|
||||
#else
|
||||
pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock);
|
||||
#endif
|
||||
|
||||
pluginInstance->prepareToPlay (state->sampleRate, samplesPerBlock);
|
||||
|
||||
scratchBuffer.setSize (jmax (pluginInstance->getTotalNumInputChannels(), pluginInstance->getTotalNumOutputChannels()), samplesPerBlock);
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
pluginInstance->releaseResources();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
pluginInstance->reset();
|
||||
}
|
||||
|
||||
void process (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
|
||||
{
|
||||
// If the plugin has a bypass parameter, set it to the current bypass state
|
||||
if (auto* param = pluginInstance->getBypassParameter())
|
||||
if (isBypassed != (param->getValue() >= 0.5f))
|
||||
param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f);
|
||||
|
||||
for (int pos = 0; pos < bufferSize;)
|
||||
{
|
||||
auto max = jmin (bufferSize - pos, samplesPerBlock);
|
||||
processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed);
|
||||
|
||||
pos += max;
|
||||
}
|
||||
}
|
||||
|
||||
void declareParameters (UnityAudioEffectDefinition& definition)
|
||||
{
|
||||
static std::unique_ptr<UnityAudioParameterDefinition> parametersPtr;
|
||||
static int numParams = 0;
|
||||
|
||||
if (parametersPtr == nullptr)
|
||||
{
|
||||
numParams = (int) juceParameters.size();
|
||||
|
||||
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
|
||||
sizeof (UnityAudioParameterDefinition))));
|
||||
|
||||
parameterDescriptions.clear();
|
||||
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
{
|
||||
auto* parameter = juceParameters.getParamForIndex (i);
|
||||
auto& paramDef = parametersPtr.get()[i];
|
||||
|
||||
const auto nameLength = (size_t) numElementsInArray (paramDef.name);
|
||||
const auto unitLength = (size_t) numElementsInArray (paramDef.unit);
|
||||
|
||||
parameter->getName ((int) nameLength - 1).copyToUTF8 (paramDef.name, nameLength);
|
||||
|
||||
if (parameter->getLabel().isNotEmpty())
|
||||
parameter->getLabel().copyToUTF8 (paramDef.unit, unitLength);
|
||||
|
||||
parameterDescriptions.add (parameter->getName (15));
|
||||
paramDef.description = parameterDescriptions[i].toRawUTF8();
|
||||
|
||||
paramDef.defaultVal = parameter->getDefaultValue();
|
||||
paramDef.min = 0.0f;
|
||||
paramDef.max = 1.0f;
|
||||
paramDef.displayScale = 1.0f;
|
||||
paramDef.displayExponent = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
definition.numParameters = static_cast<uint32> (numParams);
|
||||
definition.parameterDefintions = parametersPtr.get();
|
||||
}
|
||||
|
||||
void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValueNotifyingHost (value); }
|
||||
float getParameter (int index) const noexcept { return juceParameters.getParamForIndex (index)->getValue(); }
|
||||
|
||||
String getParameterString (int index) const noexcept
|
||||
{
|
||||
auto* param = juceParameters.getParamForIndex (index);
|
||||
return param->getText (param->getValue(), 16);
|
||||
}
|
||||
|
||||
int getNumInputChannels() const noexcept { return pluginInstance->getTotalNumInputChannels(); }
|
||||
int getNumOutputChannels() const noexcept { return pluginInstance->getTotalNumOutputChannels(); }
|
||||
|
||||
bool hasEditor() const noexcept { return pluginInstance->hasEditor(); }
|
||||
|
||||
UnityPeer& getEditorPeer() const
|
||||
{
|
||||
auto* peer = dynamic_cast<UnityPeer*> (pluginInstanceEditor->getPeer());
|
||||
|
||||
jassert (peer != nullptr);
|
||||
return *peer;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void processBuffers (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
|
||||
{
|
||||
int ch;
|
||||
for (ch = 0; ch < numInChannels; ++ch)
|
||||
{
|
||||
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
|
||||
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::Const>;
|
||||
|
||||
DstSampleType dstData (scratchBuffer.getWritePointer (ch));
|
||||
SrcSampleType srcData (inBuffer + ch, numInChannels);
|
||||
dstData.convertSamples (srcData, bufferSize);
|
||||
}
|
||||
|
||||
for (; ch < numOutChannels; ++ch)
|
||||
scratchBuffer.clear (ch, 0, bufferSize);
|
||||
|
||||
{
|
||||
const ScopedLock sl (pluginInstance->getCallbackLock());
|
||||
|
||||
if (pluginInstance->isSuspended())
|
||||
{
|
||||
scratchBuffer.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
MidiBuffer mb;
|
||||
|
||||
if (isBypassed && pluginInstance->getBypassParameter() == nullptr)
|
||||
pluginInstance->processBlockBypassed (scratchBuffer, mb);
|
||||
else
|
||||
pluginInstance->processBlock (scratchBuffer, mb);
|
||||
}
|
||||
}
|
||||
|
||||
for (ch = 0; ch < numOutChannels; ++ch)
|
||||
{
|
||||
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst>;
|
||||
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
|
||||
|
||||
DstSampleType dstData (outBuffer + ch, numOutChannels);
|
||||
SrcSampleType srcData (scratchBuffer.getReadPointer (ch));
|
||||
dstData.convertSamples (srcData, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<AudioProcessor> pluginInstance;
|
||||
std::unique_ptr<AudioProcessorEditor> pluginInstanceEditor;
|
||||
|
||||
int samplesPerBlock = 1024;
|
||||
StringArray parameterDescriptions;
|
||||
|
||||
AudioBuffer<float> scratchBuffer;
|
||||
|
||||
LegacyAudioParametersWrapper juceParameters;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static HashMap<int, AudioProcessorUnityWrapper*>& getWrapperMap()
|
||||
{
|
||||
static HashMap<int, AudioProcessorUnityWrapper*> wrapperMap;
|
||||
return wrapperMap;
|
||||
}
|
||||
|
||||
static void onWrapperCreation (AudioProcessorUnityWrapper* wrapperToAdd)
|
||||
{
|
||||
getWrapperMap().set (std::abs (Random::getSystemRandom().nextInt (65536)), wrapperToAdd);
|
||||
}
|
||||
|
||||
static void onWrapperDeletion (AudioProcessorUnityWrapper* wrapperToRemove)
|
||||
{
|
||||
getWrapperMap().removeValue (wrapperToRemove);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static UnityAudioEffectDefinition getEffectDefinition()
|
||||
{
|
||||
const auto wrapper = std::make_unique<AudioProcessorUnityWrapper> (true);
|
||||
const String originalName { JucePlugin_Name };
|
||||
const auto name = (! originalName.startsWithIgnoreCase ("audioplugin") ? "audioplugin_" : "") + originalName;
|
||||
|
||||
UnityAudioEffectDefinition result{};
|
||||
name.copyToUTF8 (result.name, (size_t) numElementsInArray (result.name));
|
||||
|
||||
result.structSize = sizeof (UnityAudioEffectDefinition);
|
||||
result.parameterStructSize = sizeof (UnityAudioParameterDefinition);
|
||||
|
||||
result.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION;
|
||||
result.pluginVersion = JucePlugin_VersionCode;
|
||||
|
||||
// effects must set this to 0, generators > 0
|
||||
result.channels = (wrapper->getNumInputChannels() != 0 ? 0
|
||||
: static_cast<uint32> (wrapper->getNumOutputChannels()));
|
||||
|
||||
wrapper->declareParameters (result);
|
||||
|
||||
result.create = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = new AudioProcessorUnityWrapper (false);
|
||||
pluginInstance->create (state);
|
||||
|
||||
state->effectData = pluginInstance;
|
||||
|
||||
onWrapperCreation (pluginInstance);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.release = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->release();
|
||||
|
||||
onWrapperDeletion (pluginInstance);
|
||||
delete pluginInstance;
|
||||
|
||||
if (getWrapperMap().size() == 0)
|
||||
shutdownJuce_GUI();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.reset = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->reset();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.setPosition = [] (UnityAudioEffectState* state, unsigned int pos)
|
||||
{
|
||||
ignoreUnused (state, pos);
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.process = [] (UnityAudioEffectState* state,
|
||||
float* inBuffer,
|
||||
float* outBuffer,
|
||||
unsigned int bufferSize,
|
||||
int numInChannels,
|
||||
int numOutChannels)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
if (pluginInstance != nullptr)
|
||||
{
|
||||
auto isPlaying = ((state->flags & stateIsPlaying) != 0);
|
||||
auto isMuted = ((state->flags & stateIsMuted) != 0);
|
||||
auto isPaused = ((state->flags & stateIsPaused) != 0);
|
||||
|
||||
const auto bypassed = ! isPlaying || (isMuted || isPaused);
|
||||
pluginInstance->process (inBuffer, outBuffer, static_cast<int> (bufferSize), numInChannels, numOutChannels, bypassed);
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatVectorOperations::clear (outBuffer, static_cast<int> (bufferSize) * numOutChannels);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.setFloatParameter = [] (UnityAudioEffectState* state, int index, float value)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->setParameter (index, value);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.getFloatParameter = [] (UnityAudioEffectState* state, int index, float* value, char* valueStr)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
*value = pluginInstance->getParameter (index);
|
||||
|
||||
pluginInstance->getParameterString (index).copyToUTF8 (valueStr, 15);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.getFloatBuffer = [] (UnityAudioEffectState* state, const char* kind, float* buffer, int numSamples)
|
||||
{
|
||||
ignoreUnused (numSamples);
|
||||
|
||||
const StringRef kindStr { kind };
|
||||
|
||||
if (kindStr == StringRef ("Editor"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f;
|
||||
}
|
||||
else if (kindStr == StringRef ("ID"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
for (HashMap<int, AudioProcessorUnityWrapper*>::Iterator i (getWrapperMap()); i.next();)
|
||||
{
|
||||
if (i.getValue() == pluginInstance)
|
||||
{
|
||||
buffer[0] = (float) i.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (kindStr == StringRef ("Size"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
auto& editor = pluginInstance->getEditorPeer().getEditor();
|
||||
|
||||
buffer[0] = (float) editor.getBounds().getWidth();
|
||||
buffer[1] = (float) editor.getBounds().getHeight();
|
||||
buffer[2] = (float) editor.getConstrainer()->getMinimumWidth();
|
||||
buffer[3] = (float) editor.getConstrainer()->getMinimumHeight();
|
||||
buffer[4] = (float) editor.getConstrainer()->getMaximumWidth();
|
||||
buffer[5] = (float) editor.getConstrainer()->getMaximumHeight();
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
||||
// From reading the example code, it seems that the triple indirection indicates
|
||||
// an out-value of an array of pointers. That is, after calling this function, definitionsPtr
|
||||
// should point to a pre-existing/static array of pointer-to-effect-definition.
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr)
|
||||
{
|
||||
if (juce::getWrapperMap().size() == 0)
|
||||
juce::initialiseJuce_GUI();
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once (flag, [] { juce::juce_createUnityPeerFn = juce::createUnityPeer; });
|
||||
|
||||
static auto definition = juce::getEffectDefinition();
|
||||
static UnityAudioEffectDefinition* definitions[] { &definition };
|
||||
*definitionsPtr = definitions;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static juce::ModifierKeys unityModifiersToJUCE (UnityEventModifiers mods, bool mouseDown, int mouseButton = -1)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (mouseDown)
|
||||
{
|
||||
if (mouseButton == 0)
|
||||
flags |= juce::ModifierKeys::leftButtonModifier;
|
||||
else if (mouseButton == 1)
|
||||
flags |= juce::ModifierKeys::rightButtonModifier;
|
||||
else if (mouseButton == 2)
|
||||
flags |= juce::ModifierKeys::middleButtonModifier;
|
||||
}
|
||||
|
||||
if (mods == 0)
|
||||
return flags;
|
||||
|
||||
if ((mods & UnityEventModifiers::shift) != 0) flags |= juce::ModifierKeys::shiftModifier;
|
||||
if ((mods & UnityEventModifiers::control) != 0) flags |= juce::ModifierKeys::ctrlModifier;
|
||||
if ((mods & UnityEventModifiers::alt) != 0) flags |= juce::ModifierKeys::altModifier;
|
||||
if ((mods & UnityEventModifiers::command) != 0) flags |= juce::ModifierKeys::commandModifier;
|
||||
|
||||
return { flags };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static juce::AudioProcessorUnityWrapper* getWrapperChecked (int id)
|
||||
{
|
||||
auto* wrapper = juce::getWrapperMap()[id];
|
||||
jassert (wrapper != nullptr);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void UNITY_INTERFACE_API onRenderEvent (int id)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback()
|
||||
{
|
||||
return onRenderEvent;
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityInitialiseTexture (int id, void* data, int w, int h)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast<juce::uint8*> (data), w, h);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers unityMods, int button)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers unityMods, int button)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers unityMods)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, false));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardKeyPress (code, name, unityModifiersToJUCE (mods, false));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().getEditor().setBounds ({ (int) x, (int) y, (int) w, (int) h });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_WINDOWS
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
|
||||
|
||||
extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
juce::Process::setCurrentModuleInstanceHandle (instance);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace juce::detail
|
||||
{
|
||||
|
||||
#if JucePlugin_Build_Unity
|
||||
bool isRunningInUnity();
|
||||
bool isRunningInUnity() { return PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Unity; }
|
||||
#endif
|
||||
|
||||
#if VST3_REPLACEMENT_AVAILABLE
|
||||
|
||||
// NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code.
|
||||
void PluginUtilities::getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16])
|
||||
{
|
||||
#if JUCE_MSVC
|
||||
const auto juce_sprintf = [] (auto&& head, auto&&... tail) { sprintf_s (head, numElementsInArray (head), tail...); };
|
||||
const auto juce_strcpy = [] (auto&& head, auto&&... tail) { strcpy_s (head, numElementsInArray (head), tail...); };
|
||||
const auto juce_strcat = [] (auto&& head, auto&&... tail) { strcat_s (head, numElementsInArray (head), tail...); };
|
||||
const auto juce_sscanf = [] (auto&&... args) { sscanf_s (args...); };
|
||||
#else
|
||||
const auto juce_sprintf = [] (auto&& head, auto&&... tail) { snprintf (head, (size_t) numElementsInArray (head), tail...); };
|
||||
const auto juce_strcpy = [] (auto&&... args) { strcpy (args...); };
|
||||
const auto juce_strcat = [] (auto&&... args) { strcat (args...); };
|
||||
const auto juce_sscanf = [] (auto&&... args) { sscanf (args...); };
|
||||
#endif
|
||||
|
||||
char uidString[33];
|
||||
|
||||
const int vstfxid = (('V' << 16) | ('S' << 8) | (forControllerUID ? 'E' : 'T'));
|
||||
char vstfxidStr[7] = { 0 };
|
||||
juce_sprintf (vstfxidStr, "%06X", vstfxid);
|
||||
|
||||
juce_strcpy (uidString, vstfxidStr);
|
||||
|
||||
char uidStr[9] = { 0 };
|
||||
juce_sprintf (uidStr, "%08X", JucePlugin_VSTUniqueID);
|
||||
juce_strcat (uidString, uidStr);
|
||||
|
||||
char nameidStr[3] = { 0 };
|
||||
const size_t len = strlen (JucePlugin_Name);
|
||||
|
||||
for (size_t i = 0; i <= 8; ++i)
|
||||
{
|
||||
juce::uint8 c = i < len ? static_cast<juce::uint8> (JucePlugin_Name[i]) : 0;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
|
||||
juce_sprintf (nameidStr, "%02X", c);
|
||||
juce_strcat (uidString, nameidStr);
|
||||
}
|
||||
|
||||
unsigned long p0;
|
||||
unsigned int p1, p2;
|
||||
unsigned int p3[8];
|
||||
|
||||
juce_sscanf (uidString, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
&p0, &p1, &p2, &p3[0], &p3[1], &p3[2], &p3[3], &p3[4], &p3[5], &p3[6], &p3[7]);
|
||||
|
||||
union q0_u {
|
||||
uint32 word;
|
||||
uint8 bytes[4];
|
||||
} q0;
|
||||
|
||||
union q1_u {
|
||||
uint16 half;
|
||||
uint8 bytes[2];
|
||||
} q1, q2;
|
||||
|
||||
q0.word = static_cast<uint32> (p0);
|
||||
q1.half = static_cast<uint16> (p1);
|
||||
q2.half = static_cast<uint16> (p2);
|
||||
|
||||
// VST3 doesn't use COM compatible UUIDs on non windows platforms
|
||||
#if ! JUCE_WINDOWS
|
||||
q0.word = ByteOrder::swap (q0.word);
|
||||
q1.half = ByteOrder::swap (q1.half);
|
||||
q2.half = ByteOrder::swap (q2.half);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
uuid[i+0] = q0.bytes[i];
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
uuid[i+4] = q1.bytes[i];
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
uuid[i+6] = q2.bytes[i];
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
uuid[i+8] = static_cast<uint8> (p3[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JucePlugin_Build_VST
|
||||
bool PluginUtilities::handleManufacturerSpecificVST2Opcode ([[maybe_unused]] int32 index,
|
||||
[[maybe_unused]] pointer_sized_int value,
|
||||
[[maybe_unused]] void* ptr,
|
||||
float)
|
||||
{
|
||||
#if VST3_REPLACEMENT_AVAILABLE
|
||||
if ((index == (int32) ByteOrder::bigEndianInt ("stCA") || index == (int32) ByteOrder::bigEndianInt ("stCa"))
|
||||
&& value == (int32) ByteOrder::bigEndianInt ("FUID") && ptr != nullptr)
|
||||
{
|
||||
uint8 fuid[16];
|
||||
getUUIDForVST2ID (false, fuid);
|
||||
::memcpy (ptr, fuid, 16);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -30,6 +30,13 @@
|
|||
namespace juce::detail
|
||||
{
|
||||
|
||||
bool isRunningInUnity();
|
||||
#if JucePlugin_Build_Unity
|
||||
bool isRunningInUnity() { return PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Unity; }
|
||||
#else
|
||||
bool isRunningInUnity() { return false; }
|
||||
#endif
|
||||
|
||||
struct PluginUtilities
|
||||
{
|
||||
PluginUtilities() = delete;
|
||||
|
|
@ -61,20 +68,106 @@ struct PluginUtilities
|
|||
#define JUCE_VST3_CAN_REPLACE_VST2 1
|
||||
#endif
|
||||
|
||||
#if JucePlugin_Build_VST3 && JUCE_VST3_CAN_REPLACE_VST2 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD)
|
||||
#define VST3_REPLACEMENT_AVAILABLE 1
|
||||
// NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code.
|
||||
static void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16])
|
||||
{
|
||||
#if JUCE_WINDOWS && ! JUCE_MINGW
|
||||
const auto juce_sprintf = [] (auto&& head, auto&&... tail) { sprintf_s (head, (size_t) numElementsInArray (head), tail...); };
|
||||
const auto juce_strcpy = [] (auto&& head, auto&&... tail) { strcpy_s (head, (size_t) numElementsInArray (head), tail...); };
|
||||
const auto juce_strcat = [] (auto&& head, auto&&... tail) { strcat_s (head, (size_t) numElementsInArray (head), tail...); };
|
||||
const auto juce_sscanf = [] (auto&&... args) { sscanf_s (args...); };
|
||||
#else
|
||||
const auto juce_sprintf = [] (auto&& head, auto&&... tail) { snprintf (head, (size_t) numElementsInArray (head), tail...); };
|
||||
const auto juce_strcpy = [] (auto&&... args) { strcpy (args...); };
|
||||
const auto juce_strcat = [] (auto&&... args) { strcat (args...); };
|
||||
const auto juce_sscanf = [] (auto&&... args) { sscanf (args...); };
|
||||
#endif
|
||||
|
||||
static void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16]);
|
||||
char uidString[33];
|
||||
|
||||
#else
|
||||
#define VST3_REPLACEMENT_AVAILABLE 0
|
||||
#endif
|
||||
const int vstfxid = (('V' << 16) | ('S' << 8) | (forControllerUID ? 'E' : 'T'));
|
||||
char vstfxidStr[7] = { 0 };
|
||||
juce_sprintf (vstfxidStr, "%06X", vstfxid);
|
||||
|
||||
juce_strcpy (uidString, vstfxidStr);
|
||||
|
||||
char uidStr[9] = { 0 };
|
||||
juce_sprintf (uidStr, "%08X", JucePlugin_VSTUniqueID);
|
||||
juce_strcat (uidString, uidStr);
|
||||
|
||||
char nameidStr[3] = { 0 };
|
||||
const size_t len = strlen (JucePlugin_Name);
|
||||
|
||||
for (size_t i = 0; i <= 8; ++i)
|
||||
{
|
||||
juce::uint8 c = i < len ? static_cast<juce::uint8> (JucePlugin_Name[i]) : 0;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
|
||||
juce_sprintf (nameidStr, "%02X", c);
|
||||
juce_strcat (uidString, nameidStr);
|
||||
}
|
||||
|
||||
unsigned long p0;
|
||||
unsigned int p1, p2;
|
||||
unsigned int p3[8];
|
||||
|
||||
juce_sscanf (uidString, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
&p0, &p1, &p2, &p3[0], &p3[1], &p3[2], &p3[3], &p3[4], &p3[5], &p3[6], &p3[7]);
|
||||
|
||||
union q0_u {
|
||||
uint32 word;
|
||||
uint8 bytes[4];
|
||||
} q0;
|
||||
|
||||
union q1_u {
|
||||
uint16 half;
|
||||
uint8 bytes[2];
|
||||
} q1, q2;
|
||||
|
||||
q0.word = static_cast<uint32> (p0);
|
||||
q1.half = static_cast<uint16> (p1);
|
||||
q2.half = static_cast<uint16> (p2);
|
||||
|
||||
// VST3 doesn't use COM compatible UUIDs on non windows platforms
|
||||
#if ! JUCE_WINDOWS
|
||||
q0.word = ByteOrder::swap (q0.word);
|
||||
q1.half = ByteOrder::swap (q1.half);
|
||||
q2.half = ByteOrder::swap (q2.half);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
uuid[i+0] = q0.bytes[i];
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
uuid[i+4] = q1.bytes[i];
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
uuid[i+6] = q2.bytes[i];
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
uuid[i+8] = static_cast<uint8> (p3[i]);
|
||||
}
|
||||
|
||||
#if JucePlugin_Build_VST
|
||||
static bool handleManufacturerSpecificVST2Opcode (int32 index,
|
||||
pointer_sized_int value,
|
||||
void* ptr,
|
||||
float);
|
||||
static bool handleManufacturerSpecificVST2Opcode ([[maybe_unused]] int32 index,
|
||||
[[maybe_unused]] pointer_sized_int value,
|
||||
[[maybe_unused]] void* ptr,
|
||||
float)
|
||||
{
|
||||
#if JUCE_VST3_CAN_REPLACE_VST2
|
||||
if ((index == (int32) ByteOrder::bigEndianInt ("stCA") || index == (int32) ByteOrder::bigEndianInt ("stCa"))
|
||||
&& value == (int32) ByteOrder::bigEndianInt ("FUID") && ptr != nullptr)
|
||||
{
|
||||
uint8 fuid[16];
|
||||
getUUIDForVST2ID (false, fuid);
|
||||
::memcpy (ptr, fuid, 16);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,15 +38,59 @@ struct VSTWindowUtilities
|
|||
|
||||
static void* attachComponentToWindowRefVST (Component* comp,
|
||||
int desktopFlags,
|
||||
void* parentWindowOrView);
|
||||
void* parentWindowOrView)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSView* parentView = [(NSView*) parentWindowOrView retain];
|
||||
|
||||
const auto defaultFlags = JucePlugin_EditorRequiresKeyboardFocus
|
||||
? 0
|
||||
: ComponentPeer::windowIgnoresKeyPresses;
|
||||
comp->addToDesktop (desktopFlags | defaultFlags, parentView);
|
||||
|
||||
// (this workaround is because Wavelab provides a zero-size parent view..)
|
||||
if ([parentView frame].size.height == 0)
|
||||
[((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
|
||||
|
||||
comp->setVisible (true);
|
||||
comp->toFront (false);
|
||||
|
||||
[[parentView window] setAcceptsMouseMovedEvents: YES];
|
||||
return parentView;
|
||||
}
|
||||
}
|
||||
|
||||
static void detachComponentFromWindowRefVST (Component* comp,
|
||||
void* window);
|
||||
void* window)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
comp->removeFromDesktop();
|
||||
[(id) window release];
|
||||
}
|
||||
}
|
||||
|
||||
static void setNativeHostWindowSizeVST (void* window,
|
||||
Component* component,
|
||||
int newWidth,
|
||||
int newHeight);
|
||||
int newHeight)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
if (NSView* hostView = (NSView*) window)
|
||||
{
|
||||
const int dx = newWidth - component->getWidth();
|
||||
const int dy = newHeight - component->getHeight();
|
||||
|
||||
NSRect r = [hostView frame];
|
||||
r.size.width += dx;
|
||||
r.size.height += dy;
|
||||
r.origin.y -= dy;
|
||||
[hostView setFrame: r];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace juce::detail
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#if JUCE_MAC
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_VSTWindowUtilities.h>
|
||||
|
||||
namespace juce::detail
|
||||
{
|
||||
|
||||
void* VSTWindowUtilities::attachComponentToWindowRefVST (Component* comp,
|
||||
int desktopFlags,
|
||||
void* parentWindowOrView)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSView* parentView = [(NSView*) parentWindowOrView retain];
|
||||
|
||||
const auto defaultFlags = JucePlugin_EditorRequiresKeyboardFocus
|
||||
? 0
|
||||
: ComponentPeer::windowIgnoresKeyPresses;
|
||||
comp->addToDesktop (desktopFlags | defaultFlags, parentView);
|
||||
|
||||
// (this workaround is because Wavelab provides a zero-size parent view..)
|
||||
if ([parentView frame].size.height == 0)
|
||||
[((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
|
||||
|
||||
comp->setVisible (true);
|
||||
comp->toFront (false);
|
||||
|
||||
[[parentView window] setAcceptsMouseMovedEvents: YES];
|
||||
return parentView;
|
||||
}
|
||||
}
|
||||
|
||||
void VSTWindowUtilities::detachComponentFromWindowRefVST (Component* comp, void* window)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
comp->removeFromDesktop();
|
||||
[(id) window release];
|
||||
}
|
||||
}
|
||||
|
||||
void VSTWindowUtilities::setNativeHostWindowSizeVST (void* window,
|
||||
Component* component,
|
||||
int newWidth,
|
||||
int newHeight)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
if (NSView* hostView = (NSView*) window)
|
||||
{
|
||||
const int dx = newWidth - component->getWidth();
|
||||
const int dy = newHeight - component->getHeight();
|
||||
|
||||
NSRect r = [hostView frame];
|
||||
r.size.width += dx;
|
||||
r.size.height += dy;
|
||||
r.origin.y -= dy;
|
||||
[hostView setFrame: r];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce::detail
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -24,4 +24,4 @@
|
|||
*/
|
||||
|
||||
#define JUCE_INCLUDED_AAX_IN_MM 1
|
||||
#include "AAX/juce_AAX_Wrapper.cpp"
|
||||
#include "juce_audio_plugin_client_AAX.cpp"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#if JucePlugin_Build_AAX && (JUCE_MAC || JUCE_WINDOWS)
|
||||
#if JucePlugin_Build_AAX
|
||||
|
||||
#include <AAX_Version.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -23,4 +23,23 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "ARA/juce_ARA_Wrapper.cpp"
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
|
||||
|
||||
#if JucePlugin_Enable_ARA
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h>
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", "-Wgnu-zero-variadic-macro-arguments", "-Wmissing-prototypes")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100)
|
||||
|
||||
#include <ARA_Library/PlugIn/ARAPlug.cpp>
|
||||
#include <ARA_Library/Dispatch/ARAPlugInDispatch.cpp>
|
||||
#include <ARA_Library/Utilities/ARAPitchInterpretation.cpp>
|
||||
#include <ARA_Library/Utilities/ARAChannelArrangement.cpp>
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -86,18 +86,18 @@ enum MIDICVStatus : unsigned int
|
|||
|
||||
#endif
|
||||
|
||||
#include "AU/AudioUnitSDK/AUBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUBuffer.cpp"
|
||||
#include "AU/AudioUnitSDK/AUBufferAllocator.cpp"
|
||||
#include "AU/AudioUnitSDK/AUEffectBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUInputElement.cpp"
|
||||
#include "AU/AudioUnitSDK/AUMIDIBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUMIDIEffectBase.cpp"
|
||||
#include "AU/AudioUnitSDK/AUOutputElement.cpp"
|
||||
#include "AU/AudioUnitSDK/AUPlugInDispatch.cpp"
|
||||
#include "AU/AudioUnitSDK/AUScopeElement.cpp"
|
||||
#include "AU/AudioUnitSDK/ComponentBase.cpp"
|
||||
#include "AU/AudioUnitSDK/MusicDeviceBase.cpp"
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUBase.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUBuffer.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUBufferAllocator.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUEffectBase.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUInputElement.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIBase.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUMIDIEffectBase.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUOutputElement.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUPlugInDispatch.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/AUScopeElement.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/ComponentBase.cpp>
|
||||
#include <juce_audio_plugin_client/AU/AudioUnitSDK/MusicDeviceBase.cpp>
|
||||
|
||||
#undef verify
|
||||
#undef verify_noerr
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -31,7 +31,152 @@
|
|||
#error To compile AudioUnitv3 and/or Standalone plug-ins, you need to add the juce_audio_utils and juce_audio_devices modules!
|
||||
#endif
|
||||
|
||||
#include "Standalone/juce_StandaloneFilterApp.cpp"
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_WindowsHooks.h>
|
||||
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
|
||||
|
||||
#include <juce_audio_devices/juce_audio_devices.h>
|
||||
#include <juce_gui_extra/juce_gui_extra.h>
|
||||
#include <juce_audio_utils/juce_audio_utils.h>
|
||||
|
||||
// You can set this flag in your build if you need to specify a different
|
||||
// standalone JUCEApplication class for your app to use. If you don't
|
||||
// set it then by default we'll just create a simple one as below.
|
||||
#if ! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP
|
||||
|
||||
#include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class StandaloneFilterApp : public JUCEApplication
|
||||
{
|
||||
public:
|
||||
StandaloneFilterApp()
|
||||
{
|
||||
PropertiesFile::Options options;
|
||||
|
||||
options.applicationName = getApplicationName();
|
||||
options.filenameSuffix = ".settings";
|
||||
options.osxLibrarySubFolder = "Application Support";
|
||||
#if JUCE_LINUX || JUCE_BSD
|
||||
options.folderName = "~/.config";
|
||||
#else
|
||||
options.folderName = "";
|
||||
#endif
|
||||
|
||||
appProperties.setStorageParameters (options);
|
||||
}
|
||||
|
||||
const String getApplicationName() override { return CharPointer_UTF8 (JucePlugin_Name); }
|
||||
const String getApplicationVersion() override { return JucePlugin_VersionString; }
|
||||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
void anotherInstanceStarted (const String&) override {}
|
||||
|
||||
virtual StandaloneFilterWindow* createWindow()
|
||||
{
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
StandalonePluginHolder::PluginInOuts channels[] = { JucePlugin_PreferredChannelConfigurations };
|
||||
#endif
|
||||
|
||||
return new StandaloneFilterWindow (getApplicationName(),
|
||||
LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId),
|
||||
appProperties.getUserSettings(),
|
||||
false, {}, nullptr
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
, juce::Array<StandalonePluginHolder::PluginInOuts> (channels, juce::numElementsInArray (channels))
|
||||
#else
|
||||
, {}
|
||||
#endif
|
||||
#if JUCE_DONT_AUTO_OPEN_MIDI_DEVICES_ON_MOBILE
|
||||
, false
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String&) override
|
||||
{
|
||||
mainWindow.reset (createWindow());
|
||||
|
||||
#if JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE
|
||||
Desktop::getInstance().setKioskModeComponent (mainWindow.get(), false);
|
||||
#endif
|
||||
|
||||
mainWindow->setVisible (true);
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
mainWindow = nullptr;
|
||||
appProperties.saveIfNeeded();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
if (mainWindow.get() != nullptr)
|
||||
mainWindow->pluginHolder->savePluginState();
|
||||
|
||||
if (ModalComponentManager::getInstance()->cancelAllModalComponents())
|
||||
{
|
||||
Timer::callAfterDelay (100, []()
|
||||
{
|
||||
if (auto app = JUCEApplicationBase::getInstance())
|
||||
app->systemRequestedQuit();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
quit();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ApplicationProperties appProperties;
|
||||
std::unique_ptr<StandaloneFilterWindow> mainWindow;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#if JucePlugin_Build_Standalone && JUCE_IOS
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
|
||||
|
||||
using namespace juce;
|
||||
|
||||
bool JUCE_CALLTYPE juce_isInterAppAudioConnected()
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
return holder->isInterAppAudioConnected();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE juce_switchToHostApplication()
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
holder->switchToHostApplication();
|
||||
}
|
||||
|
||||
Image JUCE_CALLTYPE juce_getIAAHostIcon (int size)
|
||||
{
|
||||
if (auto holder = StandalonePluginHolder::getInstance())
|
||||
return holder->getIAAHostIcon (size);
|
||||
|
||||
return Image();
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP
|
||||
extern juce::JUCEApplicationBase* juce_CreateApplication();
|
||||
|
|
|
|||
|
|
@ -23,4 +23,752 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "Unity/juce_Unity_Wrapper.cpp"
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#if JucePlugin_Build_Unity
|
||||
|
||||
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
|
||||
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
|
||||
#endif
|
||||
|
||||
#include <juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h>
|
||||
|
||||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
|
||||
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
|
||||
extern createUnityPeerFunctionType juce_createUnityPeerFn;
|
||||
|
||||
//==============================================================================
|
||||
class UnityPeer : public ComponentPeer,
|
||||
public AsyncUpdater
|
||||
{
|
||||
public:
|
||||
UnityPeer (Component& ed)
|
||||
: ComponentPeer (ed, 0),
|
||||
mouseWatcher (*this)
|
||||
{
|
||||
getEditor().setResizable (false, false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> getBounds() const override { return bounds; }
|
||||
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); }
|
||||
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); }
|
||||
|
||||
using ComponentPeer::localToGlobal;
|
||||
using ComponentPeer::globalToLocal;
|
||||
|
||||
StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); }
|
||||
|
||||
void setBounds (const Rectangle<int>& newBounds, bool) override
|
||||
{
|
||||
bounds = newBounds;
|
||||
mouseWatcher.setBoundsToWatch (bounds);
|
||||
}
|
||||
|
||||
bool contains (Point<int> localPos, bool) const override
|
||||
{
|
||||
if (isPositiveAndBelow (localPos.getX(), getBounds().getWidth())
|
||||
&& isPositiveAndBelow (localPos.getY(), getBounds().getHeight()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
fillPixels();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorEditor& getEditor() { return *dynamic_cast<AudioProcessorEditor*> (&getComponent()); }
|
||||
|
||||
void setPixelDataHandle (uint8* handle, int width, int height)
|
||||
{
|
||||
pixelData = handle;
|
||||
|
||||
textureWidth = width;
|
||||
textureHeight = height;
|
||||
|
||||
renderImage = Image (new UnityBitmapImage (pixelData, width, height));
|
||||
}
|
||||
|
||||
// N.B. This is NOT an efficient way to do this and you shouldn't use this method in your own code.
|
||||
// It works for our purposes here but a much more efficient way would be to use a GL texture.
|
||||
void fillPixels()
|
||||
{
|
||||
if (pixelData == nullptr)
|
||||
return;
|
||||
|
||||
LowLevelGraphicsSoftwareRenderer renderer (renderImage);
|
||||
renderer.addTransform (AffineTransform::verticalFlip ((float) getComponent().getHeight()));
|
||||
|
||||
handlePaint (renderer);
|
||||
|
||||
for (int i = 0; i < textureWidth * textureHeight * 4; i += 4)
|
||||
{
|
||||
auto r = pixelData[i + 2];
|
||||
auto g = pixelData[i + 1];
|
||||
auto b = pixelData[i + 0];
|
||||
|
||||
pixelData[i + 0] = r;
|
||||
pixelData[i + 1] = g;
|
||||
pixelData[i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardMouseEvent (Point<float> position, ModifierKeys mods)
|
||||
{
|
||||
ModifierKeys::currentModifiers = mods;
|
||||
|
||||
handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::defaultPressure,
|
||||
juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
|
||||
}
|
||||
|
||||
void forwardKeyPress (int code, String name, ModifierKeys mods)
|
||||
{
|
||||
ModifierKeys::currentModifiers = mods;
|
||||
|
||||
handleKeyPress (getKeyPress (code, name));
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct UnityBitmapImage : public ImagePixelData
|
||||
{
|
||||
UnityBitmapImage (uint8* data, int w, int h)
|
||||
: ImagePixelData (Image::PixelFormat::ARGB, w, h),
|
||||
imageData (data),
|
||||
lineStride (width * pixelStride)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageType> createType() const override
|
||||
{
|
||||
return std::make_unique<SoftwareImageType>();
|
||||
}
|
||||
|
||||
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
|
||||
{
|
||||
return std::make_unique<LowLevelGraphicsSoftwareRenderer> (Image (this));
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, [[maybe_unused]] Image::BitmapData::ReadWriteMode mode) override
|
||||
{
|
||||
const auto offset = (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride;
|
||||
bitmap.data = imageData + offset;
|
||||
bitmap.size = (size_t) (lineStride * height) - offset;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
ImagePixelData::Ptr clone() override
|
||||
{
|
||||
auto im = new UnityBitmapImage (imageData, width, height);
|
||||
|
||||
for (int i = 0; i < height; ++i)
|
||||
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
uint8* imageData;
|
||||
int pixelStride = 4, lineStride;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityBitmapImage)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct MouseWatcher : public Timer
|
||||
{
|
||||
MouseWatcher (ComponentPeer& o) : owner (o) {}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
auto pos = Desktop::getMousePosition();
|
||||
|
||||
if (boundsToWatch.contains (pos) && pos != lastMousePos)
|
||||
{
|
||||
auto ms = Desktop::getInstance().getMainMouseSource();
|
||||
|
||||
if (! ms.getCurrentModifiers().isLeftButtonDown())
|
||||
owner.handleMouseEvent (juce::MouseInputSource::mouse, owner.globalToLocal (pos.toFloat()), {},
|
||||
juce::MouseInputSource::defaultPressure, juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
|
||||
|
||||
lastMousePos = pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setBoundsToWatch (Rectangle<int> b)
|
||||
{
|
||||
if (boundsToWatch != b)
|
||||
boundsToWatch = b;
|
||||
|
||||
startTimer (250);
|
||||
}
|
||||
|
||||
ComponentPeer& owner;
|
||||
Rectangle<int> boundsToWatch;
|
||||
Point<int> lastMousePos;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
KeyPress getKeyPress (int keyCode, String name)
|
||||
{
|
||||
if (keyCode >= 32 && keyCode <= 64)
|
||||
return { keyCode, ModifierKeys::currentModifiers, juce::juce_wchar (keyCode) };
|
||||
|
||||
if (keyCode >= 91 && keyCode <= 122)
|
||||
return { keyCode, ModifierKeys::currentModifiers, name[0] };
|
||||
|
||||
if (keyCode >= 256 && keyCode <= 265)
|
||||
return { juce::KeyPress::numberPad0 + (keyCode - 256), ModifierKeys::currentModifiers, juce::String (keyCode - 256).getCharPointer()[0] };
|
||||
|
||||
if (keyCode == 8) return { juce::KeyPress::backspaceKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 127) return { juce::KeyPress::deleteKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 9) return { juce::KeyPress::tabKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 13) return { juce::KeyPress::returnKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 27) return { juce::KeyPress::escapeKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 32) return { juce::KeyPress::spaceKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 266) return { juce::KeyPress::numberPadDecimalPoint, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 267) return { juce::KeyPress::numberPadDivide, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 268) return { juce::KeyPress::numberPadMultiply, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 269) return { juce::KeyPress::numberPadSubtract, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 270) return { juce::KeyPress::numberPadAdd, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 272) return { juce::KeyPress::numberPadEquals, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 273) return { juce::KeyPress::upKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 274) return { juce::KeyPress::downKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 275) return { juce::KeyPress::rightKey, ModifierKeys::currentModifiers, {} };
|
||||
if (keyCode == 276) return { juce::KeyPress::leftKey, ModifierKeys::currentModifiers, {} };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> bounds;
|
||||
MouseWatcher mouseWatcher;
|
||||
|
||||
uint8* pixelData = nullptr;
|
||||
int textureWidth, textureHeight;
|
||||
Image renderImage;
|
||||
|
||||
//==============================================================================
|
||||
void setMinimised (bool) override {}
|
||||
bool isMinimised() const override { return false; }
|
||||
void setFullScreen (bool) override {}
|
||||
bool isFullScreen() const override { return false; }
|
||||
bool setAlwaysOnTop (bool) override { return false; }
|
||||
void toFront (bool) override {}
|
||||
void toBehind (ComponentPeer*) override {}
|
||||
bool isFocused() const override { return true; }
|
||||
void grabFocus() override {}
|
||||
void* getNativeHandle() const override { return nullptr; }
|
||||
OptionalBorderSize getFrameSizeIfPresent() const override { return {}; }
|
||||
BorderSize<int> getFrameSize() const override { return {}; }
|
||||
void setVisible (bool) override {}
|
||||
void setTitle (const String&) override {}
|
||||
void setIcon (const Image&) override {}
|
||||
void textInputRequired (Point<int>, TextInputTarget&) override {}
|
||||
void setAlpha (float) override {}
|
||||
void performAnyPendingRepaintsNow() override {}
|
||||
void repaint (const Rectangle<int>&) override {}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer)
|
||||
};
|
||||
|
||||
static ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); }
|
||||
|
||||
//==============================================================================
|
||||
class AudioProcessorUnityWrapper
|
||||
{
|
||||
public:
|
||||
AudioProcessorUnityWrapper (bool isTemporary)
|
||||
{
|
||||
pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_Unity);
|
||||
|
||||
if (! isTemporary && pluginInstance->hasEditor())
|
||||
{
|
||||
pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded());
|
||||
pluginInstanceEditor->setVisible (true);
|
||||
detail::PluginUtilities::addToDesktop (*pluginInstanceEditor, nullptr);
|
||||
}
|
||||
|
||||
juceParameters.update (*pluginInstance, false);
|
||||
}
|
||||
|
||||
~AudioProcessorUnityWrapper()
|
||||
{
|
||||
if (pluginInstanceEditor != nullptr)
|
||||
{
|
||||
pluginInstanceEditor->removeFromDesktop();
|
||||
|
||||
PopupMenu::dismissAllActiveMenus();
|
||||
pluginInstanceEditor->processor.editorBeingDeleted (pluginInstanceEditor.get());
|
||||
pluginInstanceEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void create (UnityAudioEffectState* state)
|
||||
{
|
||||
// only supported in Unity plugin API > 1.0
|
||||
if (state->structSize >= sizeof (UnityAudioEffectState))
|
||||
samplesPerBlock = static_cast<int> (state->dspBufferSize);
|
||||
|
||||
#ifdef JucePlugin_PreferredChannelConfigurations
|
||||
short configs[][2] = { JucePlugin_PreferredChannelConfigurations };
|
||||
const int numConfigs = sizeof (configs) / sizeof (short[2]);
|
||||
|
||||
jassertquiet (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
|
||||
|
||||
pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], state->sampleRate, samplesPerBlock);
|
||||
#else
|
||||
pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock);
|
||||
#endif
|
||||
|
||||
pluginInstance->prepareToPlay (state->sampleRate, samplesPerBlock);
|
||||
|
||||
scratchBuffer.setSize (jmax (pluginInstance->getTotalNumInputChannels(), pluginInstance->getTotalNumOutputChannels()), samplesPerBlock);
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
pluginInstance->releaseResources();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
pluginInstance->reset();
|
||||
}
|
||||
|
||||
void process (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
|
||||
{
|
||||
// If the plugin has a bypass parameter, set it to the current bypass state
|
||||
if (auto* param = pluginInstance->getBypassParameter())
|
||||
if (isBypassed != (param->getValue() >= 0.5f))
|
||||
param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f);
|
||||
|
||||
for (int pos = 0; pos < bufferSize;)
|
||||
{
|
||||
auto max = jmin (bufferSize - pos, samplesPerBlock);
|
||||
processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed);
|
||||
|
||||
pos += max;
|
||||
}
|
||||
}
|
||||
|
||||
void declareParameters (UnityAudioEffectDefinition& definition)
|
||||
{
|
||||
static std::unique_ptr<UnityAudioParameterDefinition> parametersPtr;
|
||||
static int numParams = 0;
|
||||
|
||||
if (parametersPtr == nullptr)
|
||||
{
|
||||
numParams = (int) juceParameters.size();
|
||||
|
||||
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
|
||||
sizeof (UnityAudioParameterDefinition))));
|
||||
|
||||
parameterDescriptions.clear();
|
||||
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
{
|
||||
auto* parameter = juceParameters.getParamForIndex (i);
|
||||
auto& paramDef = parametersPtr.get()[i];
|
||||
|
||||
const auto nameLength = (size_t) numElementsInArray (paramDef.name);
|
||||
const auto unitLength = (size_t) numElementsInArray (paramDef.unit);
|
||||
|
||||
parameter->getName ((int) nameLength - 1).copyToUTF8 (paramDef.name, nameLength);
|
||||
|
||||
if (parameter->getLabel().isNotEmpty())
|
||||
parameter->getLabel().copyToUTF8 (paramDef.unit, unitLength);
|
||||
|
||||
parameterDescriptions.add (parameter->getName (15));
|
||||
paramDef.description = parameterDescriptions[i].toRawUTF8();
|
||||
|
||||
paramDef.defaultVal = parameter->getDefaultValue();
|
||||
paramDef.min = 0.0f;
|
||||
paramDef.max = 1.0f;
|
||||
paramDef.displayScale = 1.0f;
|
||||
paramDef.displayExponent = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
definition.numParameters = static_cast<uint32> (numParams);
|
||||
definition.parameterDefintions = parametersPtr.get();
|
||||
}
|
||||
|
||||
void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValueNotifyingHost (value); }
|
||||
float getParameter (int index) const noexcept { return juceParameters.getParamForIndex (index)->getValue(); }
|
||||
|
||||
String getParameterString (int index) const noexcept
|
||||
{
|
||||
auto* param = juceParameters.getParamForIndex (index);
|
||||
return param->getText (param->getValue(), 16);
|
||||
}
|
||||
|
||||
int getNumInputChannels() const noexcept { return pluginInstance->getTotalNumInputChannels(); }
|
||||
int getNumOutputChannels() const noexcept { return pluginInstance->getTotalNumOutputChannels(); }
|
||||
|
||||
bool hasEditor() const noexcept { return pluginInstance->hasEditor(); }
|
||||
|
||||
UnityPeer& getEditorPeer() const
|
||||
{
|
||||
auto* peer = dynamic_cast<UnityPeer*> (pluginInstanceEditor->getPeer());
|
||||
|
||||
jassert (peer != nullptr);
|
||||
return *peer;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void processBuffers (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
|
||||
{
|
||||
int ch;
|
||||
for (ch = 0; ch < numInChannels; ++ch)
|
||||
{
|
||||
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
|
||||
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::Const>;
|
||||
|
||||
DstSampleType dstData (scratchBuffer.getWritePointer (ch));
|
||||
SrcSampleType srcData (inBuffer + ch, numInChannels);
|
||||
dstData.convertSamples (srcData, bufferSize);
|
||||
}
|
||||
|
||||
for (; ch < numOutChannels; ++ch)
|
||||
scratchBuffer.clear (ch, 0, bufferSize);
|
||||
|
||||
{
|
||||
const ScopedLock sl (pluginInstance->getCallbackLock());
|
||||
|
||||
if (pluginInstance->isSuspended())
|
||||
{
|
||||
scratchBuffer.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
MidiBuffer mb;
|
||||
|
||||
if (isBypassed && pluginInstance->getBypassParameter() == nullptr)
|
||||
pluginInstance->processBlockBypassed (scratchBuffer, mb);
|
||||
else
|
||||
pluginInstance->processBlock (scratchBuffer, mb);
|
||||
}
|
||||
}
|
||||
|
||||
for (ch = 0; ch < numOutChannels; ++ch)
|
||||
{
|
||||
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst>;
|
||||
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
|
||||
|
||||
DstSampleType dstData (outBuffer + ch, numOutChannels);
|
||||
SrcSampleType srcData (scratchBuffer.getReadPointer (ch));
|
||||
dstData.convertSamples (srcData, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<AudioProcessor> pluginInstance;
|
||||
std::unique_ptr<AudioProcessorEditor> pluginInstanceEditor;
|
||||
|
||||
int samplesPerBlock = 1024;
|
||||
StringArray parameterDescriptions;
|
||||
|
||||
AudioBuffer<float> scratchBuffer;
|
||||
|
||||
LegacyAudioParametersWrapper juceParameters;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static HashMap<int, AudioProcessorUnityWrapper*>& getWrapperMap()
|
||||
{
|
||||
static HashMap<int, AudioProcessorUnityWrapper*> wrapperMap;
|
||||
return wrapperMap;
|
||||
}
|
||||
|
||||
static void onWrapperCreation (AudioProcessorUnityWrapper* wrapperToAdd)
|
||||
{
|
||||
getWrapperMap().set (std::abs (Random::getSystemRandom().nextInt (65536)), wrapperToAdd);
|
||||
}
|
||||
|
||||
static void onWrapperDeletion (AudioProcessorUnityWrapper* wrapperToRemove)
|
||||
{
|
||||
getWrapperMap().removeValue (wrapperToRemove);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static UnityAudioEffectDefinition getEffectDefinition()
|
||||
{
|
||||
const auto wrapper = std::make_unique<AudioProcessorUnityWrapper> (true);
|
||||
const String originalName { JucePlugin_Name };
|
||||
const auto name = (! originalName.startsWithIgnoreCase ("audioplugin") ? "audioplugin_" : "") + originalName;
|
||||
|
||||
UnityAudioEffectDefinition result{};
|
||||
name.copyToUTF8 (result.name, (size_t) numElementsInArray (result.name));
|
||||
|
||||
result.structSize = sizeof (UnityAudioEffectDefinition);
|
||||
result.parameterStructSize = sizeof (UnityAudioParameterDefinition);
|
||||
|
||||
result.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION;
|
||||
result.pluginVersion = JucePlugin_VersionCode;
|
||||
|
||||
// effects must set this to 0, generators > 0
|
||||
result.channels = (wrapper->getNumInputChannels() != 0 ? 0
|
||||
: static_cast<uint32> (wrapper->getNumOutputChannels()));
|
||||
|
||||
wrapper->declareParameters (result);
|
||||
|
||||
result.create = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = new AudioProcessorUnityWrapper (false);
|
||||
pluginInstance->create (state);
|
||||
|
||||
state->effectData = pluginInstance;
|
||||
|
||||
onWrapperCreation (pluginInstance);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.release = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->release();
|
||||
|
||||
onWrapperDeletion (pluginInstance);
|
||||
delete pluginInstance;
|
||||
|
||||
if (getWrapperMap().size() == 0)
|
||||
shutdownJuce_GUI();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.reset = [] (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->reset();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.setPosition = [] (UnityAudioEffectState* state, unsigned int pos)
|
||||
{
|
||||
ignoreUnused (state, pos);
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.process = [] (UnityAudioEffectState* state,
|
||||
float* inBuffer,
|
||||
float* outBuffer,
|
||||
unsigned int bufferSize,
|
||||
int numInChannels,
|
||||
int numOutChannels)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
if (pluginInstance != nullptr)
|
||||
{
|
||||
auto isPlaying = ((state->flags & stateIsPlaying) != 0);
|
||||
auto isMuted = ((state->flags & stateIsMuted) != 0);
|
||||
auto isPaused = ((state->flags & stateIsPaused) != 0);
|
||||
|
||||
const auto bypassed = ! isPlaying || (isMuted || isPaused);
|
||||
pluginInstance->process (inBuffer, outBuffer, static_cast<int> (bufferSize), numInChannels, numOutChannels, bypassed);
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatVectorOperations::clear (outBuffer, static_cast<int> (bufferSize) * numOutChannels);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.setFloatParameter = [] (UnityAudioEffectState* state, int index, float value)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->setParameter (index, value);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.getFloatParameter = [] (UnityAudioEffectState* state, int index, float* value, char* valueStr)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
*value = pluginInstance->getParameter (index);
|
||||
|
||||
pluginInstance->getParameterString (index).copyToUTF8 (valueStr, 15);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
result.getFloatBuffer = [] (UnityAudioEffectState* state, const char* kind, float* buffer, int numSamples)
|
||||
{
|
||||
ignoreUnused (numSamples);
|
||||
|
||||
const StringRef kindStr { kind };
|
||||
|
||||
if (kindStr == StringRef ("Editor"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f;
|
||||
}
|
||||
else if (kindStr == StringRef ("ID"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
for (HashMap<int, AudioProcessorUnityWrapper*>::Iterator i (getWrapperMap()); i.next();)
|
||||
{
|
||||
if (i.getValue() == pluginInstance)
|
||||
{
|
||||
buffer[0] = (float) i.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (kindStr == StringRef ("Size"))
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
auto& editor = pluginInstance->getEditorPeer().getEditor();
|
||||
|
||||
buffer[0] = (float) editor.getBounds().getWidth();
|
||||
buffer[1] = (float) editor.getBounds().getHeight();
|
||||
buffer[2] = (float) editor.getConstrainer()->getMinimumWidth();
|
||||
buffer[3] = (float) editor.getConstrainer()->getMinimumHeight();
|
||||
buffer[4] = (float) editor.getConstrainer()->getMaximumWidth();
|
||||
buffer[5] = (float) editor.getConstrainer()->getMaximumHeight();
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
||||
// From reading the example code, it seems that the triple indirection indicates
|
||||
// an out-value of an array of pointers. That is, after calling this function, definitionsPtr
|
||||
// should point to a pre-existing/static array of pointer-to-effect-definition.
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr)
|
||||
{
|
||||
if (juce::getWrapperMap().size() == 0)
|
||||
juce::initialiseJuce_GUI();
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once (flag, [] { juce::juce_createUnityPeerFn = juce::createUnityPeer; });
|
||||
|
||||
static auto definition = juce::getEffectDefinition();
|
||||
static UnityAudioEffectDefinition* definitions[] { &definition };
|
||||
*definitionsPtr = definitions;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static juce::ModifierKeys unityModifiersToJUCE (UnityEventModifiers mods, bool mouseDown, int mouseButton = -1)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (mouseDown)
|
||||
{
|
||||
if (mouseButton == 0)
|
||||
flags |= juce::ModifierKeys::leftButtonModifier;
|
||||
else if (mouseButton == 1)
|
||||
flags |= juce::ModifierKeys::rightButtonModifier;
|
||||
else if (mouseButton == 2)
|
||||
flags |= juce::ModifierKeys::middleButtonModifier;
|
||||
}
|
||||
|
||||
if (mods == 0)
|
||||
return flags;
|
||||
|
||||
if ((mods & UnityEventModifiers::shift) != 0) flags |= juce::ModifierKeys::shiftModifier;
|
||||
if ((mods & UnityEventModifiers::control) != 0) flags |= juce::ModifierKeys::ctrlModifier;
|
||||
if ((mods & UnityEventModifiers::alt) != 0) flags |= juce::ModifierKeys::altModifier;
|
||||
if ((mods & UnityEventModifiers::command) != 0) flags |= juce::ModifierKeys::commandModifier;
|
||||
|
||||
return { flags };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static juce::AudioProcessorUnityWrapper* getWrapperChecked (int id)
|
||||
{
|
||||
auto* wrapper = juce::getWrapperMap()[id];
|
||||
jassert (wrapper != nullptr);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void UNITY_INTERFACE_API onRenderEvent (int id)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback()
|
||||
{
|
||||
return onRenderEvent;
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityInitialiseTexture (int id, void* data, int w, int h)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast<juce::uint8*> (data), w, h);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers unityMods, int button)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers unityMods, int button)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers unityMods)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, false));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().forwardKeyPress (code, name, unityModifiersToJUCE (mods, false));
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h)
|
||||
{
|
||||
getWrapperChecked (id)->getEditorPeer().getEditor().setBounds ({ (int) x, (int) y, (int) w, (int) h });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_WINDOWS
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
|
||||
|
||||
extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
juce::Process::setCurrentModuleInstanceHandle (instance);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,4 +23,4 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "detail/juce_PluginUtilities.cpp"
|
||||
#include "juce_audio_plugin_client_VST2.cpp"
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -23,6 +23,4 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JucePlugin_Build_VST || JucePlugin_Build_VST3
|
||||
#include "detail/juce_VSTWindowUtilities.mm"
|
||||
#endif
|
||||
#include "juce_audio_plugin_client_VST3.cpp"
|
||||
|
|
@ -27,7 +27,7 @@ extern HWND juce_messageWindowHandle;
|
|||
|
||||
namespace detail
|
||||
{
|
||||
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
|
||||
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
|
||||
bool isRunningInUnity();
|
||||
#else
|
||||
constexpr bool isRunningInUnity() { return false; }
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-function-type")
|
|||
#endif
|
||||
|
||||
void juce_repeatLastProcessPriority();
|
||||
bool juce_isRunningInWine();
|
||||
|
||||
using CheckEventBlockedByModalComps = bool (*) (const MSG&);
|
||||
extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue