|
- /*
- ==============================================================================
-
- 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]);
-
- jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
-
- ignoreUnused (numConfigs);
-
- 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 = juceParameters.params.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.params[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
|