Missing Juce items

pull/1/head
asb2m10 11 years ago
parent 1692e9a267
commit 36bd40be31
  1. 1617
      JuceLibraryCode/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  2. 269
      JuceLibraryCode/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.mm
  3. 393
      JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h
  4. 171
      JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Headers.h
  5. 41
      JuceLibraryCode/modules/juce_core/files/juce_FileFilter.cpp
  6. 77
      JuceLibraryCode/modules/juce_core/files/juce_FileFilter.h
  7. 77
      JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.cpp
  8. 86
      JuceLibraryCode/modules/juce_core/files/juce_WildcardFileFilter.h
  9. 259
      JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp
  10. 179
      JuceLibraryCode/modules/juce_events/interprocess/juce_ConnectedChildProcess.h

@ -0,0 +1,269 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
// Your project must contain an AppConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "AppConfig.h"
#include "../utility/juce_CheckSettingMacros.h"
#if JucePlugin_Build_VST3
#define JUCE_MAC_WINDOW_VISIBITY_BODGE 1
#include "../utility/juce_IncludeSystemHeaders.h"
#include "../utility/juce_IncludeModuleHeaders.h"
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../utility/juce_CarbonVisibility.h"
#undef Component
#undef Point
//==============================================================================
namespace juce
{
static void initialiseMac()
{
#if ! JUCE_64BIT
NSApplicationLoad();
#endif
}
#if ! JUCE_64BIT
static void updateComponentPos (Component* const comp)
{
DBG ("updateComponentPos()");
HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
HIRect r;
HIViewGetFrame (dummyView, &r);
HIViewRef root;
HIViewFindByID (HIViewGetRoot (HIViewGetWindow (dummyView)), kHIViewWindowContentID, &root);
HIViewConvertRect (&r, HIViewGetSuperview (dummyView), root);
Rect windowPos;
GetWindowBounds (HIViewGetWindow (dummyView), kWindowContentRgn, &windowPos);
comp->setTopLeftPosition ((int) (windowPos.left + r.origin.x),
(int) (windowPos.top + r.origin.y));
}
static pascal OSStatus viewBoundsChangedEvent (EventHandlerCallRef, EventRef, void* user)
{
updateComponentPos ((Component*) user);
return noErr;
}
#endif
static void* attachComponentToWindowRef (Component* comp, void* windowRef, bool isHIView)
{
DBG ("attachComponentToWindowRef()");
JUCE_AUTORELEASEPOOL
{
#if JUCE_64BIT
NSView* parentView = (NSView*) windowRef;
#if JucePlugin_EditorRequiresKeyboardFocus
comp->addToDesktop (0, parentView);
#else
comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
#endif
// (this workaround is because Wavelab provides a zero-size parent view..)
if ([parentView frame].size.height == 0)
[((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
comp->setVisible (true);
comp->toFront (false);
[[parentView window] setAcceptsMouseMovedEvents: YES];
return parentView;
#else
//treat NSView like 64bit
if (! isHIView)
{
NSView* parentView = (NSView*) windowRef;
#if JucePlugin_EditorRequiresKeyboardFocus
comp->addToDesktop (0, parentView);
#else
comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
#endif
// (this workaround is because Wavelab provides a zero-size parent view..)
if ([parentView frame].size.height == 0)
[((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
comp->setVisible (true);
comp->toFront (false);
[[parentView window] setAcceptsMouseMovedEvents: YES];
return parentView;
}
NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
[hostWindow retain];
[hostWindow setCanHide: YES];
[hostWindow setReleasedWhenClosed: YES];
HIViewRef parentView = nullptr;
WindowAttributes attributes;
GetWindowAttributes ((WindowRef) windowRef, &attributes);
if ((attributes & kWindowCompositingAttribute) != 0)
{
HIViewRef root = HIViewGetRoot ((WindowRef) windowRef);
HIViewFindByID (root, kHIViewWindowContentID, &parentView);
if (parentView == nullptr)
parentView = root;
}
else
{
GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
if (parentView == nullptr)
CreateRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
}
// It seems that the only way to successfully position our overlaid window is by putting a dummy
// HIView into the host's carbon window, and then catching events to see when it gets repositioned
HIViewRef dummyView = 0;
HIImageViewCreate (0, &dummyView);
HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} };
HIViewSetFrame (dummyView, &r);
HIViewAddSubview (parentView, dummyView);
comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView));
EventHandlerRef ref;
const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged };
InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref);
comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref));
updateComponentPos (comp);
#if ! JucePlugin_EditorRequiresKeyboardFocus
comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses);
#else
comp->addToDesktop (ComponentPeer::windowIsTemporary);
#endif
comp->setVisible (true);
comp->toFront (false);
NSView* pluginView = (NSView*) comp->getWindowHandle();
NSWindow* pluginWindow = [pluginView window];
[pluginWindow setExcludedFromWindowsMenu: YES];
[pluginWindow setCanHide: YES];
[hostWindow addChildWindow: pluginWindow
ordered: NSWindowAbove];
[hostWindow orderFront: nil];
[pluginWindow orderFront: nil];
attachWindowHidingHooks (comp, (WindowRef) windowRef, hostWindow);
return hostWindow;
#endif
}
}
static void detachComponentFromWindowRef (Component* comp, void* nsWindow, bool isHIView)
{
#if JUCE_64BIT
comp->removeFromDesktop();
#else
//treat NSView like 64bit
if (! isHIView)
{
comp->removeFromDesktop();
}
else
{
JUCE_AUTORELEASEPOOL
{
EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
comp->getProperties() ["boundsEventRef"].toString().getHexValue64();
RemoveEventHandler (ref);
removeWindowHidingHooks (comp);
HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
if (HIViewIsValid (dummyView))
CFRelease (dummyView);
NSWindow* hostWindow = (NSWindow*) nsWindow;
NSView* pluginView = (NSView*) comp->getWindowHandle();
NSWindow* pluginWindow = [pluginView window];
[hostWindow removeChildWindow: pluginWindow];
comp->removeFromDesktop();
[hostWindow release];
}
// The event loop needs to be run between closing the window and deleting the plugin,
// presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes
// in Live and Reaper when you delete the plugin with its window open.
// (Doing it this way rather than using a single longer timout means that we can guarantee
// how many messages will be dispatched, which seems to be vital in Reaper)
for (int i = 20; --i >= 0;)
MessageManager::getInstance()->runDispatchLoopUntil (1);
}
#endif
}
static void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight, bool isHIView)
{
JUCE_AUTORELEASEPOOL
{
#if JUCE_64BIT
component->setSize (newWidth, newHeight);
#else
if (! isHIView)
{ //Treat NSView like 64bit:
component->setSize (newWidth, newHeight);
}
else if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
component->getProperties() ["dummyViewRef"].toString().getHexValue64())
{
HIRect frameRect;
HIViewGetFrame (dummyView, &frameRect);
frameRect.size.width = newWidth;
frameRect.size.height = newHeight;
HIViewSetFrame (dummyView, &frameRect);
}
#endif
}
}
} // (juce namespace)
#endif

@ -0,0 +1,393 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_VST3COMMON_H_INCLUDED
#define JUCE_VST3COMMON_H_INCLUDED
//==============================================================================
#define JUCE_DECLARE_VST3_COM_REF_METHODS \
Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \
Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; }
#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \
Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \
{ \
jassertfalse; \
*obj = nullptr; \
return Steinberg::kNotImplemented; \
}
static bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept
{
return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0;
}
#define TEST_FOR_AND_RETURN_IF_VALID(ClassType) \
if (doUIDsMatch (iid, ClassType::iid)) \
{ \
addRef(); \
*obj = dynamic_cast<ClassType*> (this); \
return Steinberg::kResultOk; \
}
#define TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID(CommonClassType, SourceClassType) \
if (doUIDsMatch (iid, CommonClassType::iid)) \
{ \
addRef(); \
*obj = (CommonClassType*) static_cast<SourceClassType*> (this); \
return Steinberg::kResultOk; \
}
//==============================================================================
static juce::String toString (const Steinberg::char8* string) noexcept { return juce::String (string); }
static juce::String toString (const Steinberg::char16* string) noexcept { return juce::String (juce::CharPointer_UTF16 ((juce::CharPointer_UTF16::CharType*) string)); }
// NB: The casts are handled by a Steinberg::UString operator
static juce::String toString (const Steinberg::UString128& string) noexcept { return toString (static_cast<const Steinberg::char16*> (string)); }
static juce::String toString (const Steinberg::UString256& string) noexcept { return toString (static_cast<const Steinberg::char16*> (string)); }
static void toString128 (Steinberg::Vst::String128 result, const juce::String& source)
{
Steinberg::UString (result, 128).fromAscii (source.toUTF8());
}
static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept
{
return reinterpret_cast<Steinberg::Vst::TChar*> (source.toUTF16().getAddress());
}
#if JUCE_WINDOWS
static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeHWND;
#else
static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeNSView;
#endif
//==============================================================================
/** For the sake of simplicity, there can only be 1 arrangement type per channel count.
i.e.: 4 channels == k31Cine OR k40Cine
*/
static Steinberg::Vst::SpeakerArrangement getArrangementForNumChannels (int numChannels) noexcept
{
using namespace Steinberg::Vst::SpeakerArr;
switch (numChannels)
{
case 0: return kEmpty;
case 1: return kMono;
case 2: return kStereo;
case 3: return k30Cine;
case 4: return k31Cine;
case 5: return k50;
case 6: return k51;
case 7: return k61Cine;
case 8: return k71CineFullFront;
case 9: return k90;
case 10: return k91;
case 11: return k101;
case 12: return k111;
case 13: return k130;
case 14: return k131;
case 24: return (Steinberg::Vst::SpeakerArrangement) 1929904127; // k222
default: break;
}
jassert (numChannels >= 0);
juce::BigInteger bi;
bi.setRange (0, jmin (numChannels, (int) (sizeof (Steinberg::Vst::SpeakerArrangement) * 8)), true);
return (Steinberg::Vst::SpeakerArrangement) bi.toInt64();
}
//==============================================================================
template <class ObjectType>
class ComSmartPtr
{
public:
ComSmartPtr() noexcept : source (nullptr) {}
ComSmartPtr (ObjectType* object) noexcept : source (object) { if (source != nullptr) source->addRef(); }
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
~ComSmartPtr() { if (source != nullptr) source->release(); }
operator ObjectType*() const noexcept { return source; }
ObjectType* get() const noexcept { return source; }
ObjectType& operator*() const noexcept { return *source; }
ObjectType* operator->() const noexcept { return source; }
ComSmartPtr& operator= (const ComSmartPtr& other) { return operator= (other.source); }
ComSmartPtr& operator= (ObjectType* const newObjectToTakePossessionOf)
{
ComSmartPtr p (newObjectToTakePossessionOf);
std::swap (p.source, source);
return *this;
}
bool operator== (ObjectType* const other) noexcept { return source == other; }
bool operator!= (ObjectType* const other) noexcept { return source != other; }
bool loadFrom (Steinberg::FUnknown* o)
{
*this = nullptr;
return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
}
bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid)
{
jassert (factory != nullptr);
*this = nullptr;
return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
}
private:
ObjectType* source;
};
//==============================================================================
class MidiEventList : public Steinberg::Vst::IEventList
{
public:
MidiEventList() {}
virtual ~MidiEventList() {}
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
//==============================================================================
void clear()
{
events.clearQuick();
}
Steinberg::int32 PLUGIN_API getEventCount() override
{
return (Steinberg::int32) events.size();
}
// NB: This has to cope with out-of-range indexes from some plugins.
Steinberg::tresult PLUGIN_API getEvent (Steinberg::int32 index, Steinberg::Vst::Event& e) override
{
if (isPositiveAndBelow ((int) index, events.size()))
{
e = events.getReference ((int) index);
return Steinberg::kResultTrue;
}
return Steinberg::kResultFalse;
}
Steinberg::tresult PLUGIN_API addEvent (Steinberg::Vst::Event& e) override
{
events.add (e);
return Steinberg::kResultTrue;
}
//==============================================================================
static void toMidiBuffer (MidiBuffer& result, Steinberg::Vst::IEventList& eventList)
{
const int32 numEvents = eventList.getEventCount();
for (Steinberg::int32 i = 0; i < numEvents; ++i)
{
Steinberg::Vst::Event e;
if (eventList.getEvent (i, e) == Steinberg::kResultOk)
{
switch (e.type)
{
case Steinberg::Vst::Event::kNoteOnEvent:
result.addEvent (MidiMessage::noteOn (createSafeChannel (e.noteOn.channel),
createSafeNote (e.noteOn.pitch),
(Steinberg::uint8) denormaliseToMidiValue (e.noteOn.velocity)),
e.sampleOffset);
break;
case Steinberg::Vst::Event::kNoteOffEvent:
result.addEvent (MidiMessage::noteOff (createSafeChannel (e.noteOff.channel),
createSafeNote (e.noteOff.pitch),
(Steinberg::uint8) denormaliseToMidiValue (e.noteOff.velocity)),
e.sampleOffset);
break;
case Steinberg::Vst::Event::kPolyPressureEvent:
result.addEvent (MidiMessage::aftertouchChange (createSafeChannel (e.polyPressure.channel),
createSafeNote (e.polyPressure.pitch),
denormaliseToMidiValue (e.polyPressure.pressure)),
e.sampleOffset);
break;
case Steinberg::Vst::Event::kDataEvent:
result.addEvent (MidiMessage::createSysExMessage (e.data.bytes, e.data.size),
e.sampleOffset);
break;
default:
break;
}
}
}
}
static void toEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer)
{
MidiBuffer::Iterator iterator (midiBuffer);
MidiMessage msg;
int midiEventPosition = 0;
enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once
int numEvents = 0;
while (iterator.getNextEvent (msg, midiEventPosition))
{
if (++numEvents > maxNumEvents)
break;
Steinberg::Vst::Event e = { 0 };
if (msg.isNoteOn())
{
e.type = Steinberg::Vst::Event::kNoteOnEvent;
e.noteOn.channel = createSafeChannel (msg.getChannel());
e.noteOn.pitch = createSafeNote (msg.getNoteNumber());
e.noteOn.velocity = normaliseMidiValue (msg.getVelocity());
e.noteOn.length = 0;
e.noteOn.tuning = 0.0f;
e.noteOn.noteId = -1;
}
else if (msg.isNoteOff())
{
e.type = Steinberg::Vst::Event::kNoteOffEvent;
e.noteOff.channel = createSafeChannel (msg.getChannel());
e.noteOff.pitch = createSafeNote (msg.getNoteNumber());
e.noteOff.velocity = normaliseMidiValue (msg.getVelocity());
e.noteOff.tuning = 0.0f;
e.noteOff.noteId = -1;
}
else if (msg.isSysEx())
{
e.type = Steinberg::Vst::Event::kDataEvent;
e.data.bytes = msg.getSysExData();
e.data.size = msg.getSysExDataSize();
e.data.type = Steinberg::Vst::DataEvent::kMidiSysEx;
}
else if (msg.isAftertouch())
{
e.type = Steinberg::Vst::Event::kPolyPressureEvent;
e.polyPressure.channel = createSafeChannel (msg.getChannel());
e.polyPressure.pitch = createSafeNote (msg.getNoteNumber());
e.polyPressure.pressure = normaliseMidiValue (msg.getAfterTouchValue());
}
else
{
continue;
}
e.busIndex = 0;
e.sampleOffset = midiEventPosition;
result.addEvent (e);
}
}
private:
Array<Steinberg::Vst::Event, CriticalSection> events;
Atomic<int> refCount;
static Steinberg::int16 createSafeChannel (int channel) noexcept { return (Steinberg::int16) jlimit (0, 15, channel - 1); }
static int createSafeChannel (Steinberg::int16 channel) noexcept { return (int) jlimit (1, 16, channel + 1); }
static Steinberg::int16 createSafeNote (int note) noexcept { return (Steinberg::int16) jlimit (0, 127, note); }
static int createSafeNote (Steinberg::int16 note) noexcept { return jlimit (0, 127, (int) note); }
static float normaliseMidiValue (int value) noexcept { return jlimit (0.0f, 1.0f, (float) value / 127.0f); }
static int denormaliseToMidiValue (float value) noexcept { return roundToInt (jlimit (0.0f, 127.0f, value * 127.0f)); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList)
};
//==============================================================================
namespace VST3BufferExchange
{
typedef Array<float*> Bus;
typedef Array<Bus> BusMap;
/** Assigns a series of AudioSampleBuffer's channels to an AudioBusBuffers'
@warning For speed, does not check the channel count and offsets
according to the AudioSampleBuffer
*/
void associateBufferTo (Steinberg::Vst::AudioBusBuffers& vstBuffers,
Bus& bus,
const AudioSampleBuffer& buffer,
int numChannels, int channelStartOffset,
int sampleOffset = 0) noexcept
{
const int channelEnd = numChannels + channelStartOffset;
jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels());
bus.clearQuick();
for (int i = channelStartOffset; i < channelEnd; ++i)
bus.add (buffer.getSampleData (i, sampleOffset));
vstBuffers.channelBuffers32 = bus.getRawDataPointer();
vstBuffers.numChannels = numChannels;
vstBuffers.silenceFlags = 0;
}
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
Steinberg::Vst::IAudioProcessor& processor,
BusMap& busMapToUse,
bool isInput, int numBusses,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
for (int i = 0; i < numBusses; ++i)
{
Steinberg::Vst::SpeakerArrangement arrangement = 0;
processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
(Steinberg::int32) i, arrangement);
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
if (i >= result.size())
result.add (Steinberg::Vst::AudioBusBuffers());
if (i >= busMapToUse.size())
busMapToUse.add (Bus());
if (numChansForBus > 0)
{
associateBufferTo (result.getReference (i),
busMapToUse.getReference (i),
source, numChansForBus, channelIndexOffset);
}
channelIndexOffset += numChansForBus;
}
}
}
#endif // JUCE_VST3COMMON_H_INCLUDED

@ -0,0 +1,171 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_VST3HEADERS_H_INCLUDED
#define JUCE_VST3HEADERS_H_INCLUDED
#undef Point
#undef Component
// Wow, those Steinberg guys really don't worry too much about compiler warnings.
#if _MSC_VER
#pragma warning (disable: 4505)
#pragma warning (push, 0)
#pragma warning (disable: 4702)
#elif __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#pragma clang diagnostic ignored "-Wreorder"
#pragma clang diagnostic ignored "-Wunsequenced"
#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Woverloaded-virtual"
#pragma clang diagnostic ignored "-Wshadow"
#endif
/* These files come with the Steinberg VST3 SDK - to get them, you'll need to
visit the Steinberg website and agree to whatever is currently required to
get them.
Then, you'll need to make sure your include path contains your "VST3 SDK"
directory (or whatever you've named it on your machine). The Introjucer has
a special box for setting this path.
*/
#if JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY
#include <base/source/fstring.h>
#include <pluginterfaces/base/conststringtable.h>
#include <pluginterfaces/base/funknown.h>
#include <pluginterfaces/base/ipluginbase.h>
#include <pluginterfaces/base/ustring.h>
#include <pluginterfaces/gui/iplugview.h>
#include <pluginterfaces/vst/ivstattributes.h>
#include <pluginterfaces/vst/ivstaudioprocessor.h>
#include <pluginterfaces/vst/ivstcomponent.h>
#include <pluginterfaces/vst/ivstcontextmenu.h>
#include <pluginterfaces/vst/ivsteditcontroller.h>
#include <pluginterfaces/vst/ivstevents.h>
#include <pluginterfaces/vst/ivsthostapplication.h>
#include <pluginterfaces/vst/ivstmessage.h>
#include <pluginterfaces/vst/ivstmidicontrollers.h>
#include <pluginterfaces/vst/ivstparameterchanges.h>
#include <pluginterfaces/vst/ivstplugview.h>
#include <pluginterfaces/vst/ivstprocesscontext.h>
#include <pluginterfaces/vst/vsttypes.h>
#include <pluginterfaces/vst/ivstunits.h>
#include <public.sdk/source/common/memorystream.h>
#else
#include <base/source/baseiids.cpp>
#include <base/source/fatomic.cpp>
#include <base/source/fbuffer.cpp>
#include <base/source/fdebug.cpp>
#include <base/source/fobject.cpp>
#include <base/source/frect.cpp>
#include <base/source/fstreamer.cpp>
#include <base/source/fstring.cpp>
#include <base/source/fthread.cpp>
#include <base/source/updatehandler.cpp>
#include <pluginterfaces/base/conststringtable.cpp>
#include <pluginterfaces/base/funknown.cpp>
#include <pluginterfaces/base/ipluginbase.h>
#include <pluginterfaces/base/ustring.cpp>
#include <pluginterfaces/gui/iplugview.h>
#include <public.sdk/source/common/memorystream.cpp>
#include <public.sdk/source/common/pluginview.cpp>
#include <public.sdk/source/vst/vsteditcontroller.cpp>
#include <public.sdk/source/vst/vstbus.cpp>
#include <public.sdk/source/vst/vstinitiids.cpp>
#include <public.sdk/source/vst/vstcomponent.cpp>
#include <public.sdk/source/vst/vstcomponentbase.cpp>
#include <public.sdk/source/vst/vstparameters.cpp>
#include <public.sdk/source/vst/hosting/hostclasses.cpp>
//==============================================================================
namespace Steinberg
{
/** Missing IIDs */
DEF_CLASS_IID (IPluginBase)
DEF_CLASS_IID (IPlugView)
DEF_CLASS_IID (IPlugFrame)
DEF_CLASS_IID (IBStream)
DEF_CLASS_IID (ISizeableStream)
DEF_CLASS_IID (IPluginFactory)
DEF_CLASS_IID (IPluginFactory2)
DEF_CLASS_IID (IPluginFactory3)
}
#endif //JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY
#if _MSC_VER
#pragma warning (pop)
#elif __clang__
#pragma clang diagnostic pop
#endif
//==============================================================================
#undef ASSERT
#undef WARNING
#undef PRINTSYSERROR
#undef DEBUGSTR
#undef DBPRT0
#undef DBPRT1
#undef DBPRT2
#undef DBPRT3
#undef DBPRT4
#undef DBPRT5
#undef min
#undef max
#undef MIN
#undef MAX
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef NEW
#undef NEWVEC
#undef VERIFY
#undef VERIFY_IS
#undef VERIFY_NOT
#undef META_CREATE_FUNC
#undef CLASS_CREATE_FUNC
#undef SINGLE_CREATE_FUNC
#undef _META_CLASS
#undef _META_CLASS_IFACE
#undef _META_CLASS_SINGLE
#undef META_CLASS
#undef META_CLASS_IFACE
#undef META_CLASS_SINGLE
#undef SINGLETON
#undef OBJ_METHODS
#undef QUERY_INTERFACE
#undef LICENCE_UID
#undef BEGIN_FACTORY
#undef DEF_CLASS
#undef DEF_CLASS1
#undef DEF_CLASS2
#undef DEF_CLASS_W
#undef END_FACTORY
#undef Point
#undef Component
#endif // JUCE_VST3HEADERS_H_INCLUDED

@ -0,0 +1,41 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
FileFilter::FileFilter (const String& filterDescription)
: description (filterDescription)
{
}
FileFilter::~FileFilter()
{
}
const String& FileFilter::getDescription() const noexcept
{
return description;
}

@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_FILEFILTER_H_INCLUDED
#define JUCE_FILEFILTER_H_INCLUDED
//==============================================================================
/**
Interface for deciding which files are suitable for something.
For example, this is used by DirectoryContentsList to select which files
go into the list.
@see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
*/
class JUCE_API FileFilter
{
public:
//==============================================================================
/** Creates a filter with the given description.
The description can be returned later with the getDescription() method.
*/
FileFilter (const String& filterDescription);
/** Destructor. */
virtual ~FileFilter();
//==============================================================================
/** Returns the description that the filter was created with. */
const String& getDescription() const noexcept;
//==============================================================================
/** Should return true if this file is suitable for inclusion in whatever context
the object is being used.
*/
virtual bool isFileSuitable (const File& file) const = 0;
/** Should return true if this directory is suitable for inclusion in whatever context
the object is being used.
*/
virtual bool isDirectorySuitable (const File& file) const = 0;
protected:
//==============================================================================
String description;
};
#endif // JUCE_FILEFILTER_H_INCLUDED

@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& desc)
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
: (desc + " (" + fileWildcardPatterns + ")"))
{
parse (fileWildcardPatterns, fileWildcards);
parse (directoryWildcardPatterns, directoryWildcards);
}
WildcardFileFilter::~WildcardFileFilter()
{
}
bool WildcardFileFilter::isFileSuitable (const File& file) const
{
return match (file, fileWildcards);
}
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
{
return match (file, directoryWildcards);
}
//==============================================================================
void WildcardFileFilter::parse (const String& pattern, StringArray& result)
{
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
result.trim();
result.removeEmptyStrings();
// special case for *.*, because people use it to mean "any file", but it
// would actually ignore files with no extension.
for (int i = result.size(); --i >= 0;)
if (result[i] == "*.*")
result.set (i, "*");
}
bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
{
const String filename (file.getFileName());
for (int i = wildcards.size(); --i >= 0;)
if (filename.matchesWildcard (wildcards[i], true))
return true;
return false;
}

@ -0,0 +1,86 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_WILDCARDFILEFILTER_H_INCLUDED
#define JUCE_WILDCARDFILEFILTER_H_INCLUDED
//==============================================================================
/**
A type of FileFilter that works by wildcard pattern matching.
This filter only allows files that match one of the specified patterns, but
allows all directories through.
@see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
*/
class JUCE_API WildcardFileFilter : public FileFilter
{
public:
//==============================================================================
/**
Creates a wildcard filter for one or more patterns.
The wildcardPatterns parameter is a comma or semicolon-delimited set of
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
or .aiff.
Passing an empty string as a pattern will fail to match anything, so by leaving
either the file or directory pattern parameter empty means you can control
whether files or directories are found.
The description is a name to show the user in a list of possible patterns, so
for the wav/aiff example, your description might be "audio files".
*/
WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& description);
/** Destructor. */
~WildcardFileFilter();
//==============================================================================
/** Returns true if the filename matches one of the patterns specified. */
bool isFileSuitable (const File& file) const;
/** This always returns true. */
bool isDirectorySuitable (const File& file) const;
private:
//==============================================================================
StringArray fileWildcards, directoryWildcards;
static void parse (const String& pattern, StringArray& result);
static bool match (const File& file, const StringArray& wildcards);
JUCE_LEAK_DETECTOR (WildcardFileFilter)
};
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED

@ -0,0 +1,259 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
enum { magicMastSlaveConnectionHeader = 0x712baf04 };
static const char* startMessage = "__ipc_st";
static const char* killMessage = "__ipc_k_";
static const char* pingMessage = "__ipc_p_";
enum { specialMessageSize = 8 };
static String getCommandLinePrefix (const String& commandLineUniqueID)
{
return "--" + commandLineUniqueID + ":";
}
//==============================================================================
// This thread sends and receives ping messages every second, so that it
// can find out if the other process has stopped running.
struct ChildProcessPingThread : public Thread,
private AsyncUpdater
{
ChildProcessPingThread() : Thread ("IPC ping"), timeoutMs (8000)
{
pingReceived();
}
static bool isPingMessage (const MemoryBlock& m) noexcept
{
return memcmp (m.getData(), pingMessage, specialMessageSize) == 0;
}
void pingReceived() noexcept { countdown = timeoutMs / 1000 + 1; }
void triggerConnectionLostMessage() { triggerAsyncUpdate(); }
virtual bool sendPingMessage (const MemoryBlock&) = 0;
virtual void pingFailed() = 0;
int timeoutMs;
private:
Atomic<int> countdown;
void handleAsyncUpdate() override { pingFailed(); }
void run() override
{
while (! threadShouldExit())
{
if (--countdown <= 0 || ! sendPingMessage (MemoryBlock (pingMessage, specialMessageSize)))
{
triggerConnectionLostMessage();
break;
}
wait (1000);
}
}
JUCE_DECLARE_NON_COPYABLE (ChildProcessPingThread)
};
//==============================================================================
struct ChildProcessMaster::Connection : public InterprocessConnection,
private ChildProcessPingThread
{
Connection (ChildProcessMaster& m, const String& pipeName)
: InterprocessConnection (false, magicMastSlaveConnectionHeader), owner (m)
{
if (createPipe (pipeName, timeoutMs))
startThread (4);
}
~Connection()
{
stopThread (10000);
}
private:
void connectionMade() override {}
void connectionLost() override { owner.handleConnectionLost(); }
bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToSlave (m); }
void pingFailed() override { connectionLost(); }
void messageReceived (const MemoryBlock& m) override
{
pingReceived();
if (m.getSize() != specialMessageSize || ! isPingMessage (m))
owner.handleMessageFromSlave (m);
}
ChildProcessMaster& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
};
//==============================================================================
ChildProcessMaster::ChildProcessMaster() {}
ChildProcessMaster::~ChildProcessMaster()
{
if (connection != nullptr)
{
sendMessageToSlave (MemoryBlock (killMessage, specialMessageSize));
connection->disconnect();
connection = nullptr;
}
}
void ChildProcessMaster::handleConnectionLost() {}
bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb)
{
if (connection != nullptr)
return connection->sendMessage (mb);
jassertfalse; // this can only be used when the connection is active!
return false;
}
bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID)
{
connection = nullptr;
jassert (childProcess.kill());
const String pipeName ("p" + String::toHexString (Random().nextInt64()));
StringArray args;
args.add (executable.getFullPathName());
args.add (getCommandLinePrefix (commandLineUniqueID) + pipeName);
if (childProcess.start (args))
{
connection = new Connection (*this, pipeName);
if (connection->isConnected())
{
sendMessageToSlave (MemoryBlock (startMessage, specialMessageSize));
return true;
}
connection = nullptr;
}
return false;
}
//==============================================================================
struct ChildProcessSlave::Connection : public InterprocessConnection,
private ChildProcessPingThread
{
Connection (ChildProcessSlave& p, const String& pipeName)
: InterprocessConnection (false, magicMastSlaveConnectionHeader), owner (p)
{
connectToPipe (pipeName, timeoutMs);
startThread (4);
}
~Connection()
{
stopThread (10000);
}
private:
ChildProcessSlave& owner;
void connectionMade() override {}
void connectionLost() override { owner.handleConnectionLost(); }
bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToMaster (m); }
void pingFailed() override { connectionLost(); }
void messageReceived (const MemoryBlock& m) override
{
pingReceived();
if (m.getSize() == specialMessageSize)
{
if (isPingMessage (m))
return;
if (memcmp (m.getData(), killMessage, specialMessageSize) == 0)
{
triggerConnectionLostMessage();
return;
}
if (memcmp (m.getData(), startMessage, specialMessageSize) == 0)
{
owner.handleConnectionMade();
return;
}
}
owner.handleMessageFromMaster (m);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
};
//==============================================================================
ChildProcessSlave::ChildProcessSlave() {}
ChildProcessSlave::~ChildProcessSlave() {}
void ChildProcessSlave::handleConnectionMade() {}
void ChildProcessSlave::handleConnectionLost() {}
bool ChildProcessSlave::sendMessageToMaster (const MemoryBlock& mb)
{
if (connection != nullptr)
return connection->sendMessage (mb);
jassertfalse; // this can only be used when the connection is active!
return false;
}
bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine,
const String& commandLineUniqueID)
{
String prefix (getCommandLinePrefix (commandLineUniqueID));
if (commandLine.trim().startsWith (prefix))
{
String pipeName (commandLine.fromFirstOccurrenceOf (prefix, false, false)
.upToFirstOccurrenceOf (" ", false, false).trim());
if (pipeName.isNotEmpty())
{
connection = new Connection (*this, pipeName);
if (! connection->isConnected())
connection = nullptr;
}
}
return connection != nullptr;
}

@ -0,0 +1,179 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_CONNECTEDCHILDPROCESS_H_INCLUDED
#define JUCE_CONNECTEDCHILDPROCESS_H_INCLUDED
//==============================================================================
/**
Acts as the slave end of a master/slave pair of connected processes.
The ChildProcessSlave and ChildProcessMaster classes make it easy for an app
to spawn a child process, and to manage a 2-way messaging connection to control it.
To use the system, you need to create subclasses of both ChildProcessSlave and
ChildProcessMaster. To instantiate the ChildProcessSlave object, you must
add some code to your main() or JUCEApplication::initialise() function that
calls the initialiseFromCommandLine() method to check the app's command-line
parameters to see whether it's being launched as a child process. If this returns
true then the slave process can be allowed to run, and its handleMessageFromMaster()
method will be called whenever a message arrives.
The juce demo app has a good example of this class in action.
@see ChildProcessMaster, InterprocessConnection, ChildProcess
*/
class JUCE_API ChildProcessSlave
{
public:
/** Creates a non-connected slave process.
Use initialiseFromCommandLine to connect to a master process.
*/
ChildProcessSlave();
/** Destructor. */
virtual ~ChildProcessSlave();
/** This checks some command-line parameters to see whether they were generated by
ChildProcessMaster::launchSlaveProcess(), and if so, connects to that master process.
In an exe that can be used as a child process, you should add some code to your
main() or JUCEApplication::initialise() that calls this method.
The commandLineUniqueID should be a short alphanumeric identifier (no spaces!)
that matches the string passed to ChildProcessMaster::launchSlaveProcess().
Returns true if the command-line matches and the connection is made successfully.
*/
bool initialiseFromCommandLine (const String& commandLine,
const String& commandLineUniqueID);
//==============================================================================
/** This will be called to deliver messages from the master process.
The call will probably be made on a background thread, so be careful with your
thread-safety! You may want to respond by sending back a message with
sendMessageToMaster()
*/
virtual void handleMessageFromMaster (const MemoryBlock&) = 0;
/** This will be called when the master process finishes connecting to this slave.
The call will probably be made on a background thread, so be careful with your thread-safety!
*/
virtual void handleConnectionMade();
/** This will be called when the connection to the master process is lost.
The call may be made from any thread (including the message thread).
Typically, if your process only exists to act as a slave, you should probably exit
when this happens.
*/
virtual void handleConnectionLost();
/** Tries to send a message to the master process.
This returns true if the message was sent, but doesn't check that it actually gets
delivered at the other end. If successful, the data will emerge in a call to your
ChildProcessMaster::handleMessageFromSlave().
*/
bool sendMessageToMaster (const MemoryBlock&);
private:
struct Connection;
friend struct Connection;
friend struct ContainerDeletePolicy<Connection>;
ScopedPointer<Connection> connection;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessSlave)
};
//==============================================================================
/**
Acts as the master in a master/slave pair of connected processes.
The ChildProcessSlave and ChildProcessMaster classes make it easy for an app
to spawn a child process, and to manage a 2-way messaging connection to control it.
To use the system, you need to create subclasses of both ChildProcessSlave and
ChildProcessMaster. When you want your master process to launch the slave, you
just call launchSlaveProcess(), and it'll attempt to launch the executable that
you specify (which may be the same exe), and assuming it has been set-up to
correctly parse the command-line parameters (see ChildProcessSlave) then a
two-way connection will be created.
The juce demo app has a good example of this class in action.
@see ChildProcessSlave, InterprocessConnection, ChildProcess
*/
class JUCE_API ChildProcessMaster
{
public:
/** Creates an uninitialised master process object.
Use launchSlaveProcess to launch and connect to a child process.
*/
ChildProcessMaster();
/** Destructor. */
virtual ~ChildProcessMaster();
/** Attempts to launch and connect to a slave process.
This will start the given executable, passing it a special command-line
parameter based around the commandLineUniqueID string, which must be a
short alphanumeric string (no spaces!) that identifies your app. The exe
that gets launched must respond by calling ChildProcessSlave::initialiseFromCommandLine()
in its startup code, and must use a matching ID to commandLineUniqueID.
If this all works, the method returns true, and you can begin sending and
receiving messages with the slave process.
*/
bool launchSlaveProcess (const File& executableToLaunch,
const String& commandLineUniqueID);
/** This will be called to deliver a message from the slave process.
The call will probably be made on a background thread, so be careful with your thread-safety!
*/
virtual void handleMessageFromSlave (const MemoryBlock&) = 0;
/** This will be called when the slave process dies or is somehow disconnected.
The call will probably be made on a background thread, so be careful with your thread-safety!
*/
virtual void handleConnectionLost();
/** Attempts to send a message to the slave process.
This returns true if the message was dispatched, but doesn't check that it actually
gets delivered at the other end. If successful, the data will emerge in a call to
your ChildProcessSlave::handleMessageFromMaster().
*/
bool sendMessageToSlave (const MemoryBlock&);
private:
ChildProcess childProcess;
struct Connection;
friend struct Connection;
friend struct ContainerDeletePolicy<Connection>;
ScopedPointer<Connection> connection;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessMaster)
};
#endif // JUCE_CONNECTEDCHILDPROCESS_H_INCLUDED
Loading…
Cancel
Save