git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
194
deps/juce/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h
vendored
Normal file
194
deps/juce/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#define UNITY_AUDIO_PLUGIN_API_VERSION 0x010401
|
||||
|
||||
#if JUCE_MSVC
|
||||
#define UNITY_INTERFACE_API __stdcall
|
||||
#define UNITY_INTERFACE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define UNITY_INTERFACE_API
|
||||
#define UNITY_INTERFACE_EXPORT __attribute__ ((visibility("default")))
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
struct UnityAudioEffectState;
|
||||
|
||||
typedef int (UNITY_INTERFACE_API * createCallback) (UnityAudioEffectState* state);
|
||||
typedef int (UNITY_INTERFACE_API * releaseCallback) (UnityAudioEffectState* state);
|
||||
typedef int (UNITY_INTERFACE_API * resetCallback) (UnityAudioEffectState* state);
|
||||
|
||||
typedef int (UNITY_INTERFACE_API * processCallback) (UnityAudioEffectState* state, float* inBuffer, float* outBuffer, unsigned int bufferSize,
|
||||
int numInChannels, int numOutChannels);
|
||||
|
||||
typedef int (UNITY_INTERFACE_API * setPositionCallback) (UnityAudioEffectState* state, unsigned int pos);
|
||||
|
||||
typedef int (UNITY_INTERFACE_API * setFloatParameterCallback) (UnityAudioEffectState* state, int index, float value);
|
||||
typedef int (UNITY_INTERFACE_API * getFloatParameterCallback) (UnityAudioEffectState* state, int index, float* value, char* valuestr);
|
||||
typedef int (UNITY_INTERFACE_API * getFloatBufferCallback) (UnityAudioEffectState* state, const char* name, float* buffer, int numsamples);
|
||||
|
||||
typedef int (UNITY_INTERFACE_API * distanceAttenuationCallback) (UnityAudioEffectState* state, float distanceIn, float attenuationIn, float* attenuationOut);
|
||||
|
||||
typedef void (UNITY_INTERFACE_API * renderCallback) (int eventId);
|
||||
|
||||
//==============================================================================
|
||||
enum UnityAudioEffectDefinitionFlags
|
||||
{
|
||||
isSideChainTarget = 1,
|
||||
isSpatializer = 2,
|
||||
isAmbisonicDecoder = 4,
|
||||
appliesDistanceAttenuation = 8
|
||||
};
|
||||
|
||||
enum UnityAudioEffectStateFlags
|
||||
{
|
||||
stateIsPlaying = 1,
|
||||
stateIsPaused = 2,
|
||||
stateIsMuted = 8,
|
||||
statIsSideChainTarget = 16
|
||||
};
|
||||
|
||||
enum UnityEventModifiers
|
||||
{
|
||||
shift = 1,
|
||||
control = 2,
|
||||
alt = 4,
|
||||
command = 8,
|
||||
numeric = 16,
|
||||
capsLock = 32,
|
||||
functionKey = 64
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
|
||||
struct UnityAudioSpatializerData
|
||||
{
|
||||
float listenerMatrix[16];
|
||||
float sourceMatrix[16];
|
||||
float spatialBlend;
|
||||
float reverbZoneMix;
|
||||
float spread;
|
||||
float stereoPan;
|
||||
distanceAttenuationCallback attenuationCallback;
|
||||
float minDistance;
|
||||
float maxDistance;
|
||||
};
|
||||
|
||||
struct UnityAudioAmbisonicData
|
||||
{
|
||||
float listenerMatrix[16];
|
||||
float sourceMatrix[16];
|
||||
float spatialBlend;
|
||||
float reverbZoneMix;
|
||||
float spread;
|
||||
float stereoPan;
|
||||
distanceAttenuationCallback attenuationCallback;
|
||||
int ambisonicOutChannels;
|
||||
float volume;
|
||||
};
|
||||
|
||||
struct UnityAudioEffectState
|
||||
{
|
||||
juce::uint32 structSize;
|
||||
juce::uint32 sampleRate;
|
||||
juce::uint64 dspCurrentTick;
|
||||
juce::uint64 dspPreviousTick;
|
||||
float* sidechainBuffer;
|
||||
void* effectData;
|
||||
juce::uint32 flags;
|
||||
void* internal;
|
||||
|
||||
UnityAudioSpatializerData* spatializerData;
|
||||
juce::uint32 dspBufferSize;
|
||||
juce::uint32 hostAPIVersion;
|
||||
|
||||
UnityAudioAmbisonicData* ambisonicData;
|
||||
|
||||
template <typename T>
|
||||
inline T* getEffectData() const
|
||||
{
|
||||
jassert (effectData != nullptr);
|
||||
jassert (internal != nullptr);
|
||||
|
||||
return (T*) effectData;
|
||||
}
|
||||
};
|
||||
|
||||
struct UnityAudioParameterDefinition
|
||||
{
|
||||
char name[16];
|
||||
char unit[16];
|
||||
const char* description;
|
||||
float min;
|
||||
float max;
|
||||
float defaultVal;
|
||||
float displayScale;
|
||||
float displayExponent;
|
||||
};
|
||||
|
||||
struct UnityAudioEffectDefinition
|
||||
{
|
||||
juce::uint32 structSize;
|
||||
juce::uint32 parameterStructSize;
|
||||
juce::uint32 apiVersion;
|
||||
juce::uint32 pluginVersion;
|
||||
juce::uint32 channels;
|
||||
juce::uint32 numParameters;
|
||||
juce::uint64 flags;
|
||||
char name[32];
|
||||
createCallback create;
|
||||
releaseCallback release;
|
||||
resetCallback reset;
|
||||
processCallback process;
|
||||
setPositionCallback setPosition;
|
||||
UnityAudioParameterDefinition* parameterDefintions;
|
||||
setFloatParameterCallback setFloatParameter;
|
||||
getFloatParameterCallback getFloatParameter;
|
||||
getFloatBufferCallback getFloatBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// Unity callback
|
||||
extern "C" UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr);
|
||||
|
||||
// GUI script callbacks
|
||||
extern "C" UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback();
|
||||
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityInitialiseTexture (int id, void* textureHandle, int w, int h);
|
||||
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers mods, int button);
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers mods, int button);
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers mods);
|
||||
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name);
|
||||
|
||||
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h);
|
781
deps/juce/modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp
vendored
Normal file
781
deps/juce/modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp
vendored
Normal file
@ -0,0 +1,781 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#if JucePlugin_Build_Unity
|
||||
|
||||
#include "../utility/juce_IncludeModuleHeaders.h"
|
||||
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include "../utility/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::invalidPressure,
|
||||
juce::MouseInputSource::invalidOrientation, 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, Image::BitmapData::ReadWriteMode mode) override
|
||||
{
|
||||
ignoreUnused (mode);
|
||||
|
||||
bitmap.data = imageData + x * pixelStride + y * lineStride;
|
||||
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::invalidPressure, juce::MouseInputSource::invalidOrientation, 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; }
|
||||
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)
|
||||
};
|
||||
|
||||
ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); }
|
||||
|
||||
//==============================================================================
|
||||
class AudioProcessorUnityWrapper
|
||||
{
|
||||
public:
|
||||
AudioProcessorUnityWrapper (bool isTemporary)
|
||||
{
|
||||
pluginInstance.reset (createPluginFilterOfType (AudioProcessor::wrapperType_Unity));
|
||||
|
||||
if (! isTemporary && pluginInstance->hasEditor())
|
||||
{
|
||||
pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded());
|
||||
pluginInstanceEditor->setVisible (true);
|
||||
pluginInstanceEditor->addToDesktop (0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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->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)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
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);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace UnityCallbacks
|
||||
{
|
||||
int UNITY_INTERFACE_API createCallback (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = new AudioProcessorUnityWrapper (false);
|
||||
pluginInstance->create (state);
|
||||
|
||||
state->effectData = pluginInstance;
|
||||
|
||||
onWrapperCreation (pluginInstance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API releaseCallback (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->release();
|
||||
|
||||
onWrapperDeletion (pluginInstance);
|
||||
delete pluginInstance;
|
||||
|
||||
if (getWrapperMap().size() == 0)
|
||||
shutdownJuce_GUI();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API resetCallback (UnityAudioEffectState* state)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API setPositionCallback (UnityAudioEffectState* state, unsigned int pos)
|
||||
{
|
||||
ignoreUnused (state, pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API setFloatParameterCallback (UnityAudioEffectState* state, int index, float value)
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
pluginInstance->setParameter (index, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API getFloatParameterCallback (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;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API getFloatBufferCallback (UnityAudioEffectState* state, const char* name, float* buffer, int numSamples)
|
||||
{
|
||||
ignoreUnused (numSamples);
|
||||
|
||||
auto nameStr = String (name);
|
||||
|
||||
if (nameStr == "Editor")
|
||||
{
|
||||
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
|
||||
|
||||
buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f;
|
||||
}
|
||||
else if (nameStr == "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 (nameStr == "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;
|
||||
}
|
||||
|
||||
int UNITY_INTERFACE_API processCallback (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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void declareEffect (UnityAudioEffectDefinition& definition)
|
||||
{
|
||||
memset (&definition, 0, sizeof (definition));
|
||||
|
||||
std::unique_ptr<AudioProcessorUnityWrapper> wrapper = std::make_unique<AudioProcessorUnityWrapper> (true);
|
||||
|
||||
String name (JucePlugin_Name);
|
||||
if (! name.startsWithIgnoreCase ("audioplugin"))
|
||||
name = "audioplugin_" + name;
|
||||
|
||||
name.copyToUTF8 (definition.name, (size_t) numElementsInArray (definition.name));
|
||||
|
||||
definition.structSize = sizeof (UnityAudioEffectDefinition);
|
||||
definition.parameterStructSize = sizeof (UnityAudioParameterDefinition);
|
||||
|
||||
definition.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION;
|
||||
definition.pluginVersion = JucePlugin_VersionCode;
|
||||
|
||||
// effects must set this to 0, generators > 0
|
||||
definition.channels = (wrapper->getNumInputChannels() != 0 ? 0
|
||||
: static_cast<uint32> (wrapper->getNumOutputChannels()));
|
||||
|
||||
wrapper->declareParameters (definition);
|
||||
|
||||
definition.create = UnityCallbacks::createCallback;
|
||||
definition.release = UnityCallbacks::releaseCallback;
|
||||
definition.reset = UnityCallbacks::resetCallback;
|
||||
definition.setPosition = UnityCallbacks::setPositionCallback;
|
||||
definition.process = UnityCallbacks::processCallback;
|
||||
definition.setFloatParameter = UnityCallbacks::setFloatParameterCallback;
|
||||
definition.getFloatParameter = UnityCallbacks::getFloatParameterCallback;
|
||||
definition.getFloatBuffer = UnityCallbacks::getFloatBufferCallback;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
||||
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr)
|
||||
{
|
||||
if (juce::getWrapperMap().size() == 0)
|
||||
juce::initialiseJuce_GUI();
|
||||
|
||||
static bool hasInitialised = false;
|
||||
|
||||
if (! hasInitialised)
|
||||
{
|
||||
juce::PluginHostType::jucePlugInClientCurrentWrapperType = juce::AudioProcessor::wrapperType_Unity;
|
||||
juce::juce_createUnityPeerFn = juce::createUnityPeer;
|
||||
|
||||
hasInitialised = true;
|
||||
}
|
||||
|
||||
auto* definition = new UnityAudioEffectDefinition();
|
||||
juce::declareEffect (*definition);
|
||||
|
||||
*definitionsPtr = &definition;
|
||||
|
||||
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
|
||||
extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
juce::Process::setCurrentModuleInstanceHandle (instance);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user