text:
//------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vst2wrapper/vst2wrapper.h
// Created by  : Steinberg, 01/2009
// Description : VST 3 -> VST 2 Wrapper
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

/**
**************************************
\page vst2xwrapper VST 2.x Wrapper
***************************
\section VST2Introduction Introduction
***************************
The VST 3 SDK comes with a helper class which wraps one VST 3 Audio Processor and Edit Controller to
a VST 2.x Plug-in.
\n\n
***************************
\section VST2howdoesitwork How does it work ?
***************************
You just need to add public.sdk/source/vst/vst2wrapper/vst2wrapper.sdk.cpp to your project and add
the following code somewhere in your sources:
\code

#include "public.sdk/source/vst/vst2wrapper/vst2wrapper.h"

//------------------------------------------------------------------------
::AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
{
	return Steinberg::Vst::Vst2Wrapper::create (GetPluginFactory (), kAudioProcessorCID, kVst2UniqueID, audioMaster);
}

\endcode
 */
/// \cond ignore

#pragma once

#include "pluginterfaces/base/ftypes.h"
#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"
#include "pluginterfaces/vst/ivsthostapplication.h"
#include "pluginterfaces/vst/ivstprocesscontext.h"
#include "pluginterfaces/vst/ivstunits.h"

#include "public.sdk/source/common/memorystream.h"
#include "public.sdk/source/vst/hosting/eventlist.h"
#include "public.sdk/source/vst/hosting/parameterchanges.h"
#include "public.sdk/source/vst/hosting/processdata.h"
#include "public.sdk/source/vst2.x/audioeffectx.h"

#include "base/source/fstring.h"
#include "base/source/timer.h"

#include <map>
#include <vector>

//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {

class Vst2MidiEventQueue;

//-------------------------------------------------------------------------------------------------------
class Vst2Wrapper : public ::AudioEffectX,
                    public IHostApplication,
                    public IComponentHandler,
                    public IUnitHandler,
                    public ITimerCallback,
                    public IVst3ToVst2Wrapper
{
public:
	//--- -------------------------------------------------------------------------------------------------
	// static creation method
	static AudioEffect* create (IPluginFactory* factory, const TUID vst3ComponentID,
	                            VstInt32 vst2ID, audioMasterCallback audioMaster);

	Vst2Wrapper (IAudioProcessor* processor, IEditController* controller,
	             audioMasterCallback audioMaster, const TUID vst3ComponentID, VstInt32 vst2ID,
	             IPluginFactory* factory = 0);
	~Vst2Wrapper ();

	bool init ();

	// AudioEffectX overrides -----------------------------------------------
	virtual void suspend () SMTG_OVERRIDE; // Called when Plug-in is switched to off
	virtual void resume () SMTG_OVERRIDE; // Called when Plug-in is switched to on
	virtual VstInt32 startProcess () SMTG_OVERRIDE;
	virtual VstInt32 stopProcess () SMTG_OVERRIDE;

	virtual void setSampleRate (float newSamplerate)
	    SMTG_OVERRIDE; // Called when the sample rate changes (always in a suspend state)
	virtual void setBlockSize (VstInt32 newBlockSize)
	    SMTG_OVERRIDE; // Called when the maximum block size changes
	// (always in a suspend state). Note that the
	// sampleFrames in Process Calls could be
	// smaller than this block size, but NOT bigger.

	virtual float getParameter (VstInt32 index) SMTG_OVERRIDE;
	virtual void setParameter (VstInt32 index, float value) SMTG_OVERRIDE;

	virtual void setProgram (VstInt32 program) SMTG_OVERRIDE;
	virtual void setProgramName (char* name) SMTG_OVERRIDE;
	virtual void getProgramName (char* name) SMTG_OVERRIDE;
	virtual bool getProgramNameIndexed (VstInt32 category, VstInt32 index,
	                                    char* text) SMTG_OVERRIDE;

	virtual void getParameterLabel (VstInt32 index, char* label) SMTG_OVERRIDE;
	virtual void getParameterDisplay (VstInt32 index, char* text) SMTG_OVERRIDE;
	virtual void getParameterName (VstInt32 index, char* text) SMTG_OVERRIDE;
	virtual bool canParameterBeAutomated (VstInt32 index) SMTG_OVERRIDE;
	virtual bool string2parameter (VstInt32 index, char* text) SMTG_OVERRIDE;
	virtual bool getParameterProperties (VstInt32 index, VstParameterProperties* p) SMTG_OVERRIDE;

	virtual VstInt32 getChunk (void** data, bool isPreset = false) SMTG_OVERRIDE;
	virtual VstInt32 setChunk (void* data, VstInt32 byteSize, bool isPreset = false) SMTG_OVERRIDE;

	virtual bool getInputProperties (VstInt32 index, VstPinProperties* properties) SMTG_OVERRIDE;
	virtual bool getOutputProperties (VstInt32 index, VstPinProperties* properties) SMTG_OVERRIDE;
	virtual bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput,
	                                    VstSpeakerArrangement* pluginOutput) SMTG_OVERRIDE;
	virtual bool getSpeakerArrangement (VstSpeakerArrangement** pluginInput,
	                                    VstSpeakerArrangement** pluginOutput) SMTG_OVERRIDE;
	virtual bool setBypass (bool onOff) SMTG_OVERRIDE;

	virtual bool setProcessPrecision (VstInt32 precision) SMTG_OVERRIDE;
	virtual VstInt32 getNumMidiInputChannels () SMTG_OVERRIDE;
	virtual VstInt32 getNumMidiOutputChannels () SMTG_OVERRIDE;
	virtual VstInt32 getGetTailSize () SMTG_OVERRIDE;
	virtual bool getEffectName (char* name) SMTG_OVERRIDE;
	virtual bool getVendorString (char* text) SMTG_OVERRIDE;
	virtual VstInt32 getVendorVersion () SMTG_OVERRIDE;
	virtual VstIntPtr vendorSpecific (VstInt32 lArg, VstIntPtr lArg2, void* ptrArg,
	                                  float floatArg) SMTG_OVERRIDE;
	virtual VstPlugCategory getPlugCategory () SMTG_OVERRIDE;
	virtual VstInt32 canDo (char* text) SMTG_OVERRIDE;

	virtual VstInt32 getMidiProgramName (VstInt32 channel,
	                                     MidiProgramName* midiProgramName) SMTG_OVERRIDE;
	virtual VstInt32 getCurrentMidiProgram (VstInt32 channel,
	                                        MidiProgramName* currentProgram) SMTG_OVERRIDE;
	virtual VstInt32 getMidiProgramCategory (VstInt32 channel,
	                                         MidiProgramCategory* category) SMTG_OVERRIDE;
	virtual bool hasMidiProgramsChanged (VstInt32 channel) SMTG_OVERRIDE;
	virtual bool getMidiKeyName (VstInt32 channel, MidiKeyName* keyName) SMTG_OVERRIDE;

	// finally process...
	virtual void processReplacing (float** inputs, float** outputs,
	                               VstInt32 sampleFrames) SMTG_OVERRIDE;
	virtual void processDoubleReplacing (double** inputs, double** outputs,
	                                     VstInt32 sampleFrames) SMTG_OVERRIDE;
	virtual VstInt32 processEvents (VstEvents* events) SMTG_OVERRIDE;

	// VST 3 Interfaces  ------------------------------------------------------
	// FUnknown
	virtual tresult PLUGIN_API queryInterface (const char* iid, void** obj) SMTG_OVERRIDE;
	virtual uint32 PLUGIN_API addRef () SMTG_OVERRIDE { return 1; }
	virtual uint32 PLUGIN_API release () SMTG_OVERRIDE { return 1; }

	// IHostApplication
	virtual tresult PLUGIN_API getName (String128 name) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API createInstance (TUID cid, TUID iid, void** obj) SMTG_OVERRIDE;

	// IComponentHandler
	virtual tresult PLUGIN_API beginEdit (ParamID tag) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API performEdit (ParamID tag, ParamValue valueNormalized) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API endEdit (ParamID tag) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API restartComponent (int32 flags) SMTG_OVERRIDE;

	// IUnitHandler
	virtual tresult PLUGIN_API notifyUnitSelection (UnitID unitId) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API notifyProgramListChange (ProgramListID listId,
	                                                    int32 programIndex) SMTG_OVERRIDE;

	void setVendorName (char* name);
	void setEffectName (char* name);
	void setEffectVersion (char* version);
	void setSubCategories (char* string);

	// ITimer
	virtual void onTimer (Timer* timer) SMTG_OVERRIDE;

//-------------------------------------------------------------------------------------------------------
protected:
	void setupBuses ();
	void setupParameters ();
	void initMidiCtrlerAssignment ();
	void getUnitPath (UnitID unitID, String& path);

	int32 countMainBusChannels (BusDirection dir, uint64& mainBusBitset);

	template <class T>
	void setProcessingBuffers (T** inputs, T** outputs);
	void setupProcessTimeInfo ();
	void doProcess (VstInt32 sampleFrames);
	void setEventPPQPositions ();
	void processOutputEvents ();
	void processMidiEvent (VstMidiEvent* midiEvent, int32 bus);

	/**	Returns the last param change from guiTransfer queue. */
	bool getLastParamChange (ParamID id, ParamValue& value);

	bool setupProcessing (int32 processModeOverwrite = -1);
	void addParameterChange (ParamID id, ParamValue value, int32 sampleOffset);

	bool getProgramListAndUnit (int32 midiChannel, UnitID& unitId, ProgramListID& programListId);
	bool getProgramListInfoByProgramListID (ProgramListID programListId, ProgramListInfo& info);
	int32 lookupProgramCategory (int32 midiChannel, String128 instrumentAttribute);
	bool setupMidiProgram (int32 midiChannel, ProgramListID programListId,
	                       MidiProgramName& midiProgramName);

	bool getPinProperties (BusDirection dir, VstInt32 pinIndex, VstPinProperties* properties);
	bool pinIndexToBusChannel (BusDirection dir, VstInt32 pinIndex, int32& busIndex,
	                           int32& busChannel);
	static VstInt32 vst3ToVst2SpeakerArr (SpeakerArrangement vst3Arr);
	static SpeakerArrangement vst2ToVst3SpeakerArr (VstInt32 vst2Arr);
	static VstInt32 vst3ToVst2Speaker (Speaker vst3Speaker);
	static void setupVst2Arrangement (VstSpeakerArrangement*& vst2arr,
	                                  Vst::SpeakerArrangement vst3Arrangement);

	struct ProgramCategory
	{
		MidiProgramCategory vst2Category;
		String128 vst3InstrumentAttribute;
	};
	std::vector<std::vector<ProgramCategory>> mProgramCategories;
	void setupProgramCategories ();
	static uint32 makeCategoriesRecursive (std::vector<ProgramCategory>& channelCategories,
	                                       String128 vst3Category);

	static const int32 kMaxProgramChangeParameters = 16;
	ParamID mProgramChangeParameterIDs[kMaxProgramChangeParameters]; // for each midi channel
	int32 mProgramChangeParameterIdxs[kMaxProgramChangeParameters]; // for each midi channel

	VstSpeakerArrangement* mVst2InputArrangement;
	VstSpeakerArrangement* mVst2OutputArrangement;

	FUID mVst3EffectClassID;

	// vst3 data
	IAudioProcessor* mProcessor;
	IComponent* mComponent;
	IEditController* mController;
	IUnitInfo* mUnitInfo;
	IMidiMapping* mMidiMapping;

	bool componentInitialized;
	bool controllerInitialized;
	bool componentsConnected;
	bool processing;
	bool hasEventInputBuses;
	bool hasEventOutputBuses;

	int32 mVst3SampleSize;
	int32 mVst3processMode;

	char mName[PClassInfo::kNameSize];
	char mVendor[PFactoryInfo::kNameSize];
	char mSubCategories[PClassInfo2::kSubCategoriesSize];
	int32 mVersion;

	struct ParamMapEntry
	{
		ParamID vst3ID;
		int32 vst3Index;
	};

	std::vector<ParamMapEntry> mParameterMap;
	std::map<ParamID, int32> mParamIndexMap;
	ParamID mBypassParameterID;
	ParamID mProgramParameterID;
	int32 mProgramParameterIdx;

	HostProcessData mProcessData;
	ProcessContext mProcessContext;
	ParameterChanges mInputChanges;
	ParameterChanges mOutputChanges;
	EventList* mInputEvents;
	EventList* mOutputEvents;
	Vst2MidiEventQueue* mVst2OutputEvents;
	uint64 mMainAudioInputBuses;
	uint64 mMainAudioOutputBuses;

	ParameterChangeTransfer mInputTransfer;
	ParameterChangeTransfer mOutputTransfer;
	ParameterChangeTransfer mGuiTransfer;

	MemoryStream mChunk;

	Timer* mTimer;
	IPluginFactory* mFactory;

	enum
	{
		kMaxMidiMappingBusses = 4
	};
	int32* mMidiCCMapping[kMaxMidiMappingBusses][16];
};

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg

/** Must be implemented externally. */
extern ::AudioEffect* createEffectInstance (audioMasterCallback audioMaster);

/// \endcond


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/PresetBrowserViewController.h
// Created by  : Steinberg, 09/2013
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

/// \cond ignore

#ifdef __OBJC__

#import <UIKit/UIKit.h>
#import <functional>

//-----------------------------------------------------------------------------
@interface PresetBrowserViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
//-----------------------------------------------------------------------------

- (id)initWithCallback:(std::function<void (const char* presetPath)>)callback;

- (void)setFactoryPresets:(NSArray*)factoryPresets userPresets:(NSArray*)userPresets;

@end

#endif // __OBJC__

/// \endcond

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/MidiIO.mm
// Created by  : Steinberg, 09/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "MidiIO.h"
#import <CoreMIDI/MIDINetworkSession.h>

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

//-----------------------------------------------------------------------------
MidiIO& MidiIO::instance ()
{
	static MidiIO gInstance;
	return gInstance;
}

//-----------------------------------------------------------------------------
MidiIO::MidiIO ()
: client (0)
, inputPort (0)
, destPort (0)
{
}

//-----------------------------------------------------------------------------
MidiIO::~MidiIO ()
{
	setEnabled (false);
}

//-----------------------------------------------------------------------------
void MidiIO::addProcessor (IMidiProcessor* processor)
{
	midiProcessors.push_back (processor);
}

//-----------------------------------------------------------------------------
void MidiIO::removeProcessor (IMidiProcessor* processor)
{
	auto it = std::find (midiProcessors.begin (), midiProcessors.end (), processor);
	if (it != midiProcessors.end ())
	{
		midiProcessors.erase (it);
	}
}

//-----------------------------------------------------------------------------
bool MidiIO::isEnabled () const
{
	return client != 0;
}

//-----------------------------------------------------------------------------
bool MidiIO::setEnabled (bool state)
{
	if (state)
	{
		if (client)
			return true;

		OSStatus err;
		NSString* name = [[NSBundle mainBundle] bundleIdentifier];
		if (err = MIDIClientCreate ((__bridge CFStringRef)name, notifyProc, this, &client) != noErr)
			return false;

		if (err = MIDIInputPortCreate (client, CFSTR("Input"), readProc, this, &inputPort) != noErr)
		{
			MIDIClientDispose (client);
			client = 0;
			return false;
		}
		name = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleDisplayName"];
		if (err = MIDIDestinationCreate (client, (__bridge CFStringRef)name, readProc, this, &destPort) != noErr)
		{
			MIDIPortDispose (inputPort);
			inputPort = 0;
			MIDIClientDispose (client);
			client = 0;
			return false;
		}
	}
	else
	{
		if (client == 0)
			return true;
		disconnectSources ();
		MIDIEndpointDispose (destPort);
		destPort = 0;
		MIDIPortDispose (inputPort);
		inputPort = 0;
		MIDIClientDispose (client);
		client = 0;
	}
	return true;
}

//-----------------------------------------------------------------------------
void MidiIO::setMidiNetworkEnabled (bool state)
{
	if (inputPort && isMidiNetworkEnabled() != state)
	{
		if (!state)
		{
			MIDIPortDisconnectSource (inputPort, [MIDINetworkSession defaultSession].sourceEndpoint);
		}
		[MIDINetworkSession defaultSession].enabled = state;
		if (state)
		{
			MIDIPortConnectSource (inputPort, [MIDINetworkSession defaultSession].sourceEndpoint, 0);
		}
	}
}

//-----------------------------------------------------------------------------
bool MidiIO::isMidiNetworkEnabled () const
{
	return [MIDINetworkSession defaultSession].isEnabled;
}

//-----------------------------------------------------------------------------
void MidiIO::setMidiNetworkPolicy (MIDINetworkConnectionPolicy policy)
{
	[MIDINetworkSession defaultSession].connectionPolicy = policy;
}

//-----------------------------------------------------------------------------
MIDINetworkConnectionPolicy MidiIO::getMidiNetworkPolicy () const
{
	return [MIDINetworkSession defaultSession].connectionPolicy;
}

//-----------------------------------------------------------------------------
void MidiIO::onInput (const MIDIPacketList *pktlist)
{
	const MIDIPacket* packet = &pktlist->packet[0];
	for (UInt32 i = 0; i < pktlist->numPackets; i++)
	{
		for (auto processor : midiProcessors)
		{
			processor->onMIDIEvent (packet->data[0], packet->data[1], packet->data[2], 0, false);
		}
		packet = MIDIPacketNext (packet);
	}
}

//-----------------------------------------------------------------------------
void MidiIO::onSourceAdded (MIDIObjectRef source)
{
	connectedSources.push_back ((MIDIEndpointRef)source);
	MIDIPortConnectSource (inputPort, (MIDIEndpointRef)source, NULL);
}

//-----------------------------------------------------------------------------
void MidiIO::disconnectSources ()
{
	for (auto source : connectedSources)
		MIDIPortDisconnectSource (inputPort, source);
	connectedSources.clear ();
}

//-----------------------------------------------------------------------------
void MidiIO::onSetupChanged ()
{
	disconnectSources ();
	ItemCount numSources = MIDIGetNumberOfSources ();
	for (ItemCount i = 0; i < numSources; i++)
	{
		onSourceAdded (MIDIGetSource (i));
	}
}

//-----------------------------------------------------------------------------
void MidiIO::readProc (const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon)
{
	MidiIO* io = static_cast<MidiIO*>(readProcRefCon);
	io->onInput (pktlist);
}

//-----------------------------------------------------------------------------
void MidiIO::notifyProc (const MIDINotification *message, void *refCon)
{
	if (message->messageID == kMIDIMsgSetupChanged)
	{
		MidiIO* mio = (MidiIO*)refCon;
		mio->onSetupChanged ();
	}
}

}}} // namespaces


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/VSTInterAppAudioAppDelegateBase.mm
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "VSTInterAppAudioAppDelegateBase.h"

#import "public.sdk/source/vst/interappaudio/AudioIO.h"
#import "public.sdk/source/vst/interappaudio/MidiIO.h"
#import "public.sdk/source/vst/interappaudio/VST3Plugin.h"
#import "public.sdk/source/vst/interappaudio/VST3Editor.h"
#import "public.sdk/source/vst/interappaudio/HostApp.h"

using namespace Steinberg::Vst::InterAppAudio;

//------------------------------------------------------------------------
static OSType fourCharCodeToOSType (NSString* inCode)
{
	OSType rval = 0;
	NSData* data = [inCode dataUsingEncoding: NSMacOSRomanStringEncoding];
	[data getBytes:&rval length:sizeof(rval)];
	HTONL(rval);
	return rval;
}

//------------------------------------------------------------------------
@interface VSTInterAppAudioAppDelegateBase ()
//------------------------------------------------------------------------
{
	VST3Plugin plugin;
	VST3Editor editor;

	BOOL audioIOInitialized;
}
@end

//------------------------------------------------------------------------
@implementation VSTInterAppAudioAppDelegateBase
//------------------------------------------------------------------------

//------------------------------------------------------------------------
- (BOOL)initAudioIO
{
	id auArray = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AudioComponents"];
	if (auArray)
	{
		id desc = [auArray objectAtIndex:0];
		if (desc)
		{
			NSString* typeStr = [desc objectForKey:@"type"];
			NSString* subtypeStr = [desc objectForKey:@"subtype"];
			NSString* manufacturerStr = [desc objectForKey:@"manufacturer"];
			NSString* nameStr = [desc objectForKey:@"name"];
			if (typeStr && subtypeStr && manufacturerStr && nameStr)
			{
				OSType type = fourCharCodeToOSType (typeStr);
				OSType subtype = fourCharCodeToOSType (subtypeStr);
				OSType manufacturer = fourCharCodeToOSType (manufacturerStr);
				AudioIO* audioIO = AudioIO::instance ();
				if (audioIO->init (type, subtype, manufacturer, (__bridge CFStringRef)nameStr) == Steinberg::kResultTrue)
				{
					if (plugin.init ())
					{
						InterAppAudioHostApp::instance ()->setPlugin (&plugin);
						audioIO->addProcessor (&plugin);
						audioIOInitialized = YES;
						return YES;
					}
				}
			}
		}
	}
	return NO;
}

//------------------------------------------------------------------------
- (BOOL)createUI
{
	if (audioIOInitialized)
	{
		[UIApplication sharedApplication].statusBarHidden = YES;
		self.window = [UIWindow new];
		self.window.backgroundColor = [UIColor redColor];
		CGRect screenSize = self.window.bounds;

		if (editor.init (screenSize))
		{
			self.window.rootViewController = editor.getViewController ();
			[self.window makeKeyAndVisible];
			if (editor.attach (plugin.getEditController ()) == false)
			{
				return NO;
			}
		}
		return YES;
	}
	return NO;
}

//------------------------------------------------------------------------
- (void)savePluginState:(NSCoder*)coder
{
	NSData* processorState = plugin.getProcessorState ();
	NSData* controllerState = plugin.getControllerState ();
	if (processorState)
		[coder encodeObject:processorState forKey:@"VST3ProcessorState"];
	if (controllerState)
		[coder encodeObject:controllerState forKey:@"VST3ControllerState"];
}

//------------------------------------------------------------------------
- (void)restorePluginState:(NSCoder*)coder
{
	NSData* processorState = [coder decodeObjectForKey:@"VST3ProcessorState"];
	if (processorState)
	{
		plugin.setProcessorState (processorState);
	}
	NSData* controllerState = [coder decodeObjectForKey:@"VST3ControllerState"];
	if (controllerState)
	{
		plugin.setControllerState (controllerState);
	}
}

//------------------------------------------------------------------------
// UIApplicationDelegate methods
//------------------------------------------------------------------------
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	return [self initAudioIO];
}

//------------------------------------------------------------------------
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	BOOL result = [self createUI];
	if (result)
	{
		AudioIO::instance ()->start ();
	}
	return result;
}

//------------------------------------------------------------------------
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
	[self savePluginState:coder];
	[coder encodeBool:MidiIO::instance ().isEnabled () forKey:@"MIDI Enabled"];
	return YES;
}

//------------------------------------------------------------------------
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
	[self restorePluginState:coder];
	BOOL midiEnabled = [coder decodeBoolForKey:@"MIDI Enabled"];
	MidiIO::instance ().setEnabled (midiEnabled);
	return YES;
}

//------------------------------------------------------------------------
- (void)applicationDidBecomeActive:(UIApplication *)application
{
	AudioIO* audioIO = AudioIO::instance ();
	audioIO->start ();
}

//------------------------------------------------------------------------
- (void)applicationWillResignActive:(UIApplication *)application
{
	AudioIO* audioIO = AudioIO::instance ();
	if (audioIO->getInterAppAudioConnected () == false && MidiIO::instance().isEnabled () == false)
	{
		audioIO->stop ();
	}
}

@end


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/PresetBrowserViewController.mm
// Created by  : Steinberg, 09/2013
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "PresetBrowserViewController.h"
#import "pluginterfaces/base/funknown.h"

static NSTimeInterval kAnimationTime = 0.2;

//------------------------------------------------------------------------
@interface PresetBrowserViewController ()
//------------------------------------------------------------------------
{
	IBOutlet UITableView* presetTableView;
	IBOutlet UIView* containerView;

	std::function<void (const char* presetPath)> callback;
	Steinberg::FUID uid;
}

@property (strong) NSArray* factoryPresets;
@property (strong) NSArray* userPresets;
@property (strong) NSArray* displayPresets;
@property (assign) BOOL editMode;

@end

//------------------------------------------------------------------------
@implementation PresetBrowserViewController
//------------------------------------------------------------------------

//------------------------------------------------------------------------
- (id)initWithCallback:(std::function<void (const char* presetPath)>)_callback
{
    self = [super initWithNibName:@"PresetBrowserView" bundle:nil];
    if (self)
	{
		callback = _callback;

		self.view.alpha = 0.;

		UIViewController* rootViewController = [[UIApplication sharedApplication].windows[0] rootViewController];
		[rootViewController addChildViewController:self];
		[rootViewController.view addSubview:self.view];

		[UIView animateWithDuration:kAnimationTime animations:^{
			self.view.alpha = 1.;
		}];
	}
	return self;
}

//------------------------------------------------------------------------
- (void)setFactoryPresets:(NSArray*)factoryPresets userPresets:(NSArray*)userPresets
{
	self.factoryPresets = factoryPresets;
	self.userPresets = userPresets;
	[self updatePresetArray];
	dispatch_async (dispatch_get_main_queue (), ^{
		[presetTableView reloadData];
	});
}

//------------------------------------------------------------------------
- (void)viewDidLoad
{
    [super viewDidLoad];

	containerView.layer.shadowOpacity = 0.5;
	containerView.layer.shadowOffset = CGSizeMake (5, 5);
	containerView.layer.shadowRadius = 5;
}

//------------------------------------------------------------------------
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

//------------------------------------------------------------------------
- (void)updatePresetArray
{
	if (self.userPresets)
	{
		self.displayPresets = [[self.factoryPresets arrayByAddingObjectsFromArray:self.userPresets] sortedArrayUsingComparator:^NSComparisonResult (NSURL* obj1, NSURL* obj2) {
			return [[obj1 lastPathComponent] caseInsensitiveCompare:[obj2 lastPathComponent]];
		}];
	}
	else
	{
		self.displayPresets = self.factoryPresets;
	}
}

//------------------------------------------------------------------------
- (void)removeSelf
{
	[UIView animateWithDuration:kAnimationTime animations:^{
		self.view.alpha = 0.;
	} completion:^(BOOL finished) {
		[self.view removeFromSuperview];
		[self removeFromParentViewController];
	}];
}

//------------------------------------------------------------------------
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	NSURL* url = [self.displayPresets objectAtIndex:indexPath.row];
	if (url)
	{
		callback ([[url path] UTF8String]);
	}
	[self removeSelf];
}

//------------------------------------------------------------------------
- (IBAction)toggleEditMode:(id)sender
{
	self.editMode = !self.editMode;
	if (self.editMode)
	{
		NSMutableArray* indexPaths = [NSMutableArray new];
		for (NSURL* url in self.factoryPresets)
		{
			NSUInteger index = [self.displayPresets indexOfObjectIdenticalTo:url];
			[indexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]];
		}
		[presetTableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
	}
	else
	{
		[self updatePresetArray];
		NSMutableArray* indexPaths = [NSMutableArray new];
		for (NSURL* url in self.factoryPresets)
		{
			NSUInteger index = [self.displayPresets indexOfObjectIdenticalTo:url];
			[indexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]];
		}
		[presetTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
	}
	[presetTableView setEditing:self.editMode animated:YES];
}

//------------------------------------------------------------------------
- (IBAction)cancel:(id)sender
{
	if (callback)
	{
		callback (0);
	}
	[self removeSelf];
}

//------------------------------------------------------------------------
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	if (self.editMode)
	{
		return [self.userPresets count];
	}
	return [self.displayPresets count];
}

//------------------------------------------------------------------------
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PresetBrowserCell"];
	if (cell == nil)
	{
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"PresetBrowserCell"];
	}

	cell.backgroundColor = [UIColor clearColor];

	NSURL* presetUrl = nil;
	if (self.editMode)
	{
		presetUrl = [self.userPresets objectAtIndex:indexPath.row];
		cell.detailTextLabel.text = @"User";
	}
	else
	{
		presetUrl = [self.displayPresets objectAtIndex:indexPath.row];
		if ([self.factoryPresets indexOfObject:presetUrl] == NSNotFound)
		{
			cell.detailTextLabel.text = @"User";
		}
		else
		{
			cell.detailTextLabel.text = @"Factory";
		}
	}

	cell.textLabel.text = [[presetUrl lastPathComponent] stringByDeletingPathExtension];

	return cell;
}

//------------------------------------------------------------------------
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
	if (self.editMode)
	{
		return YES;
	}
	return NO;
}

//------------------------------------------------------------------------
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
	NSURL* presetUrl = [self.userPresets objectAtIndex:indexPath.row];
	if (presetUrl)
	{
		NSFileManager* fs = [NSFileManager defaultManager];
		NSError* error = nil;
		if ([fs removeItemAtURL:presetUrl error:&error] == NO)
		{
			UIAlertView *alert = [[UIAlertView alloc]
								  initWithTitle:[error localizedDescription]
								  message:[error localizedRecoverySuggestion]
								  delegate:nil
								  cancelButtonTitle:NSLocalizedString(@"Dismiss", @"")
								  otherButtonTitles:nil];

			[alert show];
		}
		else
		{
			NSMutableArray* newArray = [NSMutableArray arrayWithArray:self.userPresets];
			[newArray removeObject:presetUrl];
			self.userPresets = newArray;
			[presetTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
		}
	}
}

@end


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/SettingsViewController.mm
// Created by  : Steinberg, 09/2013
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "SettingsViewController.h"
#import "MidiIO.h"
#import "AudioIO.h"
#import <CoreMIDI/MIDINetworkSession.h>

using namespace Steinberg::Vst::InterAppAudio;

static const NSTimeInterval kAnimationTime = 0.2;
static const NSUInteger kMinTempo = 30;

//------------------------------------------------------------------------
@interface SettingsViewController ()
//------------------------------------------------------------------------
{
	IBOutlet UIView* containerView;
	IBOutlet UISwitch* midiOnSwitch;
	IBOutlet UIPickerView* tempoView;
}
@end

//------------------------------------------------------------------------
@implementation SettingsViewController
//------------------------------------------------------------------------

//------------------------------------------------------------------------
- (id)init
{
    self = [super initWithNibName:@"SettingsView" bundle:nil];
    if (self)
	{
        // Custom initialization
    }
    return self;
}

//------------------------------------------------------------------------
- (void)viewDidLoad
{
    [super viewDidLoad];

	containerView.layer.shadowOpacity = 0.5;
	containerView.layer.shadowOffset = CGSizeMake (5, 5);
	containerView.layer.shadowRadius = 5;

	midiOnSwitch.on = MidiIO::instance ().isEnabled ();

	Float64 tempo = AudioIO::instance()->getStaticFallbackTempo ();
	[tempoView selectRow:tempo - kMinTempo inComponent:0 animated:YES];
}

//------------------------------------------------------------------------
- (IBAction)enableMidi:(id)sender
{
	BOOL state = midiOnSwitch.on;
	MidiIO::instance().setEnabled (state);
}

//------------------------------------------------------------------------
- (IBAction)close:(id)sender
{
	[UIView animateWithDuration:kAnimationTime animations:^{
		self.view.alpha = 0.;
	} completion:^(BOOL finished) {
		[self.view removeFromSuperview];
		[self removeFromParentViewController];
	}];
}

//------------------------------------------------------------------------
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
	AudioIO::instance()->setStaticFallbackTempo (row + kMinTempo);
}

//------------------------------------------------------------------------
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
	return 1;
}

//------------------------------------------------------------------------
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
	return 301 - kMinTempo;
}

//------------------------------------------------------------------------
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
	return [@(row + kMinTempo) stringValue];
}

@end

//------------------------------------------------------------------------
void showIOSettings ()
{
	SettingsViewController* controller = [[SettingsViewController alloc] init];
	controller.view.alpha = 0.;

	UIViewController* rootViewController = [[UIApplication sharedApplication].windows[0] rootViewController];
	[rootViewController addChildViewController:controller];
	[rootViewController.view addSubview:controller.view];

	[UIView animateWithDuration:kAnimationTime animations:^{
		controller.view.alpha = 1.;
	}];
}


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/VST3Editor.mm
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "VST3Editor.h"
#import "pluginterfaces/vst/ivsteditcontroller.h"

//------------------------------------------------------------------------
@interface VST3EditorViewController : UIViewController
//------------------------------------------------------------------------

@end

//------------------------------------------------------------------------
@implementation VST3EditorViewController
//------------------------------------------------------------------------

- (BOOL)prefersStatusBarHidden { return YES; }
- (BOOL)shouldAutorotate { return YES; }
- (NSUInteger)supportedInterfaceOrientations
{
	return UIInterfaceOrientationMaskLandscapeLeft|UIInterfaceOrientationMaskLandscapeRight;
}

@end

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

//------------------------------------------------------------------------
VST3Editor::VST3Editor ()
: plugView (0)
, viewController (0)
{

}

//------------------------------------------------------------------------
VST3Editor::~VST3Editor ()
{
	if (plugView)
	{
		plugView->release ();
	}
}

//------------------------------------------------------------------------
bool VST3Editor::init (const CGRect& frame)
{
	viewController = [VST3EditorViewController new];
	viewController.view = [[UIView alloc] initWithFrame:frame];
	return true;
}

//------------------------------------------------------------------------
bool VST3Editor::attach (IEditController* editController)
{
	FUnknownPtr<IEditController2> ec2 (editController);
	if (ec2)
	{
		ec2->setKnobMode (kLinearMode);
	}
	plugView = editController->createView (ViewType::kEditor);
	if (plugView)
	{
		if (plugView->isPlatformTypeSupported (kPlatformTypeUIView) == kResultTrue)
		{
			plugView->setFrame (this);
			if (plugView->attached ((__bridge void*)viewController.view, kPlatformTypeUIView) == kResultTrue)
			{
				return true;
			}
		}
		plugView->release ();
		plugView = 0;
	}

	return false;
}

//------------------------------------------------------------------------
tresult PLUGIN_API VST3Editor::resizeView (IPlugView* view, ViewRect* newSize)
{
	if (newSize && plugView && plugView == view)
	{
		if (view->onSize (newSize) == kResultTrue)
			return kResultTrue;
		return kResultFalse;
	}
	return kInvalidArgument;
}

//------------------------------------------------------------------------
} // InterAppAudio
} // Vst
} // Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/VST3Plugin.mm
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "VST3Plugin.h"
#import "HostApp.h"
#import "pluginterfaces/base/ipluginbase.h"
#import "pluginterfaces/vst/ivstmessage.h"
#import "pluginterfaces/vst/ivstmidicontrollers.h"
#import "pluginterfaces/vst/ivstinterappaudio.h"
#import "public.sdk/source/vst/auwrapper/NSDataIBStream.h"
#import "public.sdk/source/vst/hosting/hostclasses.h"
#import "base/source/updatehandler.h"
#import <libkern/OSAtomic.h>

//------------------------------------------------------------------------
extern "C"
{
	bool bundleEntry (CFBundleRef);
	bool bundleExit (void);
}

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

//------------------------------------------------------------------------
__attribute__((constructor))
static void InitUpdateHandler ()
{
	UpdateHandler::instance ();
}

//------------------------------------------------------------------------
VST3Plugin::VST3Plugin ()
: processor (0)
, editController (0)
, timer (0)
, processing (false)
{
	processData.processContext = &processContext;
	processData.inputParameterChanges = &inputParamChanges;
	processData.outputParameterChanges = &outputParamChanges;
	processData.inputEvents = &inputEvents;

}

//------------------------------------------------------------------------
VST3Plugin::~VST3Plugin ()
{
}

//------------------------------------------------------------------------
bool VST3Plugin::init ()
{
	if (processor == 0 && editController == 0)
	{
		::bundleEntry (CFBundleGetMainBundle ());
		createProcessorAndController ();
	}
	return processor && editController;
}

//------------------------------------------------------------------------
void VST3Plugin::createProcessorAndController ()
{
	Steinberg::IPluginFactory* factory = GetPluginFactory ();
	if (factory == 0)
		return;
	IComponent* component = 0;
	PClassInfo classInfo;
	int32 classCount = factory->countClasses ();
	for (int32 i = 0; i < classCount; i++)
	{
		if (factory->getClassInfo (i, &classInfo) != kResultTrue)
			return;
		if (strcmp (classInfo.category, kVstAudioEffectClass) == 0)
		{
			if (factory->createInstance (classInfo.cid, IComponent::iid, (void **)&component) != kResultTrue)
			{
				return;
			}
			break;
		}
	}
	if (component)
	{
		if (component->initialize (InterAppAudioHostApp::instance ()->unknownCast ()) != kResultTrue)
		{
			component->release ();
			return;
		}
		if (component->queryInterface (IEditController::iid, (void**)&editController) != kResultTrue)
		{
			FUID controllerCID;
			if (component->getControllerClassId (controllerCID) == kResultTrue && controllerCID.isValid ())
			{
				if (factory->createInstance (controllerCID, IEditController::iid, (void**)&editController) != kResultTrue)
					return;
				editController->setComponentHandler (this);
				if (editController->initialize (InterAppAudioHostApp::instance ()->unknownCast ()) != kResultTrue)
				{
					component->release ();
					editController->release ();
					editController = 0;
					return;
				}
				FUnknownPtr<IConnectionPoint> compConnection (component);
				FUnknownPtr<IConnectionPoint> ctrlerConnection (editController);
				if (compConnection && ctrlerConnection)
				{
					compConnection->connect (ctrlerConnection);
					ctrlerConnection->connect (compConnection);
				}
			}
			else
			{
				component->release ();
				return;
			}
		}
		component->queryInterface (IAudioProcessor::iid, (void**)&processor);
		if (processor == 0)
		{
			if (editController)
			{
				editController->release ();
				editController = 0;
			}
		}
		else
		{
			NSMutableData* data = [NSMutableData new];
			NSMutableDataIBStream state (data);
			if (component->getState (&state) == kResultTrue)
			{
				state.seek (0, IBStream::kIBSeekSet);
				editController->setComponentState (&state);
			}
			int32 paramCount = editController->getParameterCount ();
			inputParamChanges.setMaxParameters (paramCount);
			inputParamChangeTransfer.setMaxParameters (paramCount);
			outputParamChanges.setMaxParameters (paramCount);
			outputParamChangeTransfer.setMaxParameters (paramCount);
			midiControllerToParamIDMap = createMIDIControllerToParamIDMap ();
			uiScheduledEvents.resize (kMaxUIEvents);
		}
		component->release ();
	}
}

//------------------------------------------------------------------------
VST3Plugin::MIDIControllerToParamIDMap VST3Plugin::createMIDIControllerToParamIDMap ()
{
	MIDIControllerToParamIDMap newMap;

	FUnknownPtr<IMidiMapping> midiMapping (editController);
	if (midiMapping)
	{
		uint16 channelCount = 0;
		FUnknownPtr<IComponent> component (processor);
		if (component)
		{
			int32 busCount = component->getBusCount (kEvent, kInput);
			if (busCount > 0)
			{
				BusInfo busInfo;
				if (component->getBusInfo (kEvent, kInput, 0, busInfo) == kResultTrue)
				{
					channelCount = busInfo.channelCount;
				}
			}
		}

		ParamID paramID;
		for (int32 channel = 0; channel < channelCount; channel++)
		{
			for (CtrlNumber ctrler = 0; ctrler < kCountCtrlNumber; ctrler++)
			{
				if (midiMapping->getMidiControllerAssignment (0, channel, ctrler, paramID) == kResultTrue)
				{
					newMap.insert (std::make_pair (channelAndCtrlNumber (channel, ctrler), paramID));
				}
			}
		}
	}
	return newMap;
}

//------------------------------------------------------------------------
tresult VST3Plugin::scheduleEventFromUI (Event& event)
{
	if (event.type == Event::kNoteOnEvent)
		event.noteOn.noteId = lastNodeID++;
	return uiScheduledEvents.write (event) ? kResultTrue : kResultFalse;
}

//------------------------------------------------------------------------
NSData* VST3Plugin::getProcessorState ()
{
	if (processor)
	{
		NSMutableData* data = [NSMutableData new];
		NSMutableDataIBStream state (data);
		FUnknownPtr<IComponent> comp (processor);
		if (comp->getState (&state) == kResultTrue)
		{
			return data;
		}
	}
	return nil;
}

//------------------------------------------------------------------------
bool VST3Plugin::setProcessorState (NSData* data)
{
	if (editController && processor)
	{
		NSDataIBStream stream (data);
		FUnknownPtr<IComponent> comp (processor);
		if (comp->setState (&stream) == kResultTrue)
		{
			stream.seek (0, IBStream::kIBSeekSet);
			editController->setComponentState (&stream);
			return true;
		}
	}

	return false;
}

//------------------------------------------------------------------------
NSData* VST3Plugin::getControllerState ()
{
	if (editController)
	{
		NSMutableData* data = [NSMutableData new];
		NSMutableDataIBStream state (data);
		if (editController->getState (&state) == kResultTrue)
		{
			return data;
		}
	}
	return nil;
}

//------------------------------------------------------------------------
bool VST3Plugin::setControllerState (NSData* data)
{
	if (editController)
	{
		NSDataIBStream stream (data);
		if (editController->setState (&stream) == kResultTrue)
		{
			return true;
		}
	}
	return false;
}

//------------------------------------------------------------------------
void VST3Plugin::willStartAudio (AudioIO* audioIO)
{
	noteIDPitchMap.clear ();
	lastNodeID.store (0);

	ProcessSetup setup;
	setup.processMode = kRealtime;
	setup.symbolicSampleSize = kSample32;
	setup.maxSamplesPerBlock = 4096;// TODO:
	setup.sampleRate = audioIO->getSampleRate ();
	processor->setupProcessing (setup);
	SpeakerArrangement inputs[1];
	SpeakerArrangement outputs[1];
	inputs[0] = SpeakerArr::kStereo;
	outputs[0] = SpeakerArr::kStereo;
	processor->setBusArrangements (inputs, 1, outputs, 1);

	FUnknownPtr<IComponent> comp (processor);
	comp->setActive (true);

	processData.prepare (*comp);

	FUnknownPtr<IInterAppAudioConnectionNotification> iaaConnectionNotification (editController);
	if (iaaConnectionNotification)
	{
		iaaConnectionNotification->onInterAppAudioConnectionStateChange (audioIO->getInterAppAudioConnected () ? true : false);
	}

	timer = Timer::create (this, 16);
}

//------------------------------------------------------------------------
void VST3Plugin::didStopAudio (AudioIO* audioIO)
{
	processor->setProcessing (false); // TODO: currently not called in Audio Thread as it should according to the VST3 spec
	processing = false;

	FUnknownPtr<IComponent> comp (processor);
	comp->setActive (false);
	timer->release ();
	timer = 0;
}

//------------------------------------------------------------------------
void VST3Plugin::onMIDIEvent (UInt32 inStatus, UInt32 data1, UInt32 data2, UInt32 sampleOffset, bool withinRealtimeThread)
{
	Event e = {};
	e.flags = Event::kIsLive;

	uint16 status = inStatus & 0xF0;
	uint16 channel = inStatus & 0x0F;
	if (status == 0x90 && data2 != 0) // note on
	{
		auto noteID = noteIDPitchMap.find ((channel << 8) + data1);
		if (noteID != noteIDPitchMap.end ())
		{
			// for now, we just turn off the old note on
			Event e2 = {};
			e2.type = Event::kNoteOffEvent;
			e2.noteOff.noteId = noteID->second;
			e2.noteOff.channel = channel;
			e2.noteOff.pitch = data1;
			e2.noteOff.velocity = (float)data2 / 128.f;
			e2.sampleOffset = 0;
			inputEvents.addEvent (e2);
			noteIDPitchMap.erase (noteID);
		}
		e.type = Event::kNoteOnEvent;
		e.noteOn.channel = channel;
		e.noteOn.pitch = data1;
		e.noteOn.velocity = (float)data2 / 128.f;
		e.noteOn.length = -1;
		e.sampleOffset = sampleOffset;
		if (withinRealtimeThread)
		{
			e.noteOn.noteId = lastNodeID++;
			inputEvents.addEvent (e);
			noteIDPitchMap.insert (std::make_pair ((channel << 8) + data1, e.noteOn.noteId));
		}
		else
		{
			scheduleEventFromUI (e);
		}
	}
	else if (status == 0x80 || (status == 0x90 && data2 == 0)) // note off
	{
		auto noteID = noteIDPitchMap.find ((channel << 8) + data1);
		if (noteID != noteIDPitchMap.end())
		{
			e.type = Event::kNoteOffEvent;
			e.noteOff.noteId = noteID->second;
			e.noteOff.channel = channel;
			e.noteOff.pitch = data1;
			e.noteOff.velocity = (float)data2 / 128.f;
			e.sampleOffset = sampleOffset;
			if (withinRealtimeThread)
			{
				inputEvents.addEvent (e);
				noteIDPitchMap.erase (noteID);
			}
			else
			{
				scheduleEventFromUI (e);
			}
		}
		else
		{
			NSLog (@"NoteID not found:%d", (unsigned int)data1);
		}
	}
	else if (status == 0xb0 && data1 < kAfterTouch) // controller
	{
		auto it = midiControllerToParamIDMap.find (channelAndCtrlNumber (channel, data1));
		if (it != midiControllerToParamIDMap.end ())
		{
			ParamValue value = (ParamValue)data2 / 128.;
			if (withinRealtimeThread)
			{
				int32 index;
				IParamValueQueue* queue = inputParamChanges.addParameterData (it->second, index);
				if (queue)
				{
					queue->addPoint (sampleOffset, value, index);
				}
			}
			else
			{
				inputParamChangeTransfer.addChange (it->second, value, sampleOffset);
			}
		}
	}
	else if (status == 0xe0) // pitch bend
	{
		auto it = midiControllerToParamIDMap.find (channelAndCtrlNumber (channel, kPitchBend));
		if (it != midiControllerToParamIDMap.end ())
		{
			uint16 _14bit;
			_14bit = (uint16)data2;
			_14bit <<= 7;
			_14bit |= (uint16)data1;
			ParamValue value = (double)_14bit / (double)0x3fff;

			if (withinRealtimeThread)
			{
				int32 index;
				IParamValueQueue* queue = inputParamChanges.addParameterData (it->second, index);
				if (queue)
				{
					queue->addPoint (sampleOffset, value, index);
				}
			}
			else
			{
				inputParamChangeTransfer.addChange (it->second, value, sampleOffset);
			}
		}
	}
	else if (status == 0xd0) // aftertouch
	{
		auto it = midiControllerToParamIDMap.find (channelAndCtrlNumber (channel, kAfterTouch));
		if (it != midiControllerToParamIDMap.end ())
		{
			ParamValue value = (ParamValue)data1 / 128.;
			if (withinRealtimeThread)
			{
				int32 index;
				IParamValueQueue* queue = inputParamChanges.addParameterData (it->second, index);
				if (queue)
				{
					queue->addPoint (sampleOffset, value, index);
				}
			}
			else
			{
				inputParamChangeTransfer.addChange (it->second, value, sampleOffset);
			}
		}
	}
}

//------------------------------------------------------------------------
void VST3Plugin::process (const AudioTimeStamp* timeStamp, UInt32 busNumber, UInt32 numFrames, AudioBufferList* ioData, bool& outputIsSilence, AudioIO* audioIO)
{
	if (processing == false)
	{
		processor->setProcessing (true);
		processing = true;
	}
	updateProcessContext (audioIO);
	if (timeStamp)
		processContext.systemTime = timeStamp->mHostTime;

	// TODO: silence state update
	for (UInt32 i = 0; i < ioData->mNumberBuffers; i++)
	{
		processData.setChannelBuffer (kInput, 0, i, (float*)ioData->mBuffers[i].mData);
		processData.setChannelBuffer (kOutput, 0, i, (float*)ioData->mBuffers[i].mData);
	}

	Event e;
	while (uiScheduledEvents.read (e))
	{
		inputEvents.addEvent (e);
		if (e.type == Event::kNoteOnEvent)
		{
			auto noteID = noteIDPitchMap.find ((e.noteOn.channel << 8) + e.noteOn.pitch);
			if (noteID == noteIDPitchMap.end ())
				noteIDPitchMap.insert (std::make_pair ((e.noteOn.channel << 8) + e.noteOn.pitch, e.noteOn.noteId));
		}
	}

	processData.numSamples = numFrames;
	inputParamChangeTransfer.transferChangesTo (inputParamChanges);
	if (processor->process (processData) == kResultTrue)
	{
		inputParamChanges.clearQueue ();
		outputParamChangeTransfer.transferChangesFrom (outputParamChanges);
		outputParamChanges.clearQueue ();
		inputEvents.clear ();
	}
}

//------------------------------------------------------------------------
void VST3Plugin::updateProcessContext (AudioIO* audioIO)
{
	memset (&processContext, 0, sizeof (ProcessContext));
	processContext.sampleRate = audioIO->getSampleRate ();
	Float64 beat = 0., tempo = 0.;
	if (audioIO->getBeatAndTempo (beat, tempo))
	{
		processContext.state |= ProcessContext::kTempoValid | ProcessContext::kProjectTimeMusicValid;
		processContext.tempo = tempo;
		processContext.projectTimeMusic = beat;
	}
	else
	{
		processContext.state |= ProcessContext::kTempoValid;
		processContext.tempo = 120.;
	}
	UInt32 deltaSampleOffsetToNextBeat = 0;
	Float32 timeSigNumerator = 0;
	UInt32 timeSigDenominator = 0;
	Float64 currentMeasureDownBeat = 0;
	if (audioIO->getMusicalTimeLocation (deltaSampleOffsetToNextBeat, timeSigNumerator, timeSigDenominator, currentMeasureDownBeat))
	{
		processContext.state |= ProcessContext::kTimeSigValid | ProcessContext::kBarPositionValid | ProcessContext::kClockValid;
		processContext.timeSigNumerator = timeSigNumerator;
		processContext.timeSigDenominator = timeSigDenominator;
		processContext.samplesToNextClock = deltaSampleOffsetToNextBeat;
		processContext.barPositionMusic = currentMeasureDownBeat;
	}
	Boolean isPlaying;
	Boolean isRecording;
	Boolean transportStateChanged;
	Float64 currentSampleInTimeLine;
	Boolean isCycling;
	Float64 cycleStartBeat;
	Float64 cycleEndBeat;
	if (audioIO->getTransportState (isPlaying, isRecording, transportStateChanged, currentSampleInTimeLine, isCycling, cycleStartBeat, cycleEndBeat))
	{
		processContext.state |= ProcessContext::kCycleValid;
		processContext.cycleStartMusic = cycleStartBeat;
		processContext.cycleEndMusic = cycleEndBeat;
		processContext.projectTimeSamples = currentSampleInTimeLine;
		if (isPlaying)
			processContext.state |= ProcessContext::kPlaying;
		if (isCycling)
			processContext.state |= ProcessContext::kCycleActive;
		if (isRecording)
			processContext.state |= ProcessContext::kRecording;
	}
}

//------------------------------------------------------------------------
tresult PLUGIN_API VST3Plugin::beginEdit (ParamID id)
{
	return kResultTrue;
}

//------------------------------------------------------------------------
tresult PLUGIN_API VST3Plugin::performEdit (ParamID id, ParamValue valueNormalized)
{
	inputParamChangeTransfer.addChange (id, valueNormalized, 0);
	return kResultTrue;
}

//------------------------------------------------------------------------
tresult PLUGIN_API VST3Plugin::endEdit (ParamID id)
{
	return kResultTrue;
}

//------------------------------------------------------------------------
tresult PLUGIN_API VST3Plugin::restartComponent (int32 flags)
{
	tresult result = kNotImplemented;

	return result;
}

//------------------------------------------------------------------------
void VST3Plugin::onTimer (Timer* timer)
{
	ParamID paramID;
	ParamValue paramValue;
	int32 sampleOffset;
	while (outputParamChangeTransfer.getNextChange (paramID, paramValue, sampleOffset))
	{
		editController->setParamNormalized (paramID, paramValue);
	}
	UpdateHandler::instance ()->triggerDeferedUpdates ();
}

}}}


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/MidiIO.h
// Created by  : Steinberg, 09/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include <CoreMIDI/CoreMIDI.h>
#include "AudioIO.h"
#include <vector>

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

//-----------------------------------------------------------------------------
class MidiIO
{
public:
	static MidiIO& instance ();

	bool setEnabled (bool state);
	bool isEnabled () const;

	// MIDI Network is experimental, don't use yet
	void setMidiNetworkEnabled (bool state);
	bool isMidiNetworkEnabled () const;
	void setMidiNetworkPolicy (MIDINetworkConnectionPolicy policy);
	MIDINetworkConnectionPolicy getMidiNetworkPolicy () const;

	void addProcessor (IMidiProcessor* processor);
	void removeProcessor (IMidiProcessor* processor);

//-----------------------------------------------------------------------------
private:
	MidiIO ();
	~MidiIO ();

	void onInput (const MIDIPacketList *pktlist);
	void onSourceAdded (MIDIObjectRef source);
	void onSetupChanged ();
	void disconnectSources ();

	MIDIClientRef client;
	MIDIPortRef inputPort;
	MIDIEndpointRef destPort;

	typedef std::vector<IMidiProcessor*> MidiProcessors;
	MidiProcessors midiProcessors;

	typedef std::vector<MIDIEndpointRef> ConnectionList;
	ConnectionList connectedSources;

	static void readProc (const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
	static void notifyProc (const MIDINotification *message, void *refCon);
};

//------------------------------------------------------------------------
} // namespace InterAppAudio
} // namespace Vst
} // namespace Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/VSTInterAppAudioAppDelegateBase.h
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import <UIKit/UIKit.h>

//------------------------------------------------------------------------
/** Base UIApplicationDelegate class.
 *	This class provides the base handling of the audio engine, plug-in and plug-in editor\n
 *	You should subclass it for customization\n
 *	Make sure to call the methods of this class if you override one in your subclass !
 */
//------------------------------------------------------------------------
@interface VSTInterAppAudioAppDelegateBase : UIResponder <UIApplicationDelegate>
//------------------------------------------------------------------------
@property (strong, nonatomic) UIWindow *window;

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder;
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;

@end


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/PresetSaveViewController.mm
// Created by  : Steinberg, 09/2013
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "PresetSaveViewController.h"
#import "pluginterfaces/base/funknown.h"

static NSTimeInterval kAnimationTime = 0.2;

//------------------------------------------------------------------------
@interface PresetSaveViewController ()
//------------------------------------------------------------------------
{
	IBOutlet UIView* containerView;
	IBOutlet UITextField* presetName;

	std::function<void (const char* presetPath)> callback;
	Steinberg::FUID uid;
}
@end

//------------------------------------------------------------------------
@implementation PresetSaveViewController
//------------------------------------------------------------------------

//------------------------------------------------------------------------
- (id)initWithCallback:(std::function<void (const char* presetPath)>)_callback
{
    self = [super initWithNibName:@"PresetSaveView" bundle:nil];
    if (self)
	{
		callback = _callback;

		self.view.alpha = 0.;

		UIViewController* rootViewController = [[UIApplication sharedApplication].windows[0] rootViewController];
		[rootViewController addChildViewController:self];
		[rootViewController.view addSubview:self.view];

		[UIView animateWithDuration:kAnimationTime animations:^{
			self.view.alpha = 1.;
		}  completion:^(BOOL finished) {
			[self showKeyboard];
		}];
    }
    return self;
}

//------------------------------------------------------------------------
- (void)viewDidLoad
{
    [super viewDidLoad];

	containerView.layer.shadowOpacity = 0.5;
	containerView.layer.shadowOffset = CGSizeMake (5, 5);
	containerView.layer.shadowRadius = 5;
}

//------------------------------------------------------------------------
- (void)showKeyboard
{
	[presetName becomeFirstResponder];
}

//------------------------------------------------------------------------
- (void)removeSelf
{
	[UIView animateWithDuration:kAnimationTime animations:^{
		self.view.alpha = 0.;
	} completion:^(BOOL finished) {
		[self.view removeFromSuperview];
		[self removeFromParentViewController];
	}];
}

//------------------------------------------------------------------------
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
	if (buttonIndex != alertView.cancelButtonIndex)
	{
		callback ([[[self presetURL] path] UTF8String]);
		[self removeSelf];
	}
}

//------------------------------------------------------------------------
- (NSURL*)presetURL
{
	NSFileManager* fs = [NSFileManager defaultManager];
	NSURL* documentsUrl = [fs URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:Nil create:YES error:NULL];
	if (documentsUrl)
	{
		NSURL* presetPath = [[documentsUrl URLByAppendingPathComponent:presetName.text] URLByAppendingPathExtension:@"vstpreset"];
		return presetPath;
	}
	return nil;
}

//------------------------------------------------------------------------
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
	if ([textField.text length] > 0)
	{
		[self save:textField];
		return YES;
	}
	return NO;
}

//------------------------------------------------------------------------
- (IBAction)save:(id)sender
{
	if (callback)
	{
		NSURL* presetPath = [self presetURL];
		NSFileManager* fs = [NSFileManager defaultManager];
		if ([fs fileExistsAtPath:[presetPath path]])
		{
			// alert for overwrite
			UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"A Preset with this name already exists" message:@"Save it anyway ?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Save", nil];
			[alert show];
			return;
		}
		callback ([[presetPath path] UTF8String]);
	}
	[self removeSelf];
}

//------------------------------------------------------------------------
- (IBAction)cancel:(id)sender
{
	if (callback)
	{
		callback (0);
	}
	[self removeSelf];
}

@end


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/SettingsViewController.h
// Created by  : Steinberg, 09/2013
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#ifdef __OBJC__

#import <UIKit/UIKit.h>

@interface SettingsViewController : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>

@end

#endif // __OBJC__

extern void showIOSettings ();


text:
if(MAC AND XCODE AND IOS_DEVELOPMENT_TEAM)
	set(target interappaudio)

	set(${target}_sources
		AudioIO.mm
		AudioIO.h
		HostApp.mm
		HostApp.h
		MidiIO.mm
		MidiIO.h
		PresetBrowserViewController.mm
		PresetBrowserViewController.h
		PresetManager.mm
		PresetManager.h
		PresetSaveViewController.mm
		PresetSaveViewController.h
		SettingsViewController.mm
		SettingsViewController.h
		VST3Editor.mm
		VST3Editor.h
		VST3Plugin.mm
		VST3Plugin.h
		VSTInterAppAudioAppDelegateBase.mm
		VSTInterAppAudioAppDelegateBase.h
	)
	add_library(${target} STATIC ${${target}_sources})
	smtg_set_platform_ios(${target})
	target_link_libraries(${target} PRIVATE sdk_ios "-framework CoreGraphics" "-framework UIKit" "-framework CoreMIDI" "-framework AudioToolbox" "-framework AVFoundation")
endif()


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/HostApp.mm
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#import "HostApp.h"
#import "AudioIO.h"
#import "VST3Plugin.h"
#import "PresetManager.h"
#import "SettingsViewController.h"
#import "base/source/updatehandler.h"
#import "pluginterfaces/gui/iplugview.h"

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

//------------------------------------------------------------------------
InterAppAudioHostApp* InterAppAudioHostApp::instance ()
{
	static InterAppAudioHostApp gInstance;
	return &gInstance;
}

//-----------------------------------------------------------------------------
InterAppAudioHostApp::InterAppAudioHostApp ()
: plugin (0)
{
}

//-----------------------------------------------------------------------------
void InterAppAudioHostApp::setPlugin (VST3Plugin* plugin)
{
	this->plugin = plugin;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::getName (String128 name)
{
	String str ("InterAppAudioHost");
	str.copyTo (name, 0, 127);
	return kResultTrue;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::getScreenSize (ViewRect* size, float* scale)
{
	if (size)
	{
		UIScreen* screen = [UIScreen mainScreen];
		CGSize s = [screen currentMode].size;
		UIWindow* window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
		if (window)
		{
			NSArray* subViews = [window subviews];
			if ([subViews count] == 1)
			{
				s = [[subViews objectAtIndex:0] bounds].size;
			}
		}
		size->left = 0;
		size->top = 0;
		size->right = s.width;
		size->bottom = s.height;
		if (scale)
		{
			*scale = screen.scale;
		}
		return kResultTrue;
	}
	return kInvalidArgument;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::connectedToHost ()
{
	return AudioIO::instance ()->getInterAppAudioConnected () ? kResultTrue : kResultFalse;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::switchToHost ()
{
	return AudioIO::instance ()->switchToHost () ? kResultTrue : kResultFalse;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::sendRemoteControlEvent (uint32 event)
{
	return AudioIO::instance ()->sendRemoteControlEvent (
	           static_cast<AudioUnitRemoteControlEvent> (event)) ?
	           kResultTrue :
	           kResultFalse;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::getHostIcon (void** icon)
{
	if (icon)
	{
		UIImage* hostIcon = AudioIO::instance ()->getHostIcon ();
		if (hostIcon)
		{
			CGImageRef cgImage = [hostIcon CGImage];
			if (cgImage)
			{
				*icon = cgImage;
				return kResultTrue;
			}
		}
		return kNotImplemented;
	}
	return kInvalidArgument;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::scheduleEventFromUI (Event& event)
{
	if (plugin)
	{
		return plugin->scheduleEventFromUI (event);
	}
	return kNotInitialized;
}

//-----------------------------------------------------------------------------
IInterAppAudioPresetManager* PLUGIN_API InterAppAudioHostApp::createPresetManager (const TUID& cid)
{
	return plugin ? new PresetManager (plugin, cid) : nullptr;
}

//-----------------------------------------------------------------------------
tresult PLUGIN_API InterAppAudioHostApp::showSettingsView ()
{
	showIOSettings ();
	return kResultTrue;
}

}}}


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/interappaudio/VST3Plugin.h
// Created by  : Steinberg, 08/2013.
// Description : VST 3 InterAppAudio
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

/// \cond ignore

#import "AudioIO.h"
#import "base/source/fobject.h"
#import "base/source/timer.h"
#import "base/source/tringbuffer.h"
#import "pluginterfaces/vst/ivstaudioprocessor.h"
#import "pluginterfaces/vst/ivsteditcontroller.h"
#import "pluginterfaces/vst/ivstprocesscontext.h"
#import "public.sdk/source/vst/hosting/processdata.h"
#import "public.sdk/source/vst/hosting/parameterchanges.h"
#import "public.sdk/source/vst/hosting/eventlist.h"
#import <atomic>
#import <map>

#ifndef __OBJC__
struct NSData;
#endif

namespace Steinberg {
namespace Vst {
namespace InterAppAudio {

static const int32 kMaxUIEvents = 100;

//------------------------------------------------------------------------
class VST3Plugin : public FObject, public IComponentHandler, public IAudioIOProcessor, public ITimerCallback
{
public:
//------------------------------------------------------------------------
	VST3Plugin ();
	virtual ~VST3Plugin ();

	bool init ();

	IEditController* getEditController () const { return editController; }
	IAudioProcessor* getAudioProcessor () const { return processor; }

	tresult scheduleEventFromUI (Event& event);

	NSData* getProcessorState ();
	bool setProcessorState (NSData* data);

	NSData* getControllerState ();
	bool setControllerState (NSData* data);

	OBJ_METHODS(VST3Plugin, FObject)
	REFCOUNT_METHODS(FObject)
	DEFINE_INTERFACES
		DEF_INTERFACE(IComponentHandler)
	END_DEFINE_INTERFACES(FObject)
protected:
	typedef std::map<uint32, uint32> NoteIDPitchMap;
	typedef uint32 ChannelAndCtrlNumber;
	typedef std::map<ChannelAndCtrlNumber, ParamID> MIDIControllerToParamIDMap;

	void createProcessorAndController ();

	void updateProcessContext (AudioIO* audioIO);
	MIDIControllerToParamIDMap createMIDIControllerToParamIDMap ();

	// IComponentHandler
	tresult PLUGIN_API beginEdit (ParamID id) override;
	tresult PLUGIN_API performEdit (ParamID id, ParamValue valueNormalized) override;
	tresult PLUGIN_API endEdit (ParamID id) override;
	tresult PLUGIN_API restartComponent (int32 flags) override;

	// IAudioIOProcessor
	void willStartAudio (AudioIO* audioIO) override;
	void didStopAudio (AudioIO* audioIO) override;
	void onMIDIEvent (UInt32 status, UInt32 data1, UInt32 data2, UInt32 sampleOffset, bool withinRealtimeThread) override;
	void process (const AudioTimeStamp* timeStamp, UInt32 busNumber, UInt32 numFrames, AudioBufferList* ioData, bool& outputIsSilence, AudioIO* audioIO) override;

	// ITimerCallback
	void onTimer (Timer* timer) override;

	IAudioProcessor* processor;
	IEditController* editController;
	Timer* timer;

	HostProcessData processData;
	ProcessContext processContext;
	ParameterChangeTransfer inputParamChangeTransfer;
	ParameterChangeTransfer outputParamChangeTransfer;
	ParameterChanges inputParamChanges;
	ParameterChanges outputParamChanges;
	EventList inputEvents;

	NoteIDPitchMap noteIDPitchMap;
	std::atomic<int32> lastNodeID {0};

	bool processing;

	MIDIControllerToParamIDMap midiControllerToParamIDMap;

	TRingBuffer<Event> uiScheduledEvents;

	static ChannelAndCtrlNumber channelAndCtrlNumber (uint16 channel, CtrlNumber ctrler) { return (channel << 16) + ctrler; }
};

//------------------------------------------------------------------------
} // namespace InterAppAudio
} // namespace Vst
} // namespace Steinberg

/// \endcond