|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- JUCE is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
- */
-
- /*
- *** DON't EDIT THIS FILE!! ***
-
- The idea is that everyone's plugins should share this same wrapper
- code, so if you start hacking around in here you're missing the point!
-
- If there's a bug or a function you need that can't be done without changing
- some of the code in here, give me a shout so we can add it to the library,
- rather than branching off and going it alone!
- */
-
-
- //==============================================================================
- #ifdef _MSC_VER
- #pragma warning (disable : 4996)
- #endif
-
- #ifdef _WIN32
- #include <windows.h>
- #elif defined (LINUX)
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xatom.h>
- #undef KeyPress
- #else
- #include <Carbon/Carbon.h>
- #endif
-
- #ifdef PRAGMA_ALIGN_SUPPORTED
- #undef PRAGMA_ALIGN_SUPPORTED
- #define PRAGMA_ALIGN_SUPPORTED 1
- #endif
-
- #include "../../juce_IncludeCharacteristics.h"
-
- //==============================================================================
- /* These files come with the Steinberg VST SDK - to get them, you'll need to
- visit the Steinberg website and jump through some hoops to sign up as a
- VST developer.
-
- Then, you'll need to make sure your include path contains your "vstsdk2.3" or
- "vstsdk2.4" directory.
-
- Note that the JUCE_USE_VSTSDK_2_4 macro should be defined in JucePluginCharacteristics.h
- */
- #if JUCE_USE_VSTSDK_2_4
- // VSTSDK V2.4 includes..
- #include "public.sdk/source/vst2.x/audioeffectx.h"
- #include "public.sdk/source/vst2.x/aeffeditor.h"
- #include "public.sdk/source/vst2.x/audioeffectx.cpp"
- #include "public.sdk/source/vst2.x/audioeffect.cpp"
- #else
- // VSTSDK V2.3 includes..
- #include "source/common/audioeffectx.h"
- #include "source/common/AEffEditor.hpp"
- #include "source/common/audioeffectx.cpp"
- #include "source/common/AudioEffect.cpp"
- typedef long VstInt32;
- typedef long VstIntPtr;
- #endif
-
- //==============================================================================
- #include "../../juce_AudioFilterBase.h"
- #undef MemoryBlock
-
- class JuceVSTWrapper;
- static bool recursionCheck = false;
- static uint32 lastMasterIdleCall = 0;
-
- BEGIN_JUCE_NAMESPACE
- extern void juce_callAnyTimersSynchronously();
-
- #if JUCE_LINUX
- extern Display* display;
- extern bool juce_postMessageToSystemQueue (void* message);
- #endif
- END_JUCE_NAMESPACE
-
-
- //==============================================================================
- #if JUCE_WIN32
-
- static HWND findMDIParentOf (HWND w)
- {
- const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME);
-
- while (w != 0)
- {
- HWND parent = GetParent (w);
-
- if (parent == 0)
- break;
-
- TCHAR windowType [32];
- zeromem (windowType, sizeof (windowType));
- GetClassName (parent, windowType, 31);
-
- if (String (windowType).equalsIgnoreCase (T("MDIClient")))
- {
- w = parent;
- break;
- }
-
- RECT windowPos;
- GetWindowRect (w, &windowPos);
-
- RECT parentPos;
- GetWindowRect (parent, &parentPos);
-
- int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left);
- int dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top);
-
- if (dw > 100 || dh > 100)
- break;
-
- w = parent;
-
- if (dw == 2 * frameThickness)
- break;
- }
-
- return w;
- }
-
- //==============================================================================
- #elif JUCE_LINUX
-
- class SharedMessageThread : public Thread
- {
- public:
- SharedMessageThread()
- : Thread (T("VstMessageThread"))
- {
- startThread (7);
- }
-
- ~SharedMessageThread()
- {
- signalThreadShouldExit();
-
- const int quitMessageId = 0xfffff321;
- Message* const m = new Message (quitMessageId, 1, 0, 0);
-
- if (! juce_postMessageToSystemQueue (m))
- delete m;
-
- clearSingletonInstance();
- }
-
- void run()
- {
- MessageManager* const messageManager = MessageManager::getInstance();
-
- const int originalThreadId = messageManager->getCurrentMessageThread();
- messageManager->setCurrentMessageThread (getThreadId());
-
- while (! threadShouldExit()
- && messageManager->dispatchNextMessage())
- {
- }
-
- messageManager->setCurrentMessageThread (originalThreadId);
- }
-
- juce_DeclareSingleton (SharedMessageThread, false)
- };
-
- juce_ImplementSingleton (SharedMessageThread);
-
- #endif
-
- //==============================================================================
- // A component to hold the AudioFilterEditor, and cope with some housekeeping
- // chores when it changes or repaints.
- class EditorCompWrapper : public Component,
- public AsyncUpdater
- {
- JuceVSTWrapper* wrapper;
-
- public:
- EditorCompWrapper (JuceVSTWrapper* const wrapper_,
- AudioFilterEditor* const editor)
- : wrapper (wrapper_)
- {
- setOpaque (true);
- editor->setOpaque (true);
-
- setBounds (editor->getBounds());
- editor->setTopLeftPosition (0, 0);
- addAndMakeVisible (editor);
-
- #if JUCE_WIN32
- addMouseListener (this, true);
- #endif
- }
-
- ~EditorCompWrapper()
- {
- deleteAllChildren();
- }
-
- void paint (Graphics& g)
- {
- }
-
- void paintOverChildren (Graphics& g)
- {
- // this causes an async call to masterIdle() to help
- // creaky old DAWs like Nuendo repaint themselves while we're
- // repainting. Otherwise they just seem to give up and sit there
- // waiting.
- triggerAsyncUpdate();
- }
-
- AudioFilterEditor* getEditorComp() const
- {
- return dynamic_cast <AudioFilterEditor*> (getChildComponent (0));
- }
-
- void resized()
- {
- Component* const c = getChildComponent (0);
-
- if (c != 0)
- {
- #if JUCE_LINUX
- const MessageManagerLock mml;
- #endif
- c->setBounds (0, 0, getWidth(), getHeight());
- }
- }
-
- void childBoundsChanged (Component* child);
- void handleAsyncUpdate();
-
- #if JUCE_WIN32
- void mouseDown (const MouseEvent&)
- {
- broughtToFront();
- }
-
- void broughtToFront()
- {
- // for hosts like nuendo, need to also pop the MDI container to the
- // front when our comp is clicked on.
- HWND parent = findMDIParentOf ((HWND) getWindowHandle());
-
- if (parent != 0)
- {
- SetWindowPos (parent,
- HWND_TOP,
- 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE);
- }
- }
- #endif
-
- //==============================================================================
- juce_UseDebuggingNewOperator
- };
-
- static VoidArray activePlugins;
-
-
- //==============================================================================
- /**
- This wraps an AudioFilterBase as an AudioEffectX...
- */
- class JuceVSTWrapper : public AudioEffectX,
- private Timer,
- public AudioFilterBase::HostCallbacks
- {
- public:
- //==============================================================================
- JuceVSTWrapper (audioMasterCallback audioMaster,
- AudioFilterBase* const filter_)
- : AudioEffectX (audioMaster,
- filter_->getNumPrograms(),
- filter_->getNumParameters()),
- filter (filter_)
- {
- filter->setPlayConfigDetails (JucePlugin_MaxNumInputChannels,
- JucePlugin_MaxNumOutputChannels,
- 0, 0);
-
- filter_->setHostCallbacks (this);
-
- editorComp = 0;
- outgoingEvents = 0;
- outgoingEventSize = 0;
- chunkMemoryTime = 0;
- isProcessing = false;
- firstResize = true;
- channels = 0;
-
- #if JUCE_MAC || JUCE_LINUX
- hostWindow = 0;
- #endif
-
- cEffect.flags |= effFlagsHasEditor;
-
- setUniqueID ((int) (JucePlugin_VSTUniqueID));
- getAeffect()->version = (long) (JucePlugin_VersionCode);
-
- #if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4
- wantEvents();
- #endif
-
- setNumInputs (filter->getNumInputChannels());
- setNumOutputs (filter->getNumOutputChannels());
-
- canProcessReplacing (true);
-
- #if ! JUCE_USE_VSTSDK_2_4
- hasVu (false);
- hasClip (false);
- #endif
-
- isSynth ((JucePlugin_IsSynth) != 0);
- noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0);
- setInitialDelay (JucePlugin_Latency);
- programsAreChunks (true);
-
- activePlugins.add (this);
- }
-
- ~JuceVSTWrapper()
- {
- stopTimer();
- deleteEditor();
-
- delete filter;
- filter = 0;
-
- if (outgoingEvents != 0)
- {
- for (int i = outgoingEventSize; --i >= 0;)
- juce_free (outgoingEvents->events[i]);
-
- juce_free (outgoingEvents);
- outgoingEvents = 0;
- }
-
- jassert (editorComp == 0);
-
- jassert (activePlugins.contains (this));
- activePlugins.removeValue (this);
-
- juce_free (channels);
-
- #if JUCE_MAC || JUCE_LINUX
- if (activePlugins.size() == 0)
- {
- #if JUCE_LINUX
- SharedMessageThread::deleteInstance();
- #endif
- shutdownJuce_GUI();
- }
- #endif
- }
-
- void open()
- {
- startTimer (1000 / 4);
- }
-
- void close()
- {
- jassert (! recursionCheck);
-
- stopTimer();
- deleteEditor();
- }
-
- //==============================================================================
- bool getEffectName (char* name)
- {
- String (JucePlugin_Name).copyToBuffer (name, 64);
- return true;
- }
-
- bool getVendorString (char* text)
- {
- String (JucePlugin_Manufacturer).copyToBuffer (text, 64);
- return true;
- }
-
- bool getProductString (char* text)
- {
- return getEffectName (text);
- }
-
- VstInt32 getVendorVersion()
- {
- return JucePlugin_VersionCode;
- }
-
- VstPlugCategory getPlugCategory()
- {
- return JucePlugin_VSTCategory;
- }
-
- VstInt32 canDo (char* text)
- {
- VstInt32 result = 0;
-
- if (strcmp (text, "receiveVstEvents") == 0
- || strcmp (text, "receiveVstMidiEvent") == 0
- || strcmp (text, "receiveVstMidiEvents") == 0)
- {
- #if JucePlugin_WantsMidiInput
- result = 1;
- #else
- result = -1;
- #endif
- }
- else if (strcmp (text, "sendVstEvents") == 0
- || strcmp (text, "sendVstMidiEvent") == 0
- || strcmp (text, "sendVstMidiEvents") == 0)
- {
- #if JucePlugin_ProducesMidiOutput
- result = 1;
- #else
- result = -1;
- #endif
- }
- else if (strcmp (text, "receiveVstTimeInfo") == 0)
- {
- result = 1;
- }
- else if (strcmp (text, "conformsToWindowRules") == 0)
- {
- result = 1;
- }
-
- return result;
- }
-
- bool keysRequired()
- {
- return (JucePlugin_EditorRequiresKeyboardFocus) != 0;
- }
-
- bool getInputProperties (VstInt32 index, VstPinProperties* properties)
- {
- const String name (filter->getInputChannelName ((int) index));
-
- name.copyToBuffer (properties->label, kVstMaxLabelLen - 1);
- name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1);
-
- properties->flags = kVstPinIsActive;
-
- if (filter->isInputChannelStereoPair ((int) index))
- properties->flags |= kVstPinIsStereo;
-
- properties->arrangementType = 0;
-
- return true;
- }
-
- bool getOutputProperties (VstInt32 index, VstPinProperties* properties)
- {
- const String name (filter->getOutputChannelName ((int) index));
-
- name.copyToBuffer (properties->label, kVstMaxLabelLen - 1);
- name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1);
-
- properties->flags = kVstPinIsActive;
-
- if (filter->isOutputChannelStereoPair ((int) index))
- properties->flags |= kVstPinIsStereo;
-
- properties->arrangementType = 0;
-
- return true;
- }
-
- //==============================================================================
- VstInt32 processEvents (VstEvents* events)
- {
- #if JucePlugin_WantsMidiInput
- for (int i = 0; i < events->numEvents; ++i)
- {
- const VstEvent* const e = events->events[i];
-
- if (e != 0 && e->type == kVstMidiType)
- {
- const VstMidiEvent* const vme = (const VstMidiEvent*) e;
-
- midiEvents.addEvent ((const uint8*) vme->midiData,
- 4,
- vme->deltaFrames);
- }
- }
-
- return 1;
- #else
- return 0;
- #endif
- }
-
- void process (float** inputs, float** outputs, VstInt32 numSamples)
- {
- const int numIn = filter->getNumInputChannels();
- const int numOut = filter->getNumOutputChannels();
-
- AudioSampleBuffer temp (numIn, numSamples);
- int i;
- for (i = numIn; --i >= 0;)
- memcpy (temp.getSampleData (i), outputs[i], sizeof (float) * numSamples);
-
- processReplacing (inputs, outputs, numSamples);
-
- AudioSampleBuffer dest (outputs, numOut, numSamples);
-
- for (i = jmin (numIn, numOut); --i >= 0;)
- dest.addFrom (i, 0, temp, i, 0, numSamples);
- }
-
- void processReplacing (float** inputs, float** outputs, VstInt32 numSamples)
- {
- //process (inputs, outputs, numSamples, false);
- // if this fails, the host hasn't called resume() before processing
- jassert (isProcessing);
-
- // (tragically, some hosts actually need this, although it's stupid to have
- // to do it here..)
- if (! isProcessing)
- resume();
-
- #if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput
- const int numMidiEventsComingIn = midiEvents.getNumEvents();
- #endif
-
- jassert (activePlugins.contains (this));
-
- {
- const ScopedLock sl (filter->getCallbackLock());
-
- const int numIn = filter->getNumInputChannels();
- const int numOut = filter->getNumOutputChannels();
- const int totalChans = jmax (numIn, numOut);
-
- if (filter->isSuspended())
- {
- for (int i = 0; i < numOut; ++i)
- zeromem (outputs [i], sizeof (float) * numSamples);
- }
- else
- {
- {
- int i;
- for (i = 0; i < numOut; ++i)
- {
- channels[i] = outputs [i];
-
- if (i < numIn && inputs != outputs)
- memcpy (outputs [i], inputs[i], sizeof (float) * numSamples);
- }
-
- for (; i < numIn; ++i)
- channels [i] = inputs [i];
- }
-
- AudioSampleBuffer chans (channels, totalChans, numSamples);
-
- filter->processBlock (chans, midiEvents);
- }
- }
-
- if (! midiEvents.isEmpty())
- {
- #if JucePlugin_ProducesMidiOutput
- const int numEvents = midiEvents.getNumEvents();
-
- ensureOutgoingEventSize (numEvents);
- outgoingEvents->numEvents = 0;
-
- const uint8* midiEventData;
- int midiEventSize, midiEventPosition;
- MidiBuffer::Iterator i (midiEvents);
-
- while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
- {
- if (midiEventSize <= 4)
- {
- VstMidiEvent* const vme = (VstMidiEvent*) outgoingEvents->events [outgoingEvents->numEvents++];
-
- memcpy (vme->midiData, midiEventData, midiEventSize);
- vme->deltaFrames = midiEventPosition;
-
- jassert (vme->deltaFrames >= 0 && vme->deltaFrames < numSamples);
- }
- }
-
- sendVstEventsToHost (outgoingEvents);
- #else
- /* This assertion is caused when you've added some events to the
- midiMessages array in your processBlock() method, which usually means
- that you're trying to send them somewhere. But in this case they're
- getting thrown away.
-
- If your plugin does want to send midi messages, you'll need to set
- the JucePlugin_ProducesMidiOutput macro to 1 in your
- JucePluginCharacteristics.h file.
-
- If you don't want to produce any midi output, then you should clear the
- midiMessages array at the end of your processBlock() method, to
- indicate that you don't want any of the events to be passed through
- to the output.
- */
- jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn);
- #endif
-
- midiEvents.clear();
- }
- }
-
- //==============================================================================
- void resume()
- {
- isProcessing = true;
- juce_free (channels);
- channels = (float**) juce_calloc (sizeof (float*) * jmax (filter->getNumInputChannels(), filter->getNumOutputChannels()));
-
- double rate = getSampleRate();
- jassert (rate > 0);
- if (rate <= 0.0)
- rate = 44100.0;
-
- const int blockSize = getBlockSize();
- jassert (blockSize > 0);
-
- filter->setPlayConfigDetails (JucePlugin_MaxNumInputChannels,
- JucePlugin_MaxNumOutputChannels,
- rate, blockSize);
-
- filter->prepareToPlay (rate, blockSize);
- midiEvents.clear();
-
- AudioEffectX::resume();
-
- #if JucePlugin_ProducesMidiOutput
- ensureOutgoingEventSize (64);
- #endif
-
- #if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4
- wantEvents();
- #endif
- }
-
- void suspend()
- {
- AudioEffectX::suspend();
-
- filter->releaseResources();
- midiEvents.clear();
-
- isProcessing = false;
- juce_free (channels);
- channels = 0;
- }
-
- bool JUCE_CALLTYPE getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info)
- {
- const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid
- | kVstTempoValid
- | kVstBarsValid
- //| kVstCyclePosValid
- | kVstTimeSigValid
- | kVstSmpteValid
- | kVstClockValid);
-
- if (ti == 0 || ti->sampleRate <= 0)
- return false;
-
- if ((ti->flags & kVstTempoValid) != 0)
- info.bpm = ti->tempo;
- else
- info.bpm = 0.0;
-
- if ((ti->flags & kVstTimeSigValid) != 0)
- {
- info.timeSigNumerator = ti->timeSigNumerator;
- info.timeSigDenominator = ti->timeSigDenominator;
- }
- else
- {
- info.timeSigNumerator = 4;
- info.timeSigDenominator = 4;
- }
-
- info.timeInSeconds = ti->samplePos / ti->sampleRate;
-
- if ((ti->flags & kVstPpqPosValid) != 0)
- info.ppqPosition = ti->ppqPos;
- else
- info.ppqPosition = 0.0;
-
- if ((ti->flags & kVstBarsValid) != 0)
- info.ppqPositionOfLastBarStart = ti->barStartPos;
- else
- info.ppqPositionOfLastBarStart = 0.0;
-
- if ((ti->flags & kVstSmpteValid) != 0)
- {
- info.frameRate = (AudioFilterBase::CurrentPositionInfo::FrameRateType) (int) ti->smpteFrameRate;
-
- const double fpsDivisors[] = { 24.0, 25.0, 30.0, 30.0, 30.0, 30.0, 1.0 };
- info.editOriginTime = (ti->smpteOffset / (80.0 * fpsDivisors [(int) info.frameRate]));
- }
- else
- {
- info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown;
- info.editOriginTime = 0;
- }
-
- info.isRecording = (ti->flags & kVstTransportRecording) != 0;
- info.isPlaying = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording;
-
- return true;
- }
-
- //==============================================================================
- VstInt32 getProgram()
- {
- return filter->getCurrentProgram();
- }
-
- void setProgram (VstInt32 program)
- {
- filter->setCurrentProgram (program);
- }
-
- void setProgramName (char* name)
- {
- filter->changeProgramName (filter->getCurrentProgram(), name);
- }
-
- void getProgramName (char* name)
- {
- filter->getProgramName (filter->getCurrentProgram()).copyToBuffer (name, 24);
- }
-
- bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text)
- {
- if (index >= 0 && index < filter->getNumPrograms())
- {
- filter->getProgramName (index).copyToBuffer (text, 24);
- return true;
- }
-
- return false;
- }
-
- //==============================================================================
- float getParameter (VstInt32 index)
- {
- jassert (index >= 0 && index < filter->getNumParameters());
- return filter->getParameter (index);
- }
-
- void setParameter (VstInt32 index, float value)
- {
- jassert (index >= 0 && index < filter->getNumParameters());
- filter->setParameter (index, value);
- }
-
- void getParameterDisplay (VstInt32 index, char* text)
- {
- jassert (index >= 0 && index < filter->getNumParameters());
- filter->getParameterText (index).copyToBuffer (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
- }
-
- void getParameterName (VstInt32 index, char* text)
- {
- jassert (index >= 0 && index < filter->getNumParameters());
- filter->getParameterName (index).copyToBuffer (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
- }
-
- void JUCE_CALLTYPE informHostOfParameterChange (int index, float newValue)
- {
- setParameterAutomated (index, newValue);
- }
-
- void JUCE_CALLTYPE informHostOfStateChange()
- {
- updateDisplay();
- }
-
- bool canParameterBeAutomated (VstInt32 index)
- {
- return filter->isParameterAutomatable ((int) index);
- }
-
- //==============================================================================
- VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData)
- {
- chunkMemory.setSize (0);
- if (onlyStoreCurrentProgramData)
- filter->getCurrentProgramStateInformation (chunkMemory);
- else
- filter->getStateInformation (chunkMemory);
-
- *data = (void*) chunkMemory;
-
- // because the chunk is only needed temporarily by the host (or at least you'd
- // hope so) we'll give it a while and then free it in the timer callback.
- chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter();
-
- return chunkMemory.getSize();
- }
-
- VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData)
- {
- chunkMemory.setSize (0);
- chunkMemoryTime = 0;
-
- if (byteSize > 0 && data != 0)
- {
- if (onlyRestoreCurrentProgramData)
- filter->setCurrentProgramStateInformation (data, byteSize);
- else
- filter->setStateInformation (data, byteSize);
- }
-
- return 0;
- }
-
- void timerCallback()
- {
- if (chunkMemoryTime > 0
- && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000
- && ! recursionCheck)
- {
- chunkMemoryTime = 0;
- chunkMemory.setSize (0);
- }
-
- tryMasterIdle();
- }
-
- void tryMasterIdle()
- {
- if (Component::isMouseButtonDownAnywhere()
- && ! recursionCheck)
- {
- const uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter();
-
- if (now > lastMasterIdleCall + 20 && editorComp != 0)
- {
- lastMasterIdleCall = now;
-
- recursionCheck = true;
- masterIdle();
- recursionCheck = false;
- }
- }
- }
-
- void doIdleCallback()
- {
- // (wavelab calls this on a separate thread and causes a deadlock)..
- if (MessageManager::getInstance()->isThisTheMessageThread())
- {
- if (! recursionCheck)
- {
- const MessageManagerLock mml;
-
- recursionCheck = true;
-
- juce_callAnyTimersSynchronously();
-
- for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
- ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow();
-
- recursionCheck = false;
- }
- }
- }
-
- void createEditorComp()
- {
- if (editorComp == 0)
- {
- #if JUCE_LINUX
- const MessageManagerLock mml;
- #endif
-
- AudioFilterEditor* const ed = filter->createEditorIfNeeded();
-
- if (ed != 0)
- {
- ed->setOpaque (true);
- ed->setVisible (true);
-
- editorComp = new EditorCompWrapper (this, ed);
- }
- }
- }
-
- void deleteEditor()
- {
- PopupMenu::dismissAllActiveMenus();
-
- jassert (! recursionCheck);
- recursionCheck = true;
-
- #if JUCE_LINUX
- const MessageManagerLock mml;
- #endif
-
- if (editorComp != 0)
- {
- Component* const modalComponent = Component::getCurrentlyModalComponent();
- if (modalComponent != 0)
- modalComponent->exitModalState (0);
-
- filter->editorBeingDeleted (editorComp->getEditorComp());
-
- deleteAndZero (editorComp);
-
- // there's some kind of component currently modal, but the host
- // is trying to delete our plugin. You should try to avoid this happening..
- jassert (Component::getCurrentlyModalComponent() == 0);
- }
-
- #if JUCE_MAC || JUCE_LINUX
- hostWindow = 0;
- #endif
-
- recursionCheck = false;
- }
-
- VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt)
- {
- if (opCode == effEditIdle)
- {
- doIdleCallback();
- return 0;
- }
- else if (opCode == effEditOpen)
- {
- jassert (! recursionCheck);
-
- deleteEditor();
- createEditorComp();
-
- if (editorComp != 0)
- {
- #if JUCE_LINUX
- const MessageManagerLock mml;
- #endif
-
- editorComp->setOpaque (true);
- editorComp->setVisible (false);
-
- #if JUCE_WIN32
- editorComp->addToDesktop (0);
-
- hostWindow = (HWND) ptr;
- HWND editorWnd = (HWND) editorComp->getWindowHandle();
-
- SetParent (editorWnd, hostWindow);
-
- DWORD val = GetWindowLong (editorWnd, GWL_STYLE);
- val = (val & ~WS_POPUP) | WS_CHILD;
- SetWindowLong (editorWnd, GWL_STYLE, val);
-
- editorComp->setVisible (true);
- #elif JUCE_LINUX
- editorComp->addToDesktop (0);
-
- hostWindow = (Window) ptr;
-
- Window editorWnd = (Window) editorComp->getWindowHandle();
-
- XReparentWindow (display, editorWnd, hostWindow, 0, 0);
-
- editorComp->setVisible (true);
- #else
- hostWindow = (WindowRef) ptr;
- firstResize = true;
-
- SetAutomaticControlDragTrackingEnabledForWindow (hostWindow, true);
-
- WindowAttributes attributes;
- GetWindowAttributes (hostWindow, &attributes);
-
- HIViewRef parentView = 0;
-
- if ((attributes & kWindowCompositingAttribute) != 0)
- {
- HIViewRef root = HIViewGetRoot (hostWindow);
- HIViewFindByID (root, kHIViewWindowContentID, &parentView);
-
- if (parentView == 0)
- parentView = root;
- }
- else
- {
- GetRootControl (hostWindow, (ControlRef*) &parentView);
-
- if (parentView == 0)
- CreateRootControl (hostWindow, (ControlRef*) &parentView);
- }
-
- jassert (parentView != 0); // agh - the host has to provide a compositing window..
-
- editorComp->setVisible (true);
- editorComp->addToDesktop (0, (void*) parentView);
- #endif
-
- return 1;
- }
- }
- else if (opCode == effEditClose)
- {
- deleteEditor();
- return 0;
- }
- else if (opCode == effEditGetRect)
- {
- createEditorComp();
-
- if (editorComp != 0)
- {
- editorSize.left = 0;
- editorSize.top = 0;
- editorSize.right = editorComp->getWidth();
- editorSize.bottom = editorComp->getHeight();
-
- *((ERect**) ptr) = &editorSize;
-
- return (VstIntPtr) &editorSize;
- }
- else
- {
- return 0;
- }
- }
-
- return AudioEffectX::dispatcher (opCode, index, value, ptr, opt);
- }
-
- void resizeHostWindow (int newWidth, int newHeight)
- {
- if (editorComp != 0)
- {
- #if ! JUCE_LINUX // linux hosts shouldn't be trusted!
- if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight)))
- #endif
- {
- // some hosts don't support the sizeWindow call, so do it manually..
- #if JUCE_MAC
- Rect r;
- GetWindowBounds (hostWindow, kWindowContentRgn, &r);
-
- if (firstResize)
- {
- diffW = (r.right - r.left) - editorComp->getWidth();
- diffH = (r.bottom - r.top) - editorComp->getHeight();
- firstResize = false;
- }
-
- r.right = r.left + newWidth + diffW;
- r.bottom = r.top + newHeight + diffH;
-
- SetWindowBounds (hostWindow, kWindowContentRgn, &r);
-
- r.bottom -= r.top;
- r.right -= r.left;
- r.left = r.top = 0;
- InvalWindowRect (hostWindow, &r);
- #elif JUCE_LINUX
- Window root;
- int x, y;
- unsigned int width, height, border, depth;
-
- XGetGeometry (display, hostWindow, &root,
- &x, &y, &width, &height, &border, &depth);
-
- newWidth += (width + border) - editorComp->getWidth();
- newHeight += (height + border) - editorComp->getHeight();
-
- XResizeWindow (display, hostWindow, newWidth, newHeight);
- #else
- int dw = 0;
- int dh = 0;
- const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME);
-
- HWND w = (HWND) editorComp->getWindowHandle();
-
- while (w != 0)
- {
- HWND parent = GetParent (w);
-
- if (parent == 0)
- break;
-
- TCHAR windowType [32];
- zeromem (windowType, sizeof (windowType));
- GetClassName (parent, windowType, 31);
-
- if (String (windowType).equalsIgnoreCase (T("MDIClient")))
- break;
-
- RECT windowPos;
- GetWindowRect (w, &windowPos);
-
- RECT parentPos;
- GetWindowRect (parent, &parentPos);
-
- SetWindowPos (w, 0, 0, 0,
- newWidth + dw,
- newHeight + dh,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
-
- dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left);
- dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top);
-
- w = parent;
-
- if (dw == 2 * frameThickness)
- break;
-
- if (dw > 100 || dh > 100)
- w = 0;
- }
-
- if (w != 0)
- SetWindowPos (w, 0, 0, 0,
- newWidth + dw,
- newHeight + dh,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
- #endif
- }
-
- if (editorComp->getPeer() != 0)
- editorComp->getPeer()->handleMovedOrResized();
- }
- }
-
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
- private:
- AudioFilterBase* filter;
- juce::MemoryBlock chunkMemory;
- uint32 chunkMemoryTime;
- EditorCompWrapper* editorComp;
- ERect editorSize;
- MidiBuffer midiEvents;
- VstEvents* outgoingEvents;
- int outgoingEventSize;
- bool isProcessing;
- bool firstResize;
- int diffW, diffH;
- float** channels;
-
- void ensureOutgoingEventSize (int numEvents)
- {
- if (outgoingEventSize < numEvents)
- {
- numEvents += 32;
- const int size = 16 + sizeof (VstEvent*) * numEvents;
-
- if (outgoingEvents == 0)
- outgoingEvents = (VstEvents*) juce_calloc (size);
- else
- outgoingEvents = (VstEvents*) juce_realloc (outgoingEvents, size);
-
- for (int i = outgoingEventSize; i < numEvents; ++i)
- {
- VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (sizeof (VstMidiEvent));
- e->type = kVstMidiType;
- e->byteSize = 24;
-
- outgoingEvents->events[i] = (VstEvent*) e;
- }
-
- outgoingEventSize = numEvents;
- }
- }
-
- const String getHostName()
- {
- char host[256];
- zeromem (host, sizeof (host));
- getHostProductString (host);
- return host;
- }
-
- #if JUCE_MAC
- WindowRef hostWindow;
- #elif JUCE_LINUX
- Window hostWindow;
- #else
- HWND hostWindow;
- #endif
- };
-
- //==============================================================================
- void EditorCompWrapper::childBoundsChanged (Component* child)
- {
- child->setTopLeftPosition (0, 0);
-
- const int cw = child->getWidth();
- const int ch = child->getHeight();
-
- wrapper->resizeHostWindow (cw, ch);
- setSize (cw, ch);
-
- #if JUCE_MAC
- wrapper->resizeHostWindow (cw, ch); // (doing this a second time seems to be necessary in tracktion)
- #endif
- }
-
- void EditorCompWrapper::handleAsyncUpdate()
- {
- wrapper->tryMasterIdle();
- }
-
- //==============================================================================
- static AEffect* pluginEntryPoint (audioMasterCallback audioMaster)
- {
- #if JUCE_MAC || JUCE_LINUX
- initialiseJuce_GUI();
- #endif
-
- MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0);
-
- try
- {
- if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0)
- {
- AudioFilterBase* const filter = createPluginFilter();
-
- if (filter != 0)
- {
- JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter);
- return wrapper->getAeffect();
- }
- }
- }
- catch (...)
- {}
-
- return 0;
- }
-
-
- //==============================================================================
- // Mac startup code..
- #if JUCE_MAC
-
- extern "C" __attribute__ ((visibility("default"))) AEffect* VSTPluginMain (audioMasterCallback audioMaster)
- {
- return pluginEntryPoint (audioMaster);
- }
-
- extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMasterCallback audioMaster)
- {
- return pluginEntryPoint (audioMaster);
- }
-
- //==============================================================================
- // Linux startup code..
- #elif JUCE_LINUX
-
- extern "C" AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main");
-
- extern "C" AEffect* main_plugin (audioMasterCallback audioMaster)
- {
- initialiseJuce_GUI();
- SharedMessageThread::getInstance();
-
- return pluginEntryPoint (audioMaster);
- }
-
- __attribute__((constructor)) void myPluginInit()
- {
- // don't put initialiseJuce_GUI here... it will crash !
- }
-
- __attribute__((destructor)) void myPluginFini()
- {
- // don't put shutdownJuce_GUI here... it will crash !
- }
-
- //==============================================================================
- // Win32 startup code..
- #else
-
- extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster)
- {
- return pluginEntryPoint (audioMaster);
- }
-
- extern "C" __declspec (dllexport) void* main (audioMasterCallback audioMaster)
- {
- return (void*) pluginEntryPoint (audioMaster);
- }
-
- BOOL WINAPI DllMain (HINSTANCE instance, DWORD dwReason, LPVOID)
- {
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- PlatformUtilities::setCurrentModuleInstanceHandle (instance);
- initialiseJuce_GUI();
- }
- else if (dwReason == DLL_PROCESS_DETACH)
- {
- shutdownJuce_GUI();
- }
-
- return TRUE;
- }
-
- #endif
|