1 //------------------------------------------------------------------------ 2 // Project : VST SDK 3 // 4 // Category : Helpers 5 // Filename : public.sdk/source/vst/auwrapper/auwrapper.h 6 // Created by : Steinberg, 12/2007 7 // Description : VST 3 -> AU Wrapper 8 // 9 //----------------------------------------------------------------------------- 10 // LICENSE 11 // (c) 2020, Steinberg Media Technologies GmbH, All Rights Reserved 12 //----------------------------------------------------------------------------- 13 // Redistribution and use in source and binary forms, with or without modification, 14 // are permitted provided that the following conditions are met: 15 // 16 // * Redistributions of source code must retain the above copyright notice, 17 // this list of conditions and the following disclaimer. 18 // * Redistributions in binary form must reproduce the above copyright notice, 19 // this list of conditions and the following disclaimer in the documentation 20 // and/or other materials provided with the distribution. 21 // * Neither the name of the Steinberg Media Technologies nor the names of its 22 // contributors may be used to endorse or promote products derived from this 23 // software without specific prior written permission. 24 // 25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 // OF THE POSSIBILITY OF SUCH DAMAGE. 35 //----------------------------------------------------------------------------- 36 37 #include "docAUv2.h" 38 39 /// \cond ignore 40 41 #pragma once 42 43 #if CA_USE_AUDIO_PLUGIN_ONLY 44 #include "AudioUnits/AUPublic/AUBase/AUBase.h" 45 #define AUWRAPPER_BASE_CLASS AUBase 46 #else 47 #include "AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h" 48 #define AUWRAPPER_BASE_CLASS MusicDeviceBase 49 #endif 50 51 #include "public.sdk/source/vst/hosting/eventlist.h" 52 #include "public.sdk/source/vst/hosting/parameterchanges.h" 53 #include "public.sdk/source/vst/hosting/processdata.h" 54 #include "base/source/fstring.h" 55 #include "base/source/timer.h" 56 #include "base/thread/include/flock.h" 57 #include "pluginterfaces/vst/ivstaudioprocessor.h" 58 #include "pluginterfaces/vst/ivsteditcontroller.h" 59 #include "pluginterfaces/vst/ivstprocesscontext.h" 60 #include "pluginterfaces/vst/ivstunits.h" 61 62 #include <AudioToolbox/AudioToolbox.h> 63 #include <Cocoa/Cocoa.h> 64 #include <map> 65 #include <vector> 66 67 namespace Steinberg { 68 namespace Vst { 69 70 //------------------------------------------------------------------------ 71 typedef struct MIDIMessageInfoStruct 72 { 73 UInt8 status; 74 UInt8 channel; 75 UInt8 data1; 76 UInt8 data2; 77 UInt32 startFrame; 78 } MIDIMessageInfoStruct; 79 80 //------------------------------------------------------------------------ 81 class MIDIOutputCallbackHelper 82 { 83 public: MIDIOutputCallbackHelper()84 MIDIOutputCallbackHelper () 85 { 86 mMIDIMessageList.reserve (16); 87 mMIDICallbackStruct.midiOutputCallback = NULL; 88 } ~MIDIOutputCallbackHelper()89 virtual ~MIDIOutputCallbackHelper () {}; 90 SetCallbackInfo(AUMIDIOutputCallback callback,void * userData)91 void SetCallbackInfo (AUMIDIOutputCallback callback, void* userData) 92 { 93 mMIDICallbackStruct.midiOutputCallback = callback; 94 mMIDICallbackStruct.userData = userData; 95 } 96 AddEvent(UInt8 status,UInt8 channel,UInt8 data1,UInt8 data2,UInt32 inStartFrame)97 void AddEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) 98 { 99 MIDIMessageInfoStruct info = {status, channel, data1, data2, inStartFrame}; 100 mMIDIMessageList.push_back (info); 101 } 102 FireAtTimeStamp(const AudioTimeStamp & inTimeStamp)103 void FireAtTimeStamp (const AudioTimeStamp& inTimeStamp) 104 { 105 if (!mMIDIMessageList.empty () && mMIDICallbackStruct.midiOutputCallback != 0) 106 { 107 // synthesize the packet list and call the MIDIOutputCallback 108 // iterate through the vector and get each item 109 std::vector<MIDIMessageInfoStruct>::iterator myIterator; 110 MIDIPacketList* pktlist = PacketList (); 111 112 for (myIterator = mMIDIMessageList.begin (); myIterator != mMIDIMessageList.end (); 113 myIterator++) 114 { 115 MIDIMessageInfoStruct item = *myIterator; 116 117 MIDIPacket* pkt = MIDIPacketListInit (pktlist); 118 bool tooBig = false; 119 Byte data[3] = {item.status, item.data1, item.data2}; 120 if ((pkt = MIDIPacketListAdd (pktlist, sizeof (mBuffersAllocated), pkt, 121 item.startFrame, 4, const_cast<Byte*> (data))) == 122 NULL) 123 tooBig = true; 124 125 if (tooBig) 126 { // send what we have and then clear the buffer and send again 127 // issue the callback with what we got 128 OSStatus result = mMIDICallbackStruct.midiOutputCallback ( 129 mMIDICallbackStruct.userData, &inTimeStamp, 0, pktlist); 130 if (result != noErr) 131 printf ("error calling output callback: %d", (int)result); 132 133 // clear stuff we've already processed, and fire again 134 mMIDIMessageList.erase (mMIDIMessageList.begin (), myIterator); 135 this->FireAtTimeStamp (inTimeStamp); 136 return; 137 } 138 } 139 // fire callback 140 OSStatus result = mMIDICallbackStruct.midiOutputCallback (mMIDICallbackStruct.userData, 141 &inTimeStamp, 0, pktlist); 142 if (result != noErr) 143 printf ("error calling output callback: %d", (int)result); 144 145 mMIDIMessageList.clear (); 146 } 147 } 148 149 protected: 150 typedef std::vector<MIDIMessageInfoStruct> MIDIMessageList; 151 152 private: PacketList()153 MIDIPacketList* PacketList () { return (MIDIPacketList*)mBuffersAllocated; } 154 155 Byte mBuffersAllocated[1024]; 156 AUMIDIOutputCallbackStruct mMIDICallbackStruct; 157 MIDIMessageList mMIDIMessageList; 158 }; 159 160 //------------------------------------------------------------------------ 161 //------------------------------------------------------------------------ 162 class AUWrapper : public AUWRAPPER_BASE_CLASS, public IComponentHandler, public ITimerCallback 163 { 164 public: 165 AUWrapper (ComponentInstanceRecord* ci); 166 ~AUWrapper (); 167 168 //---ComponentBase--------------------- 169 ComponentResult Version () SMTG_OVERRIDE; 170 void PostConstructor () SMTG_OVERRIDE; 171 172 //---AUBase----------------------------- 173 void Cleanup () SMTG_OVERRIDE; 174 ComponentResult Initialize () SMTG_OVERRIDE; 175 AUElement* CreateElement (AudioUnitScope scope, AudioUnitElement element) SMTG_OVERRIDE; 176 UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) SMTG_OVERRIDE; 177 bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) SMTG_OVERRIDE; 178 ComponentResult ChangeStreamFormat (AudioUnitScope inScope, AudioUnitElement inElement, const CAStreamBasicDescription& inPrevFormat, const CAStreamBasicDescription& inNewFormat) SMTG_OVERRIDE; 179 ComponentResult SetConnection (const AudioUnitConnection& inConnection) SMTG_OVERRIDE; 180 ComponentResult GetParameterInfo (AudioUnitScope inScope, AudioUnitParameterID inParameterID, AudioUnitParameterInfo& outParameterInfo) SMTG_OVERRIDE; 181 ComponentResult SetParameter (AudioUnitParameterID inID, AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterValue inValue, UInt32 inBufferOffsetInFrames) SMTG_OVERRIDE; 182 183 ComponentResult SaveState (CFPropertyListRef* outData) SMTG_OVERRIDE; 184 ComponentResult RestoreState (CFPropertyListRef inData) SMTG_OVERRIDE; 185 186 ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags, const AudioTimeStamp &inTimeStamp, UInt32 inNumberFrames) SMTG_OVERRIDE; 187 void processOutputEvents (const AudioTimeStamp &inTimeStamp); 188 189 int GetNumCustomUIComponents () SMTG_OVERRIDE; 190 void GetUIComponentDescs (ComponentDescription* inDescArray) SMTG_OVERRIDE; 191 192 ComponentResult GetPropertyInfo (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32 &outDataSize, Boolean &outWritable) SMTG_OVERRIDE; 193 ComponentResult GetProperty (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData) SMTG_OVERRIDE; 194 ComponentResult SetProperty (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize) SMTG_OVERRIDE; 195 bool CanScheduleParameters() const; // Not in the base class anymore in newer CoreAudio SDKs 196 197 Float64 GetLatency () SMTG_OVERRIDE; 198 Float64 GetTailTime () SMTG_OVERRIDE; 199 200 //---Factory presets 201 OSStatus GetPresets (CFArrayRef* outData) const SMTG_OVERRIDE; 202 OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) SMTG_OVERRIDE; 203 204 //---MusicDeviceBase------------------------- 205 ComponentResult StartNote (MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID* outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams &inParams) SMTG_OVERRIDE; 206 ComponentResult StopNote (MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame) SMTG_OVERRIDE; 207 OSStatus GetInstrumentCount (UInt32 &outInstCount) const SMTG_OVERRIDE; 208 209 //---AUMIDIBase------------------------------ 210 OSStatus HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) SMTG_OVERRIDE; 211 212 //---custom---------------------------------- 213 void setControllerParameter (ParamID pid, ParamValue value); 214 215 // return for a given midiChannel the unitID and the ProgramListID 216 bool getProgramListAndUnit (int32 midiChannel, UnitID& unitId, ProgramListID& programListId); 217 218 // restore preset state, add StateType "Project" to stream if loading from project 219 ComponentResult restoreState (CFPropertyListRef inData, bool fromProject); 220 221 //------------------------------------------------------------------------ 222 #if !CA_USE_AUDIO_PLUGIN_ONLY 223 static ComponentResult ComponentEntryDispatch (ComponentParameters* params, AUWrapper* This); 224 #endif 225 //------------------------------------------------------------------------ 226 static CFBundleRef gBundleRef; 227 //------------------------------------------------------------------------ 228 DECLARE_FUNKNOWN_METHODS 229 230 protected: 231 //---from IComponentHandler------------------- 232 tresult PLUGIN_API beginEdit (ParamID tag) SMTG_OVERRIDE; 233 tresult PLUGIN_API performEdit (ParamID tag, ParamValue valueNormalized) SMTG_OVERRIDE; 234 tresult PLUGIN_API endEdit (ParamID tag) SMTG_OVERRIDE; 235 tresult PLUGIN_API restartComponent (int32 flags) SMTG_OVERRIDE; 236 237 //---from ITimerCallback---------------------- 238 void onTimer (Timer* timer) SMTG_OVERRIDE; 239 240 // internal helpers getSampleRate()241 double getSampleRate () const { return sampleRate; } 242 void updateProcessContext (); 243 void syncParameterValues (); 244 void cacheParameterValues (); 245 void clearParameterValueCache (); 246 247 virtual IPluginFactory* getFactory (); 248 void loadVST3Module (); 249 void unloadVST3Module (); 250 bool validateChannelPair (int inChannelsIn, int inChannelsOut, const AUChannelInfo* info, 251 UInt32 numChanInfo) const; 252 253 IAudioProcessor* audioProcessor; 254 IEditController* editController; 255 IMidiMapping* midiMapping; 256 257 Timer* timer; 258 259 HostProcessData processData; 260 ParameterChanges processParamChanges; 261 ParameterChanges outputParamChanges; 262 ParameterChangeTransfer transferParamChanges; 263 ParameterChangeTransfer outputParamTransfer; 264 ProcessContext processContext; 265 EventList eventList; 266 267 typedef std::map<uint32, AudioUnitParameterInfo> CachedParameterInfoMap; 268 typedef std::map<UnitID, UnitInfo> UnitInfoMap; 269 typedef std::vector<String> ClumpGroupVector; 270 271 UnitInfoMap unitInfos; 272 ClumpGroupVector clumpGroups; 273 CachedParameterInfoMap cachedParameterInfos; 274 Steinberg::Base::Thread::FLock parameterCacheChanging; 275 276 NoteInstanceID noteCounter; 277 double sampleRate; 278 ParamID bypassParamID; 279 280 AUPreset* presets; 281 int32 numPresets; 282 ParamID factoryProgramChangedID; 283 284 bool isInstrument; 285 bool isBypassed; 286 287 AUParameterListenerRef paramListenerRef; 288 static const int32 kMaxProgramChangeParameters = 16; 289 ParamID programChangeParameters[kMaxProgramChangeParameters]; // for each midi channel 290 291 int32 midiOutCount; // currently only 0 or 1 supported 292 MIDIOutputCallbackHelper mCallbackHelper; 293 EventList outputEvents; 294 295 private: 296 void buildUnitInfos (IUnitInfo* unitInfoController, UnitInfoMap& units) const; 297 }; 298 299 //------------------------------------------------------------------------ 300 class AutoreleasePool 301 { 302 public: AutoreleasePool()303 AutoreleasePool () { ap = [[NSAutoreleasePool alloc] init]; } ~AutoreleasePool()304 ~AutoreleasePool () { [ap drain]; } 305 //------------------------------------------------------------------------ 306 protected: 307 NSAutoreleasePool* ap; 308 }; 309 310 //------------------------------------------------------------------------ 311 } // namespace Vst 312 } // namespace Steinberg 313 314 /// \endcond 315