288 lines
11 KiB
C++
288 lines
11 KiB
C++
//------------------------------------------------------------------------
|
|
// Project : VST SDK
|
|
//
|
|
// Category : Helpers
|
|
// Filename : public.sdk/source/vst/auwrapper/auwrapper.h
|
|
// Created by : Steinberg, 12/2007
|
|
// Description : VST 3 -> AU Wrapper
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// This file is part of a Steinberg SDK. It is subject to the license terms
|
|
// in the LICENSE file found in the top-level directory of this distribution
|
|
// and at www.steinberg.net/sdklicenses.
|
|
// No part of the SDK, including this file, may be copied, modified, propagated,
|
|
// or distributed except according to the terms contained in the LICENSE file.
|
|
//-----------------------------------------------------------------------------
|
|
/// \cond ignore
|
|
|
|
#pragma once
|
|
|
|
#ifdef SMTG_AUWRAPPER_USES_AUSDK
|
|
#if CA_USE_AUDIO_PLUGIN_ONLY
|
|
#include "AudioUnitSDK/AUBase.h"
|
|
#define AUWRAPPER_BASE_CLASS ausdk::AUBase
|
|
#else
|
|
#include "AudioUnitSDK/MusicDeviceBase.h"
|
|
#define AUWRAPPER_BASE_CLASS ausdk::MusicDeviceBase
|
|
#endif // CA_USE_AUDIO_PLUGIN_ONLY
|
|
#else
|
|
#if CA_USE_AUDIO_PLUGIN_ONLY
|
|
#include "AudioUnits/AUPublic/AUBase/AUBase.h"
|
|
#define AUWRAPPER_BASE_CLASS AUBase
|
|
#else
|
|
#include "AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h"
|
|
#define AUWRAPPER_BASE_CLASS MusicDeviceBase
|
|
#endif // CA_USE_AUDIO_PLUGIN_ONLY
|
|
#endif // SMTG_AUWRAPPER_USES_AUSDK
|
|
|
|
#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/vst/utility/ringbuffer.h"
|
|
#include "public.sdk/source/vst/utility/rttransfer.h"
|
|
#include "base/source/fstring.h"
|
|
#include "base/source/timer.h"
|
|
#include "base/thread/include/flock.h"
|
|
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
|
#include "pluginterfaces/vst/ivsteditcontroller.h"
|
|
#include "pluginterfaces/vst/ivstmidilearn.h"
|
|
#include "pluginterfaces/vst/ivstprocesscontext.h"
|
|
#include "pluginterfaces/vst/ivstunits.h"
|
|
|
|
#include <AudioToolbox/AudioToolbox.h>
|
|
#include <Cocoa/Cocoa.h>
|
|
#include <array>
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace Steinberg {
|
|
class VST3DynLibrary;
|
|
|
|
namespace Vst {
|
|
|
|
//------------------------------------------------------------------------
|
|
//------------------------------------------------------------------------
|
|
class AUWrapper : public AUWRAPPER_BASE_CLASS, public IComponentHandler, public ITimerCallback
|
|
{
|
|
public:
|
|
#ifdef SMTG_AUWRAPPER_USES_AUSDK
|
|
using AUElement = ausdk::AUElement;
|
|
#else
|
|
using AudioStreamBasicDescription = CAStreamBasicDescription;
|
|
#endif
|
|
|
|
AUWrapper (ComponentInstanceRecord* ci);
|
|
~AUWrapper ();
|
|
|
|
//---ComponentBase---------------------
|
|
#if !CA_USE_AUDIO_PLUGIN_ONLY && !defined(SMTG_AUWRAPPER_USES_AUSDK)
|
|
ComponentResult Version () SMTG_OVERRIDE;
|
|
#endif
|
|
void PostConstructor () SMTG_OVERRIDE;
|
|
|
|
//---AUBase-----------------------------
|
|
void Cleanup () SMTG_OVERRIDE;
|
|
ComponentResult Initialize () SMTG_OVERRIDE;
|
|
#ifdef SMTG_AUWRAPPER_USES_AUSDK
|
|
std::unique_ptr<AUElement> CreateElement (AudioUnitScope scope, AudioUnitElement element) SMTG_OVERRIDE;
|
|
#else
|
|
AUElement* CreateElement (AudioUnitScope scope, AudioUnitElement element) SMTG_OVERRIDE;
|
|
#endif
|
|
UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) SMTG_OVERRIDE;
|
|
bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) SMTG_OVERRIDE;
|
|
ComponentResult ChangeStreamFormat (AudioUnitScope inScope, AudioUnitElement inElement, const AudioStreamBasicDescription& inPrevFormat, const AudioStreamBasicDescription& inNewFormat) SMTG_OVERRIDE;
|
|
ComponentResult SetConnection (const AudioUnitConnection& inConnection) SMTG_OVERRIDE;
|
|
ComponentResult GetParameterInfo (AudioUnitScope inScope, AudioUnitParameterID inParameterID, AudioUnitParameterInfo& outParameterInfo) SMTG_OVERRIDE;
|
|
ComponentResult SetParameter (AudioUnitParameterID inID, AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterValue inValue, UInt32 inBufferOffsetInFrames) SMTG_OVERRIDE;
|
|
|
|
ComponentResult SaveState (CFPropertyListRef* outData) SMTG_OVERRIDE;
|
|
ComponentResult RestoreState (CFPropertyListRef inData) SMTG_OVERRIDE;
|
|
|
|
ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags, const AudioTimeStamp &inTimeStamp, UInt32 inNumberFrames) SMTG_OVERRIDE;
|
|
void processOutputEvents (const AudioTimeStamp &inTimeStamp);
|
|
|
|
#if !CA_USE_AUDIO_PLUGIN_ONLY && !defined(SMTG_AUWRAPPER_USES_AUSDK)
|
|
int GetNumCustomUIComponents () SMTG_OVERRIDE;
|
|
void GetUIComponentDescs (ComponentDescription* inDescArray) SMTG_OVERRIDE;
|
|
#endif
|
|
|
|
#ifdef SMTG_AUWRAPPER_USES_AUSDK
|
|
OSStatus GetPropertyInfo (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32 &outDataSize, bool &outWritable) SMTG_OVERRIDE;
|
|
#else
|
|
OSStatus GetPropertyInfo (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32 &outDataSize, Boolean &outWritable) SMTG_OVERRIDE;
|
|
#endif
|
|
ComponentResult GetProperty (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData) SMTG_OVERRIDE;
|
|
ComponentResult SetProperty (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize) SMTG_OVERRIDE;
|
|
bool CanScheduleParameters() const SMTG_OVERRIDE;
|
|
|
|
Float64 GetLatency () SMTG_OVERRIDE;
|
|
Float64 GetTailTime () SMTG_OVERRIDE;
|
|
|
|
//---Factory presets
|
|
OSStatus GetPresets (CFArrayRef* outData) const SMTG_OVERRIDE;
|
|
OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) SMTG_OVERRIDE;
|
|
|
|
#if !CA_USE_AUDIO_PLUGIN_ONLY
|
|
//---MusicDeviceBase-------------------------
|
|
OSStatus HandleNoteOn (UInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) SMTG_OVERRIDE;
|
|
OSStatus HandleNoteOff (UInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) SMTG_OVERRIDE;
|
|
ComponentResult StartNote (MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID* outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams &inParams) SMTG_OVERRIDE;
|
|
ComponentResult StopNote (MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame) SMTG_OVERRIDE;
|
|
OSStatus GetInstrumentCount (UInt32 &outInstCount) const SMTG_OVERRIDE;
|
|
|
|
//---AUMIDIBase------------------------------
|
|
OSStatus HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) SMTG_OVERRIDE;
|
|
#endif
|
|
|
|
#if AUSDK_MIDI2_AVAILABLE
|
|
OSStatus MIDIEventList (UInt32 inOffsetSampleFrame,
|
|
const struct MIDIEventList* eventList) override;
|
|
bool handleMIDIEventPacket (UInt32 inOffsetSampleFrame, const MIDIEventPacket* packet);
|
|
#endif
|
|
|
|
//---custom----------------------------------
|
|
void setControllerParameter (ParamID pid, ParamValue value);
|
|
|
|
// return for a given midiChannel the unitID and the ProgramListID
|
|
bool getProgramListAndUnit (int32 midiChannel, UnitID& unitId, ProgramListID& programListId);
|
|
|
|
// restore preset state, add StateType "Project" to stream if loading from project
|
|
ComponentResult restoreState (CFPropertyListRef inData, bool fromProject);
|
|
|
|
//------------------------------------------------------------------------
|
|
#if !CA_USE_AUDIO_PLUGIN_ONLY && !defined(SMTG_AUWRAPPER_USES_AUSDK)
|
|
static ComponentResult ComponentEntryDispatch (ComponentParameters* params, AUWrapper* This);
|
|
#endif
|
|
//------------------------------------------------------------------------
|
|
static CFBundleRef gBundleRef;
|
|
//------------------------------------------------------------------------
|
|
DECLARE_FUNKNOWN_METHODS
|
|
|
|
protected:
|
|
//---from IComponentHandler-------------------
|
|
tresult PLUGIN_API beginEdit (ParamID tag) SMTG_OVERRIDE;
|
|
tresult PLUGIN_API performEdit (ParamID tag, ParamValue valueNormalized) SMTG_OVERRIDE;
|
|
tresult PLUGIN_API endEdit (ParamID tag) SMTG_OVERRIDE;
|
|
tresult PLUGIN_API restartComponent (int32 flags) SMTG_OVERRIDE;
|
|
|
|
//---from ITimerCallback----------------------
|
|
void onTimer (Timer* timer) SMTG_OVERRIDE;
|
|
|
|
// internal helpers
|
|
double getSampleRate () const { return sampleRate; }
|
|
void updateProcessContext ();
|
|
void syncParameterValues ();
|
|
void cacheParameterValues ();
|
|
void clearParameterValueCache ();
|
|
void updateProgramChangesCache ();
|
|
|
|
virtual IPluginFactory* getFactory ();
|
|
void loadVST3Module ();
|
|
void unloadVST3Module ();
|
|
bool validateChannelPair (int inChannelsIn, int inChannelsOut, const AUChannelInfo* info,
|
|
UInt32 numChanInfo) const;
|
|
|
|
IAudioProcessor* audioProcessor;
|
|
IEditController* editController;
|
|
|
|
Timer* timer;
|
|
|
|
HostProcessData processData;
|
|
ParameterChanges processParamChanges;
|
|
ParameterChanges outputParamChanges;
|
|
ParameterChangeTransfer transferParamChanges;
|
|
ParameterChangeTransfer outputParamTransfer;
|
|
ProcessContext processContext;
|
|
EventList eventList;
|
|
|
|
typedef std::map<ParamID, AudioUnitParameterInfo> CachedParameterInfoMap;
|
|
typedef std::map<UnitID, UnitInfo> UnitInfoMap;
|
|
typedef std::vector<String> ClumpGroupVector;
|
|
|
|
UnitInfoMap unitInfos;
|
|
ClumpGroupVector clumpGroups;
|
|
CachedParameterInfoMap cachedParameterInfos;
|
|
Steinberg::Base::Thread::FLock parameterCacheChanging;
|
|
|
|
NoteInstanceID noteCounter;
|
|
double sampleRate;
|
|
ParamID bypassParamID;
|
|
|
|
AUPreset* presets;
|
|
int32 numPresets;
|
|
ParamID factoryProgramChangedID;
|
|
|
|
AUParameterListenerRef paramListenerRef;
|
|
std::vector<ParameterInfo> programParameters;
|
|
|
|
static constexpr int32 kMaxProgramChangeParameters = 16;
|
|
struct ProgramChangeInfo
|
|
{
|
|
ParamID pid {kNoParamId};
|
|
int32 numPrograms {0};
|
|
};
|
|
using ProgramChangeInfoList = std::array<ProgramChangeInfo, kMaxProgramChangeParameters>;
|
|
using ProgramChangeInfoTransfer = RTTransferT<ProgramChangeInfoList>;
|
|
ProgramChangeInfoList programChangeInfos;
|
|
ProgramChangeInfoTransfer programChangeInfoTransfer;
|
|
|
|
// midi mapping
|
|
struct MidiMapping
|
|
{
|
|
using CC2ParamMap = std::unordered_map<CtrlNumber, ParamID>;
|
|
using ChannelList = std::vector<CC2ParamMap>;
|
|
using BusList = std::vector<ChannelList>;
|
|
|
|
BusList busList;
|
|
bool empty () const { return busList.empty () || busList[0].empty (); }
|
|
};
|
|
using MidiMappingTransfer = RTTransferT<MidiMapping>;
|
|
|
|
MidiMappingTransfer midiMappingTransfer;
|
|
MidiMapping midiMappingCache;
|
|
|
|
struct MidiLearnEvent
|
|
{
|
|
int32 busIndex;
|
|
int16 channel;
|
|
CtrlNumber midiCC;
|
|
};
|
|
using MidiLearnRingBuffer = OneReaderOneWriter::RingBuffer<MidiLearnEvent>;
|
|
MidiLearnRingBuffer midiLearnRingBuffer;
|
|
IPtr<IMidiLearn> midiLearn;
|
|
|
|
struct MIDIOutputCallbackHelper;
|
|
|
|
int32 midiOutCount; // currently only 0 or 1 supported
|
|
std::unique_ptr<MIDIOutputCallbackHelper> mCallbackHelper;
|
|
EventList outputEvents;
|
|
|
|
bool isInstrument;
|
|
bool isBypassed;
|
|
bool isOfflineRender;
|
|
|
|
private:
|
|
void buildUnitInfos (IUnitInfo* unitInfoController, UnitInfoMap& units) const;
|
|
void updateMidiMappingCache ();
|
|
|
|
IPtr<VST3DynLibrary> dynLib;
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
class AutoreleasePool
|
|
{
|
|
public:
|
|
AutoreleasePool () { ap = [[NSAutoreleasePool alloc] init]; }
|
|
~AutoreleasePool () { [ap drain]; }
|
|
//------------------------------------------------------------------------
|
|
protected:
|
|
NSAutoreleasePool* ap;
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
} // namespace Vst
|
|
} // namespace Steinberg
|
|
|
|
/// \endcond
|