1//----------------------------------------------------------------------------- 2// Project : VST SDK 3// 4// Category : Helpers 5// Filename : AUv3Wrapper.mm 6// Created by : Steinberg, 07/2017. 7// Description : VST 3 AUv3Wrapper 8// 9//----------------------------------------------------------------------------- 10// LICENSE 11// (c) 2018, 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#import "AUv3Wrapper.h" 38 39#import <AVFoundation/AVFoundation.h> 40 41#import "public.sdk/source/vst/auwrapper/NSDataIBStream.h" 42#import "public.sdk/source/vst/hosting/eventlist.h" 43#import "public.sdk/source/vst/hosting/parameterchanges.h" 44#import "public.sdk/source/vst/hosting/processdata.h" 45#import "public.sdk/source/vst/utility/mpeprocessor.h" 46#import "public.sdk/source/vst/vsteditcontroller.h" 47#import "base/source/timer.h" 48#import "pluginterfaces/base/ustring.h" 49#import "pluginterfaces/gui/iplugview.h" 50#import "pluginterfaces/vst/ivstmidicontrollers.h" 51#import "pluginterfaces/vst/ivstphysicalui.h" 52#import "pluginterfaces/vst/ivstpluginterfacesupport.h" 53#import "pluginterfaces/vst/vstpresetkeys.h" 54#import "pluginterfaces/vst/vsttypes.h" 55 56#import <array> 57#import <atomic> 58 59#if TARGET_OS_IPHONE 60#define SMTG_IOS_MAC_PLATFORMTYPE kPlatformTypeUIView 61#define SMTG_IOS_MAC_VIEW UIView 62#else 63#define SMTG_IOS_MAC_VIEW NSView 64#define SMTG_IOS_MAC_PLATFORMTYPE kPlatformTypeNSView 65#endif 66 67extern "C" { 68 69//------------------------------------------------------------------------ 70struct VSTBundle 71{ 72 using EntryPtr = bool (*) (CFBundleRef); 73 using ExitPtr = bool (*) (void); 74 75 VSTBundle () 76 { 77 initialized = init (); 78 } 79 80 bool loadBundle (CFURLRef bundleUrl) 81 { 82 bundle = CFBundleCreate (kCFAllocatorDefault, bundleUrl); 83 if (!bundle) 84 return false; 85 if (!CFBundleLoadExecutable (bundle)) 86 return false; 87 bundleEntry = (EntryPtr)CFBundleGetFunctionPointerForName (bundle, CFSTR ("bundleEntry")); 88 if (!bundleEntry) 89 return false; 90 bundleExit = (ExitPtr)CFBundleGetFunctionPointerForName (bundle, CFSTR ("bundleExit")); 91 if (!bundleExit) 92 return false; 93 getFactory = 94 (GetFactoryProc)CFBundleGetFunctionPointerForName (bundle, CFSTR ("GetPluginFactory")); 95 if (!bundleExit) 96 return false; 97 98 if (!bundleEntry (bundle)) 99 return false; 100 return true; 101 } 102 103 bool init () 104 { 105 NSURL* url = NSBundle.mainBundle.builtInPlugInsURL; 106 url = [url URLByAppendingPathComponent:@"plugin.vst3"]; 107 if (!url) 108 return false; 109 CFURLRef bundleUrl = (__bridge CFURLRef)url; 110 if (!loadBundle (bundleUrl)) 111 { 112 url = NSBundle.mainBundle.builtInPlugInsURL; 113 url = [url URLByAppendingPathComponent:@"auv3.appex"]; 114 NSBundle* appexBundle = [NSBundle bundleWithURL:url]; 115 if (!appexBundle) 116 return false; 117 url = appexBundle.builtInPlugInsURL; 118 url = [url URLByAppendingPathComponent:@"plugin.vst3"]; 119 if (!url) 120 return false; 121 bundleUrl = (__bridge CFURLRef)url; 122 if (!loadBundle (bundleUrl)) 123 return false; 124 } 125 126 return true; 127 } 128 129 bool initialized {false}; 130 CFBundleRef bundle {nullptr}; 131 EntryPtr bundleEntry {nullptr}; 132 ExitPtr bundleExit {nullptr}; 133 GetFactoryProc getFactory {nullptr}; 134}; 135 136//------------------------------------------------------------------------ 137Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory () 138{ 139 static VSTBundle vstBundle; 140 if (vstBundle.initialized) 141 { 142 return vstBundle.getFactory (); 143 } 144 return nullptr; 145} 146 147} // extern "C" 148 149#pragma mark - Helpers from AUv2Wrapper / aucocoaview 150//------------------------------------------------------------------------ 151namespace Steinberg { 152 153class AUPlugFrame : public FObject, public IPlugFrame 154{ 155public: 156 AUPlugFrame (SMTG_IOS_MAC_VIEW* parent) : parent (parent) {} 157 tresult PLUGIN_API resizeView (IPlugView* view, ViewRect* vr) SMTG_OVERRIDE 158 { 159 CGRect newSize = CGRectMake ([parent frame].origin.x, [parent frame].origin.y, 160 vr->right - vr->left, vr->bottom - vr->top); 161 [parent setFrame:newSize]; 162 return kResultTrue; 163 } 164 165 OBJ_METHODS (AUPlugFrame, FObject) 166 DEF_INTERFACES_1 (IPlugFrame, FObject) 167 REFCOUNT_METHODS (FObject) 168 169protected: 170 SMTG_IOS_MAC_VIEW* parent; 171}; 172 173namespace Vst { 174 175//------------------------------------------------------------------------ 176static CFStringRef createCFStringFromString128 (const String128& string) 177{ 178 UString128 str (string); 179 return CFStringCreateWithCharacters (0, (const UniChar*)string, str.getLength ()); 180} 181 182//------------------------------------------------------------------------ 183static SpeakerArrangement numChannelsToSpeakerArrangement (UInt32 numChannels) 184{ 185 switch (numChannels) 186 { 187 case 1: return SpeakerArr::kMono; 188 case 2: return SpeakerArr::kStereo; 189 case 6: return SpeakerArr::k51; 190 } 191 return 0; 192} 193 194//------------------------------------------------------------------------ 195class AUHostApplication : public FObject, 196 public HostApplication, 197 public IVst3ToAUWrapper, 198 public IVst3WrapperMPESupport 199{ 200public: 201 __weak AUv3Wrapper* wrapper {nil}; 202 203 AUHostApplication () 204 { 205 auto pis = getPlugInterfaceSupport (); 206 pis->addPlugInterfaceSupported (INoteExpressionController::iid); 207 pis->addPlugInterfaceSupported (INoteExpressionPhysicalUIMapping::iid); 208 } 209 210 tresult PLUGIN_API getName (String128 name) SMTG_OVERRIDE 211 { 212 String str ("VST3-AU Wrapper"); 213 str.copyTo (name, 0, 127); 214 return kResultTrue; 215 } 216 217 tresult PLUGIN_API enableMPEInputProcessing (TBool state) SMTG_OVERRIDE 218 { 219 if (!wrapper) 220 return kInternalError; 221 return [wrapper enableMPESupport:state != 0 ? YES : NO] ? kResultTrue : kResultFalse; 222 } 223 224 tresult PLUGIN_API setMPEInputDeviceSettings (int32 masterChannel, int32 memberBeginChannel, 225 int32 memberEndChannel) SMTG_OVERRIDE 226 { 227 if (!wrapper) 228 return kInternalError; 229 return [wrapper setMPEInputDeviceMasterChannel:masterChannel 230 memberBeginChannel:memberBeginChannel 231 memberEndChannel:memberEndChannel] ? 232 kResultTrue : 233 kResultFalse; 234 } 235 236 DEFINE_INTERFACES 237 DEF_INTERFACE (IVst3ToAUWrapper) 238 DEF_INTERFACE (IVst3WrapperMPESupport) 239 END_DEFINE_INTERFACES (HostApplication) 240 REFCOUNT_METHODS (HostApplication) 241}; 242 243//------------------------------------------------------------------------ 244typedef std::map<UnitID, UnitInfo> UnitInfoMap; 245typedef std::vector<String> ParameterGroupVector; 246 247static void buildUnitInfos (IUnitInfo* unitInfoController, UnitInfoMap& units) 248{ 249 units.clear (); 250 if (unitInfoController) 251 { 252 int32 numUnits = unitInfoController->getUnitCount (); 253 for (int32 i = 0; i < numUnits; i++) 254 { 255 UnitInfo ui; 256 if (unitInfoController->getUnitInfo (i, ui) == kResultTrue) 257 units[ui.id] = ui; 258 } 259 } 260} 261 262//------------------------------------------------------------------------ 263struct BufferedAudioBus 264{ 265 AUAudioUnitBus* bus = nullptr; 266 AUAudioFrameCount maxFrames = 0; 267 AVAudioPCMBuffer* pcmBuffer = nullptr; 268 AudioBufferList const* originalAudioBufferList = nullptr; 269 AudioBufferList* mutableAudioBufferList = nullptr; 270 271 void init (AVAudioFormat* defaultFormat, AVAudioChannelCount maxChannels) 272 { 273 maxFrames = 0; 274 pcmBuffer = nullptr; 275 originalAudioBufferList = nullptr; 276 mutableAudioBufferList = nullptr; 277 278 bus = [[AUAudioUnitBus alloc] initWithFormat:defaultFormat error:nil]; 279 280 bus.maximumChannelCount = maxChannels; 281 } 282 283 void allocateRenderResources (AUAudioFrameCount inMaxFrames) 284 { 285 maxFrames = inMaxFrames; 286 287 pcmBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:bus.format frameCapacity:maxFrames]; 288 289 originalAudioBufferList = pcmBuffer.audioBufferList; 290 mutableAudioBufferList = pcmBuffer.mutableAudioBufferList; 291 } 292 293 void deallocateRenderResources () 294 { 295 pcmBuffer = nullptr; 296 originalAudioBufferList = nullptr; 297 mutableAudioBufferList = nullptr; 298 } 299}; 300 301//------------------------------------------------------------------------ 302// This struct provides a prepareOutputBufferList method to copy the internal buffer pointers to the 303// output buffer list in case the client passed in null buffer pointers. 304struct BufferedOutputBus : BufferedAudioBus 305{ 306 void prepareOutputBufferList (AudioBufferList* outBufferList, AVAudioFrameCount frameCount, 307 bool zeroFill) 308 { 309 UInt32 byteSize = frameCount * sizeof (float); 310 311 for (UInt32 i = 0; i < outBufferList->mNumberBuffers; ++i) 312 { 313 outBufferList->mBuffers[i].mNumberChannels = 314 originalAudioBufferList->mBuffers[i].mNumberChannels; 315 outBufferList->mBuffers[i].mDataByteSize = byteSize; 316 317 if (outBufferList->mBuffers[i].mData == nullptr) 318 outBufferList->mBuffers[i].mData = originalAudioBufferList->mBuffers[i].mData; 319 320 if (zeroFill) 321 memset (outBufferList->mBuffers[i].mData, 0, byteSize); 322 } 323 } 324}; 325 326//------------------------------------------------------------------------ 327// This struct manages a buffer into which an audio unit with input busses can pull its input data. 328struct BufferedInputBus : BufferedAudioBus 329{ 330 AUAudioUnitStatus pullInput (AudioUnitRenderActionFlags* actionFlags, 331 AudioTimeStamp const* timestamp, AVAudioFrameCount frameCount, 332 NSInteger inputBusNumber, AURenderPullInputBlock pullInputBlock) 333 { 334 if (pullInputBlock == nullptr) 335 return kAudioUnitErr_NoConnection; 336 337 prepareInputBufferList (); 338 339 return pullInputBlock (actionFlags, timestamp, frameCount, inputBusNumber, 340 mutableAudioBufferList); 341 } 342 343 void prepareInputBufferList () 344 { 345 UInt32 byteSize = maxFrames * sizeof (float); 346 347 mutableAudioBufferList->mNumberBuffers = originalAudioBufferList->mNumberBuffers; 348 349 for (UInt32 i = 0; i < originalAudioBufferList->mNumberBuffers; ++i) 350 { 351 mutableAudioBufferList->mBuffers[i].mNumberChannels = 352 originalAudioBufferList->mBuffers[i].mNumberChannels; 353 mutableAudioBufferList->mBuffers[i].mData = originalAudioBufferList->mBuffers[i].mData; 354 mutableAudioBufferList->mBuffers[i].mDataByteSize = byteSize; 355 } 356 } 357}; 358 359#pragma mark - ComponentHelper class (implementing IComponentHandler) 360//------------------------------------------------------------------------ 361class ComponentHelper : public IComponentHandler 362{ 363public: 364 ComponentHelper (void* audioUnit); 365 virtual ~ComponentHelper (); 366 367 __weak AUv3Wrapper* auv3Wrapper; 368 369 DECLARE_FUNKNOWN_METHODS 370 371 tresult PLUGIN_API performEdit (ParamID tag, ParamValue valueNormalized) SMTG_OVERRIDE; 372 373protected: 374 tresult PLUGIN_API beginEdit (ParamID tag) SMTG_OVERRIDE; 375 tresult PLUGIN_API endEdit (ParamID tag) SMTG_OVERRIDE; 376 tresult PLUGIN_API restartComponent (int32 flags) SMTG_OVERRIDE; 377}; 378 379//------------------------------------------------------------------------ 380ComponentHelper::ComponentHelper (void* audioUnit) 381{ 382 FUNKNOWN_CTOR 383 auv3Wrapper = (__bridge AUv3Wrapper*)audioUnit; 384} 385 386//------------------------------------------------------------------------ 387ComponentHelper::~ComponentHelper () 388{ 389 FUNKNOWN_DTOR 390 auv3Wrapper = nil; 391} 392 393IMPLEMENT_FUNKNOWN_METHODS (ComponentHelper, IComponentHandler, IComponentHandler::iid) 394 395//------------------------------------------------------------------------ 396tresult PLUGIN_API ComponentHelper::beginEdit (ParamID tag) 397{ 398 return kResultTrue; 399} 400 401//------------------------------------------------------------------------ 402tresult PLUGIN_API ComponentHelper::performEdit (ParamID tag, ParamValue valueNormalized) 403{ 404 [auv3Wrapper performEdit:tag value:valueNormalized]; 405 return kResultTrue; 406} 407 408//------------------------------------------------------------------------ 409tresult PLUGIN_API ComponentHelper::endEdit (ParamID tag) 410{ 411 return kResultTrue; 412} 413 414//------------------------------------------------------------------------ 415tresult PLUGIN_API ComponentHelper::restartComponent (int32 flags) 416{ 417 tresult result = kNotImplemented; 418 // this method informs the host/the AU that something in the VST has changed (latency, parameter 419 // titles, etc.) 420 421 if (flags & kParamValuesChanged) 422 { 423 // vst plugin parameter names (titles) have changed 424 [auv3Wrapper syncParameterValues]; 425 result = kResultTrue; 426 } 427 428 if (flags & kParamTitlesChanged) 429 { 430 // vst plugin parameter values have changed 431 [auv3Wrapper initializeParameters]; 432 result = kResultTrue; 433 } 434 435 if (flags & kNoteExpressionChanged) 436 { 437 [auv3Wrapper onNoteExpressionChanged]; 438 } 439 440 if (flags & kLatencyChanged) 441 { 442 result = kResultTrue; 443 } 444 445 // TODO: finish restartComponent implementation 446 447 return result; 448} 449 450//------------------------------------------------------------------------ 451// TimerHelper class 452//------------------------------------------------------------------------ 453#pragma mark - TimerHelper class (implementing ITimerCallback) 454class TimerHelper : public ITimerCallback 455{ 456public: 457 TimerHelper (void* audioUnit); 458 ~TimerHelper (); 459 460 __weak AUv3Wrapper* auv3Wrapper; 461 Timer* timer; 462 463protected: 464 void onTimer (Timer* timer); 465}; 466 467//------------------------------------------------------------------------ 468TimerHelper::TimerHelper (void* audioUnit) 469{ 470 auv3Wrapper = (__bridge AUv3Wrapper*)audioUnit; 471 timer = Timer::create (this, 20); 472} 473 474//------------------------------------------------------------------------ 475TimerHelper::~TimerHelper () 476{ 477 auv3Wrapper = nil; 478 timer->release (); 479} 480 481//------------------------------------------------------------------------ 482void TimerHelper::onTimer (Timer* timer) 483{ 484 [auv3Wrapper onTimer]; 485} 486 487#pragma mark - Render Helper structs 488//------------------------------------------------------------------------ 489struct MPEHandler : public MPE::Handler 490{ 491 struct Context 492 { 493 IEventList* inputEvents {nullptr}; 494 IMidiMapping* midiMapping {nullptr}; 495 IParameterChanges* outputParamChanges {nullptr}; 496 IComponentHandler* editPerformer {nullptr}; 497 MPE::Processor* mpeProcessor {nullptr}; 498 std::atomic_bool enableMPEProcessing {true}; 499 std::array<ParamID, 16> programChangeParameters {{kNoParamId}}; 500 std::array<ParamID, 16> programChangeParameterStepCount {{0}}; 501 std::array<NoteExpressionTypeID, 3> mpeMap {{kInvalidTypeID}}; 502 }; 503 504 void process (Context& c, const AUMIDIEvent* event, const AudioTimeStamp* timeStamp) 505 { 506 context = &c; 507 currentSampleOffset = event->eventSampleTime - timeStamp->mSampleTime; 508 if (c.enableMPEProcessing.load ()) 509 { 510 mpeProcssingEnabled = true; 511 c.mpeProcessor->processMIDIInput (event->data, event->length); 512 } 513 else 514 { 515 if (mpeProcssingEnabled) 516 { 517 mpeProcssingEnabled = false; 518 c.mpeProcessor->reset (); 519 } 520 onOtherInput (event->data, event->length); 521 } 522 523 context = nullptr; 524 } 525 526private: 527 Context* context {nullptr}; 528 int32 currentSampleOffset {0}; 529 MPE::NoteID noteIDCounter {0}; 530 bool mpeProcssingEnabled {false}; 531 using Pitch2ParamID = std::array<ParamID, 128>; 532 std::array<Pitch2ParamID, 16> pitchToParamIDMap {{{0}}}; 533 534 bool generateNewNoteID (MPE::NoteID& outNoteID) override 535 { 536 if (!context) 537 return false; 538 outNoteID = ++noteIDCounter; 539 return true; 540 } 541 void releaseNoteID (MPE::NoteID noteID) override {} 542 543 void onMPENoteOn (MPE::NoteID noteID, MPE::Pitch pitch, MPE::Velocity velocity) override 544 { 545 if (!context) 546 return; 547 sendNoteOn (noteID, pitch, velocity); 548 } 549 550 void onMPENoteOff (MPE::NoteID noteID, MPE::Pitch pitch, MPE::Velocity velocity) override 551 { 552 if (!context) 553 return; 554 sendNoteOff (noteID, pitch, velocity); 555 } 556 557 void onMPEControllerChange (MPE::NoteID noteID, MPE::Controller cc, 558 MPE::NormalizedValue value) override 559 { 560 if (!context || cc > MPE::Controller::Y) 561 return; 562 if (context->mpeMap[static_cast<size_t> (cc)] != kInvalidTypeID) 563 { 564 Event e {}; 565 e.type = Event::kNoteExpressionValueEvent; 566 e.noteExpressionValue.noteId = noteID; 567 e.noteExpressionValue.typeId = context->mpeMap[static_cast<size_t> (cc)]; 568 e.noteExpressionValue.value = value; 569 e.sampleOffset = currentSampleOffset; 570 context->inputEvents->addEvent (e); 571 } 572 } 573 574 void sendNoteOn (MPE::NoteID noteID, MPE::Pitch pitch, MPE::Velocity velocity, 575 int16 channel = 0) 576 { 577 if (!context->inputEvents) 578 return; 579 Event e {}; 580 e.type = Event::kNoteOnEvent; 581 e.noteOn.pitch = pitch; 582 e.noteOn.velocity = velocity; 583 e.noteOn.noteId = noteID; 584 e.noteOn.channel = channel; 585 e.sampleOffset = currentSampleOffset; 586 context->inputEvents->addEvent (e); 587 } 588 589 void sendNoteOff (MPE::NoteID noteID, MPE::Pitch pitch, MPE::Velocity velocity, 590 int16 channel = 0) 591 { 592 if (!context->inputEvents) 593 return; 594 Event e {}; 595 e.type = Event::kNoteOffEvent; 596 e.noteOff.pitch = pitch; 597 e.noteOff.velocity = velocity; 598 e.noteOff.noteId = noteID; 599 e.noteOff.channel = channel; 600 e.sampleOffset = currentSampleOffset; 601 context->inputEvents->addEvent (e); 602 } 603 604 void sendPolyPressure (MPE::NoteID noteID, MPE::Pitch pitch, MPE::NormalizedValue pressure, 605 int16 channel) 606 { 607 if (!context->inputEvents) 608 return; 609 Event e = {0}; 610 e.type = Event::kPolyPressureEvent; 611 e.polyPressure.channel = channel; 612 e.polyPressure.pitch = pitch; 613 e.polyPressure.pressure = pressure; 614 e.polyPressure.noteId = noteID; 615 e.sampleOffset = currentSampleOffset; 616 context->inputEvents->addEvent (e); 617 } 618 619 void sendControllerChange (CtrlNumber controller, MPE::NormalizedValue value, int16 channel) 620 { 621 if (!context->midiMapping) 622 return; 623 ParamID outParamID; 624 if (context->midiMapping->getMidiControllerAssignment (0, channel, controller, 625 outParamID) != kResultTrue) 626 return; 627 context->editPerformer->performEdit (outParamID, value); 628 int32 index; 629 if (auto vq = context->outputParamChanges->addParameterData (outParamID, index)) 630 vq->addPoint (currentSampleOffset, value, index); 631 } 632 633 void sendProgramChange (int16 channel, uint8 midiValue) 634 { 635 auto prgChangeParamID = context->programChangeParameters[channel]; 636 if (prgChangeParamID == kNoParamId) 637 return; 638 auto value = -1.; 639 auto stepCount = context->programChangeParameterStepCount[channel]; 640 if (stepCount = 0) 641 value = static_cast<double> (midiValue) / 127.; 642 else if (midiValue <= stepCount) 643 value = static_cast<double> (midiValue) / static_cast<double> (stepCount); 644 if (value == -1.) 645 return; 646 647 context->editPerformer->performEdit (prgChangeParamID, value); 648 int32 index; 649 if (auto vq = context->outputParamChanges->addParameterData (prgChangeParamID, index)) 650 { 651 vq->addPoint (currentSampleOffset, value, index); 652 } 653 } 654 655 void onOtherInput (const uint8_t* data, size_t dataSize) override 656 { 657 if (!context || dataSize < 2) 658 return; 659 660 constexpr auto NoteOff = 0x80; 661 constexpr auto NoteOn = 0x90; 662 constexpr auto Aftertouch = 0xa0; 663 constexpr auto Controller = 0xb0; 664 constexpr auto ProgramChange = 0xc0; 665 constexpr auto ChannelPressure = 0xd0; 666 constexpr auto PitchWheel = 0xe0; 667 668 auto status = data[0] & 0xF0; 669 auto channel = data[0] & 0x0F; 670 switch (status) 671 { 672 case NoteOn: 673 { 674 auto pitch = data[1]; 675 if (data[2] != 0) 676 { 677 auto velocity = static_cast<float> (data[2]) / 127.; 678 if (pitchToParamIDMap[channel][pitch] != 0) 679 sendNoteOff (pitchToParamIDMap[channel][pitch], pitch, velocity); 680 MPE::NoteID noteID; 681 if (generateNewNoteID (noteID)) 682 { 683 pitchToParamIDMap[channel][pitch] = noteID; 684 sendNoteOn (noteID, pitch, velocity, channel); 685 } 686 } 687 else 688 { 689 if (pitchToParamIDMap[channel][pitch] != 0) 690 { 691 sendNoteOff (pitchToParamIDMap[channel][pitch], pitch, 0, channel); 692 pitchToParamIDMap[channel][pitch] = 0; 693 } 694 } 695 break; 696 } 697 case NoteOff: 698 { 699 auto pitch = data[1]; 700 if (pitchToParamIDMap[channel][pitch] != 0) 701 { 702 auto velocity = static_cast<float> (data[2]) / 127.; 703 sendNoteOff (pitchToParamIDMap[channel][pitch], pitch, velocity, channel); 704 pitchToParamIDMap[channel][pitch] = 0; 705 } 706 break; 707 } 708 case Aftertouch: 709 { 710 auto value = static_cast<MPE::NormalizedValue> (data[1]) / 127.; 711 sendControllerChange (ControllerNumbers::kAfterTouch, value, channel); 712 break; 713 } 714 case Controller: 715 { 716 auto value = static_cast<MPE::NormalizedValue> (data[2]) / 127.; 717 sendControllerChange (data[1], value, channel); 718 break; 719 } 720 case ProgramChange: 721 { 722 sendProgramChange (channel, data[1]); 723 break; 724 } 725 case ChannelPressure: 726 { 727 sendPolyPressure (-1, data[1], static_cast<double> (data[2]) / 127., channel); 728 break; 729 } 730 case PitchWheel: 731 { 732 auto value = 733 static_cast<MPE::NormalizedValue> ((data[1] & 0x7F) + ((data[2] & 0x7F) << 7)) / 734 16383.; 735 sendControllerChange (ControllerNumbers::kPitchBend, value, channel); 736 break; 737 } 738 } 739 } 740 741 void onSysexInput (const uint8_t* data, size_t dataSize) override 742 { 743 // no sysex handling 744 } 745 746 // error handling 747 void errorNoteDroppedBecauseNoNoteID (MPE::Pitch pitch) override {} 748 void errorNoteDroppedBecauseNoteStackFull (MPE::Channel channel, MPE::Pitch pitch) override {} 749 void errorNoteForNoteOffNotFound (MPE::Channel channel, MPE::Pitch pitch) override {} 750 void errorProgramChangeReceivedInMPEZone () override {} 751}; 752 753struct RenderProcessContext 754{ 755 RenderProcessContext () {} 756 AUHostMusicalContextBlock musicalContext; 757 AUHostTransportStateBlock transportContext; 758 const AudioTimeStamp* timestamp; 759 ProcessContext* processContext; 760 double sampleRate; 761 762 void updateProcessContext (const RenderProcessContext& renderContext) 763 { 764 Float64 currentTempo = 0; 765 double timeSignatureNumerator = 0; 766 NSInteger timeSignatureDenominator = 0; 767 Float64 currentBeatPosition = 0; 768 NSInteger sampleOffsetToNextBeat = 0; 769 Float64 currentMeasureDownbeatPosition = 0; 770 AUHostTransportStateFlags transportStateFlags; 771 double currentSamplePosition = 0; 772 double cycleStartBeatPosition = 0; 773 double cycleEndBeatPosition = 0; 774 775 if (musicalContext) 776 { 777 musicalContext (¤tTempo, &timeSignatureNumerator, &timeSignatureDenominator, 778 ¤tBeatPosition, &sampleOffsetToNextBeat, 779 ¤tMeasureDownbeatPosition); 780 781 processContext->state |= ProcessContext::kTempoValid | ProcessContext::kTimeSigValid | 782 ProcessContext::kProjectTimeMusicValid | 783 ProcessContext::kBarPositionValid | 784 ProcessContext::kClockValid; 785 processContext->tempo = currentTempo; 786 processContext->projectTimeMusic = currentBeatPosition; 787 processContext->timeSigNumerator = timeSignatureNumerator; 788 processContext->timeSigDenominator = (int32)timeSignatureDenominator; 789 processContext->samplesToNextClock = (int32)sampleOffsetToNextBeat; 790 processContext->barPositionMusic = currentMeasureDownbeatPosition; 791 } 792 793 if (transportContext) 794 { 795 transportContext (&transportStateFlags, ¤tSamplePosition, &cycleStartBeatPosition, 796 &cycleEndBeatPosition); 797 798 processContext->state |= ProcessContext::kCycleValid; 799 processContext->cycleStartMusic = cycleStartBeatPosition; 800 processContext->cycleEndMusic = cycleEndBeatPosition; 801 processContext->projectTimeSamples = currentSamplePosition; 802 803 switch (transportStateFlags) 804 { 805 case AUHostTransportStateMoving: 806 processContext->state |= ProcessContext::kPlaying; 807 break; 808 case AUHostTransportStateRecording: 809 processContext->state |= ProcessContext::kRecording; 810 break; 811 case AUHostTransportStateCycling: 812 processContext->state |= ProcessContext::kCycleActive; 813 break; 814 } 815 } 816 817 processContext->sampleRate = sampleRate; 818 processContext->systemTime = timestamp->mHostTime; 819 } 820}; 821 822} // Vst 823} // Steinberg 824 825//------------------------------------------------------------------------ 826// AUv3Wrapper main class 827//------------------------------------------------------------------------ 828#pragma mark - AUv3Wrapper main class (implementing AUAudioUnit) 829 830using namespace Steinberg; 831using namespace Vst; 832@interface AUv3Wrapper () 833 834@property AUAudioUnitBusArray* inputBusArray; 835@property AUAudioUnitBusArray* outputBusArray; 836@property (nonatomic, readonly) AUParameterTree* parameterTree; 837@property IEditController* editcontroller; 838 839@end 840 841@implementation AUv3Wrapper 842{ 843 std::vector<BufferedInputBus> inputBusBuffers; 844 std::vector<BufferedOutputBus> outputBusBuffers; 845 846 AUHostMusicalContextBlock musicalContext; 847 AUHostTransportStateBlock transportContext; 848 849 AUParameterObserverToken parameterObserverToken; 850 851 NSDictionary<NSString*, id>* fullStateVar; 852 NSMutableArray<AUAudioUnitPreset*>* factoryPresetsVar; 853 NSArray<NSNumber*>* channelCapabilitiesArray; 854 AUParameterTree* parameterTreeVar; 855 856 IPtr<IAudioProcessor> audioProcessor; 857 IMidiMapping* midiMapping; 858 859 HostProcessData processData; 860 ParameterChanges inputParamChanges; 861 ParameterChanges outputParamChanges; 862 ParameterChangeTransfer transferParamChanges; 863 ParameterChangeTransfer outputParamTransfer; 864 ProcessContext processContext; 865 EventList inputEvents; 866 EventList outputEvents; 867 AUHostApplication hostAppContext; 868 MPEHandler mpeHandler; 869 MPEHandler::Context mpeHandlerContext; 870 std::unique_ptr<MPE::Processor> mpeProcessor; 871 872 UnitInfoMap unitInfos; 873 ParameterGroupVector parameterGroups; 874 875 NoteInstanceID noteCounter; 876 double sampleRate; 877 int32 bypassParamID; 878 879 int32 numPresets; 880 int32 factoryProgramChangedID; 881 882 bool isInstrument; 883 bool isBypassed; 884 bool canProcessInPlaceValue; 885 bool renderingOfflineValue; 886 887 // Midi Stuff 888 int32 midiOutCount; // currently only 0 or 1 supported 889 890 NSMutableArray<NSNumber*>* overviewParams; 891 892 std::unique_ptr<TimerHelper> timerHelper; 893 std::unique_ptr<ComponentHelper> componentHelper; 894 895 AUAudioUnitPreset* currentPreset; 896 NSInteger currentFactoryPresetIndex; 897 AUParameterObserverToken bypassObserverToken; 898} 899 900//------------------------------------------------------------------------ 901// MARK: AUAudioUnit init & dealloc 902//------------------------------------------------------------------------ 903- (instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription 904 options:(AudioComponentInstantiationOptions)options 905 error:(NSError**)outError 906{ 907 self = [super initWithComponentDescription:componentDescription options:options error:outError]; 908 909 if (self == nil) 910 return nil; 911 912 // set instance variables 913 sampleRate = 44100.0; 914 bypassParamID = -1; 915 factoryProgramChangedID = -1; 916 isInstrument = false; 917 isBypassed = false; 918 outputParamTransfer.setMaxParameters (500); 919 transferParamChanges.setMaxParameters (500); 920 921 componentHelper = std::unique_ptr<ComponentHelper> (new ComponentHelper ((__bridge void*)self)); 922 timerHelper = std::unique_ptr<TimerHelper> (new TimerHelper ((__bridge void*)self)); 923 924 canProcessInPlaceValue = false; 925 renderingOfflineValue = false; 926 927 processData.processContext = &processContext; 928 processData.inputParameterChanges = &inputParamChanges; 929 processData.outputParameterChanges = &outputParamChanges; 930 inputEvents.setMaxSize (128); 931 outputEvents.setMaxSize (128); 932 processData.inputEvents = &inputEvents; 933 processData.outputEvents = &outputEvents; 934 hostAppContext.wrapper = self; 935 936 // create the channel capabilities 937 NSBundle* mainBundle = [NSBundle mainBundle]; 938 NSString* test = [mainBundle objectForInfoDictionaryKey:@"SupportedNumChannels"]; 939 NSMutableArray* supportedNumChannelsArray = [NSMutableArray array]; 940 941 for (int i = 0; i < test.length; i++) 942 { 943 NSString* newString = [test substringWithRange:NSMakeRange (i, 1)]; 944 [supportedNumChannelsArray addObject:[NSNumber numberWithInt:[newString intValue]]]; 945 } 946 947 channelCapabilitiesArray = supportedNumChannelsArray; 948 949 // load VST processor and controller 950 [self loadVst]; 951 952 // initialize busses 953 [self initializeBusses]; 954 955 // initialize parameters 956 [self initializeParameters]; 957 958 // initialize presets 959 [self loadPresetList]; 960 961 // MPE Support 962 mpeProcessor = std::unique_ptr<MPE::Processor> (new MPE::Processor (&mpeHandler)); 963 mpeHandlerContext.mpeProcessor = mpeProcessor.get (); 964 mpeHandlerContext.midiMapping = midiMapping; 965 mpeHandlerContext.inputEvents = &inputEvents; 966 mpeHandlerContext.outputParamChanges = &outputParamChanges; 967 mpeHandlerContext.editPerformer = componentHelper.get (); 968 969 [self onNoteExpressionChanged]; 970 971 return self; 972} 973 974//------------------------------------------------------------------------ 975- (void)onNoteExpressionChanged 976{ 977 if (!self.supportsMPE) 978 return; 979 980 FUnknownPtr<INoteExpressionPhysicalUIMapping> puiMapping (_editcontroller); 981 if (puiMapping) 982 { 983 PhysicalUIMap map[3]; 984 map[0].physicalUITypeID = kPUIXMovement; 985 map[1].physicalUITypeID = kPUIYMovement; 986 map[2].physicalUITypeID = kPUIPressure; 987 PhysicalUIMapList mapList {3, map}; 988 989 // We can only map one bus and one channel with MPE in AUv3 990 if (puiMapping->getPhysicalUIMapping (0, 0, mapList) == kResultTrue) 991 { 992 mpeHandlerContext.mpeMap[0] = map[2].noteExpressionTypeID; 993 mpeHandlerContext.mpeMap[1] = map[0].noteExpressionTypeID; 994 mpeHandlerContext.mpeMap[2] = map[1].noteExpressionTypeID; 995 } 996 } 997} 998 999//------------------------------------------------------------------------ 1000- (BOOL)enableMPESupport:(BOOL)state 1001{ 1002 if (!mpeProcessor) 1003 return NO; 1004 1005 mpeHandlerContext.enableMPEProcessing.store (state); 1006 return YES; 1007} 1008 1009//------------------------------------------------------------------------ 1010- (BOOL)setMPEInputDeviceMasterChannel:(NSInteger)masterChannel 1011 memberBeginChannel:(NSInteger)memberBeginChannel 1012 memberEndChannel:(NSInteger)memberEndChannel 1013{ 1014 if (!mpeProcessor) 1015 return NO; 1016 auto setup = mpeProcessor->getSetup (); 1017 setup.masterChannel = static_cast<MPE::Channel> (masterChannel); 1018 setup.memberChannelBegin = static_cast<MPE::Channel> (memberBeginChannel); 1019 setup.memberChannelEnd = static_cast<MPE::Channel> (memberEndChannel); 1020 mpeProcessor->changeSetup (setup); 1021 return YES; 1022} 1023 1024//------------------------------------------------------------------------ 1025- (void)dealloc 1026{ 1027 if (audioProcessor) 1028 { 1029 FUnknownPtr<IEditController> combined (audioProcessor); 1030 if (!combined) 1031 { 1032 FUnknownPtr<IConnectionPoint> controllerConnectionPoint (_editcontroller); 1033 FUnknownPtr<IConnectionPoint> processorConnectionPoint (audioProcessor); 1034 if (controllerConnectionPoint && processorConnectionPoint) 1035 { 1036 controllerConnectionPoint->disconnect (processorConnectionPoint); 1037 processorConnectionPoint->disconnect (controllerConnectionPoint); 1038 } 1039 } 1040 } 1041 1042 if (midiMapping) 1043 { 1044 midiMapping->release (); 1045 midiMapping = 0; 1046 } 1047 1048 if (_editcontroller) 1049 { 1050 _editcontroller->setComponentHandler (0); 1051 uint32 refCount = _editcontroller->addRef (); 1052 if (refCount == 2) 1053 _editcontroller->terminate (); 1054 1055 _editcontroller->release (); 1056 _editcontroller->release (); 1057 _editcontroller = nil; 1058 } 1059 1060 if (audioProcessor) 1061 { 1062 FUnknownPtr<IPluginBase> (audioProcessor)->terminate (); 1063 audioProcessor = 0; 1064 } 1065 1066 if (parameterObserverToken != nullptr) 1067 { 1068 [parameterTreeVar removeParameterObserver:parameterObserverToken]; 1069 parameterObserverToken = nullptr; 1070 } 1071 1072 timerHelper = 0; 1073 componentHelper = 0; 1074} 1075 1076//------------------------------------------------------------------------ 1077// MARK: Helper Functions 1078//------------------------------------------------------------------------ 1079- (NSString*)getParameterStringFromValue:(int)tag value:(AUValue)value 1080{ 1081 String128 paramString; 1082 1083 if (_editcontroller->getParamStringByValue (tag, value, paramString) == kResultTrue) 1084 { 1085 UString128 str (paramString); 1086 return [NSString stringWithCharacters:(const UniChar*)paramString length:str.getLength ()]; 1087 } 1088 1089 return @""; 1090} 1091 1092//------------------------------------------------------------------------ 1093- (AUValue)getParameterValueFromString:(int)tag string:(NSString*)nsString 1094{ 1095 ParamValue outValue; 1096 CFStringRef cfString = (__bridge CFStringRef)nsString; 1097 1098 String128 string128; 1099 CFStringGetCharacters (cfString, 1100 CFRangeMake (0, std::max<CFIndex> (128, CFStringGetLength (cfString))), 1101 (UniChar*)string128); 1102 1103 _editcontroller->getParamValueByString (tag, string128, outValue); 1104 1105 return (float)outValue; 1106} 1107 1108//------------------------------------------------------------------------ 1109- (void)loadVst 1110{ 1111 FUnknownPtr<IPluginFactory2> factory (owned (GetPluginFactory ())); 1112 if (factory) 1113 { 1114 // find first audio processor class 1115 for (int32 i = 0; i < factory->countClasses (); i++) 1116 { 1117 PClassInfo2 ci; 1118 if (factory->getClassInfo2 (i, &ci) == kResultTrue) 1119 { 1120 if (strcmp (ci.category, kVstAudioEffectClass) == 0) 1121 { 1122 IAudioProcessor* proc = 0; 1123 if (factory->createInstance (ci.cid, IAudioProcessor::iid, (void**)&proc) == 1124 kResultTrue) 1125 { 1126 audioProcessor = owned (proc); 1127 ConstString plugCategory (ci.subCategories); 1128 if (plugCategory.findFirst ("Instrument", -1, 1129 ConstString::kCaseInsensitive) >= 0) 1130 isInstrument = true; 1131 break; 1132 } 1133 } 1134 } 1135 } 1136 } 1137 1138 if (audioProcessor) 1139 { 1140 if (FUnknownPtr<IPluginBase> (audioProcessor)->initialize (hostAppContext.unknownCast ()) != 1141 kResultTrue) 1142 return; 1143 1144 if (audioProcessor->queryInterface (IEditController::iid, (void**)&_editcontroller) != 1145 kResultTrue) 1146 { 1147 FUnknownPtr<IComponent> component (audioProcessor); 1148 if (component) 1149 { 1150 TUID ccid; 1151 if (component->getControllerClassId (ccid) == kResultTrue) 1152 { 1153 if (factory->createInstance (ccid, IEditController::iid, 1154 (void**)&_editcontroller) == kResultTrue) 1155 { 1156 if (_editcontroller->initialize (hostAppContext.unknownCast ()) != 1157 kResultTrue) 1158 { 1159 _editcontroller->release (); 1160 _editcontroller = 0; 1161 return; 1162 } 1163 1164 FUnknownPtr<IConnectionPoint> controllerConnectionPoint (_editcontroller); 1165 FUnknownPtr<IConnectionPoint> processorConnectionPoint (audioProcessor); 1166 if (controllerConnectionPoint && processorConnectionPoint) 1167 { 1168 controllerConnectionPoint->connect (processorConnectionPoint); 1169 processorConnectionPoint->connect (controllerConnectionPoint); 1170 } 1171 1172 NSMutableData* processorData = [[NSMutableData alloc] init]; 1173 NSMutableDataIBStream stream (processorData); 1174 if (FUnknownPtr<IComponent> (audioProcessor)->getState (&stream) == 1175 kResultTrue) 1176 { 1177 stream.seek (0, IBStream::kIBSeekSet); 1178 _editcontroller->setComponentState (&stream); 1179 } 1180 } 1181 } 1182 } 1183 } 1184 } 1185} 1186 1187//------------------------------------------------------------------------ 1188- (void)initializeBusses 1189{ 1190 NSMutableArray<AUAudioUnitBus*>* outBusArray = [[NSMutableArray<AUAudioUnitBus*> alloc] init]; 1191 NSMutableArray<AUAudioUnitBus*>* inBusArray = [[NSMutableArray<AUAudioUnitBus*> alloc] init]; 1192 1193 if (_editcontroller) 1194 { 1195 _editcontroller->setComponentHandler (componentHelper.get ()); 1196 1197 FUnknownPtr<IComponent> component (audioProcessor); 1198 int32 inputBusCount = component->getBusCount (kAudio, kInput); 1199 int32 outputBusCount = component->getBusCount (kAudio, kOutput); 1200 1201 // create input busses 1202 [self createBusses:true busCount:inputBusCount busArray:inBusArray component:component]; 1203 1204 // create output busses 1205 [self createBusses:false busCount:outputBusCount busArray:outBusArray component:component]; 1206 1207 processData.prepare (*component, 0, kSample32); 1208 1209 midiOutCount = component->getBusCount (kEvent, kOutput); 1210 1211 _editcontroller->queryInterface (IMidiMapping::iid, (void**)&midiMapping); 1212 } 1213 1214 // create the input and output bus arrays (AUAudioUnitBusArray) 1215 _inputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self 1216 busType:AUAudioUnitBusTypeInput 1217 busses:inBusArray]; 1218 1219 // create the input and output bus arrays. 1220 _outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self 1221 busType:AUAudioUnitBusTypeOutput 1222 busses:outBusArray]; 1223} 1224 1225//------------------------------------------------------------------------ 1226- (void)createBusses:(bool)isInput 1227 busCount:(int)busCount 1228 busArray:(NSMutableArray<AUAudioUnitBus*>*)busArray 1229 component:(FUnknownPtr<IComponent>)component 1230{ 1231 SpeakerArrangement sa; 1232 int inputOrOutput = isInput ? kInput : kOutput; 1233 1234 for (int32 busNum = 0; busNum < busCount; busNum++) 1235 { 1236 AUAudioUnitBus* bus; 1237 AVAudioFormat* customFormat; 1238 1239 if (audioProcessor->getBusArrangement (inputOrOutput, busNum, sa) == kResultTrue) 1240 { 1241 customFormat = [[AVAudioFormat alloc] 1242 initStandardFormatWithSampleRate:sampleRate 1243 channels:SpeakerArr::getChannelCount (sa)]; 1244 1245 bus = [[AUAudioUnitBus alloc] initWithFormat:customFormat error:nil]; 1246 bus.maximumChannelCount = customFormat.channelCount; 1247 } 1248 1249 BusInfo info = {0}; 1250 if (component->getBusInfo (kAudio, inputOrOutput, busNum, info) == kResultTrue) 1251 { 1252 UString128 str (info.name); 1253 NSString* convertedNSString = 1254 [NSString stringWithCharacters:(const UniChar*)info.name length:str.getLength ()]; 1255 bus.name = convertedNSString; 1256 } 1257 1258 component->activateBus (kAudio, kInput, busNum, false); 1259 1260 if (bus != nil) 1261 [busArray addObject:bus]; 1262 } 1263} 1264 1265//------------------------------------------------------------------------ 1266- (void)allocateBusBuffers 1267{ 1268 FUnknownPtr<IComponent> component (audioProcessor); 1269 1270 for (int i = 0; i < component->getBusCount (kAudio, kInput); i++) 1271 { 1272 BufferedInputBus bus; 1273 bus.init (_inputBusArray[i].format, _inputBusArray[i].format.channelCount); 1274 bus.allocateRenderResources (self.maximumFramesToRender); 1275 inputBusBuffers.push_back (bus); 1276 } 1277 1278 for (int i = 0; i < component->getBusCount (kAudio, kOutput); i++) 1279 { 1280 BufferedOutputBus bus; 1281 bus.init (_outputBusArray[i].format, _outputBusArray[i].format.channelCount); 1282 bus.allocateRenderResources (self.maximumFramesToRender); 1283 outputBusBuffers.push_back (bus); 1284 } 1285 1286 // if no input bus create empty one 1287 if (_inputBusArray.count == 0) 1288 { 1289 AVAudioFormat* defaultFormat = 1290 [[AVAudioFormat alloc] initStandardFormatWithSampleRate:sampleRate channels:2]; 1291 BufferedInputBus bus; 1292 bus.init (defaultFormat, 2); 1293 bus.allocateRenderResources (self.maximumFramesToRender); 1294 inputBusBuffers.push_back (bus); 1295 } 1296} 1297 1298//------------------------------------------------------------------------ 1299- (void)initializeParameters 1300{ 1301 // AUv3 Parameter Initialization 1302 overviewParams = [[NSMutableArray<NSNumber*> alloc] init]; 1303 NSMutableArray* paramArray = [[NSMutableArray alloc] init]; 1304 NSMutableArray* paramArrayWithHierarchy = [[NSMutableArray<AUParameter*> alloc] init]; 1305 1306 // create parameters 1307 [self createParameters:paramArrayWithHierarchy paramArray:paramArray]; 1308 1309 // create the paramArray with AUParameterGroups 1310 for (int32 i = 0; i < [paramArrayWithHierarchy count]; i++) 1311 { 1312 if (i == 0) 1313 { 1314 for (int32 j = 0; j < [[paramArrayWithHierarchy objectAtIndex:i] count]; j++) 1315 [paramArray addObject:paramArrayWithHierarchy[i][j]]; 1316 } 1317 else 1318 { 1319 String str = parameterGroups.at (i - 1); 1320 NSString* groupName = [NSString stringWithString:[NSString stringWithUTF8String:str]]; 1321 1322 AUParameterGroup* newGroup = 1323 [AUParameterTree createGroupWithIdentifier:groupName 1324 name:groupName 1325 children:paramArrayWithHierarchy[i]]; 1326 1327 [paramArray addObject:newGroup]; 1328 } 1329 } 1330 1331 // create the parameter tree 1332 parameterTreeVar = [AUParameterTree createTreeWithChildren:paramArray]; 1333 1334 // implementorValueObserver is called when a parameter changes value. 1335 __weak AUv3Wrapper* weakSelf = self; 1336 parameterTreeVar.implementorValueObserver = ^(AUParameter* param, AUValue value) { 1337 [weakSelf setParameter:(int)param.address value:value]; 1338 }; 1339 1340 // A function to provide string representations of parameter values. 1341 parameterTreeVar.implementorStringFromValueCallback = 1342 ^(AUParameter* param, const AUValue* __nullable valuePtr) { 1343 AUValue value = valuePtr == nil ? param.value : *valuePtr; 1344 1345 return [weakSelf getParameterStringFromValue:(int)param.address value:value]; 1346 }; 1347 1348 parameterObserverToken = [parameterTreeVar 1349 tokenByAddingParameterObserver:^(AUParameterAddress address, AUValue value) { 1350 dispatch_async (dispatch_get_main_queue (), ^{ 1351 __strong AUv3Wrapper* strongSelf = weakSelf; 1352 [strongSelf setControllerParameter:(int)address value:value]; 1353 }); 1354 }]; 1355 1356 // A function to provide the parameter values of string representations. 1357 parameterTreeVar.implementorValueFromStringCallback = ^(AUParameter* param, NSString* string) { 1358 return [weakSelf getParameterValueFromString:(int)param.address string:string]; 1359 }; 1360} 1361 1362//------------------------------------------------------------------------ 1363- (void)createParameters:(NSMutableArray*)paramArrayWithHierarchy 1364 paramArray:(NSMutableArray*)paramArray 1365{ 1366 // for each VST3 parameter 1367 int32 parameterCount = _editcontroller->getParameterCount (); 1368 for (int32 i = 0; i < parameterCount; i++) 1369 { 1370 ParameterInfo pi = {0}; 1371 _editcontroller->getParameterInfo (i, pi); 1372 1373 if (pi.flags & ParameterInfo::kIsBypass) 1374 { 1375 bypassParamID = pi.id; 1376 } 1377 else 1378 { 1379 // Build parameter group if possible, maps to the AUParameterGroup Node in the 1380 // parameterTree 1381 int32 groupIdx = [self buildParameterGroup:pi]; 1382 1383 // create identifier for parameter 1384 NSString* identifier = 1385 [NSString stringWithString:[NSString stringWithFormat:@"%d", pi.id]]; 1386 NSString* name = (NSString*)CFBridgingRelease (createCFStringFromString128 (pi.title)); 1387 NSString* unitName = 1388 (NSString*)CFBridgingRelease (createCFStringFromString128 (pi.units)); 1389 AUParameterAddress address = static_cast<AUParameterAddress> (pi.id); 1390 1391 // create flags for parameter 1392 AudioUnitParameterOptions flagsToSet = 1393 kAudioUnitParameterFlag_ValuesHaveStrings | kAudioUnitParameterFlag_IsReadable; 1394 1395 if (!(pi.flags & ParameterInfo::kIsReadOnly)) 1396 flagsToSet |= kAudioUnitParameterFlag_IsWritable; 1397 if (!(pi.flags & ParameterInfo::kCanAutomate)) 1398 flagsToSet |= kAudioUnitParameterFlag_NonRealTime; 1399 if (pi.stepCount == 1) 1400 flagsToSet = kAudioUnitParameterUnit_Boolean; 1401 1402 // create the parameter 1403 AUParameter* sPar = 1404 [AUParameterTree createParameterWithIdentifier:identifier 1405 name:name 1406 address:address 1407 min:0.0 1408 max:1.0 1409 unit:kAudioUnitParameterUnit_CustomUnit 1410 unitName:unitName 1411 flags:flagsToSet 1412 valueStrings:nil 1413 dependentParameters:nil]; 1414 1415 // initialize the parameter values 1416 sPar.value = pi.defaultNormalizedValue; 1417 [self setParameter:pi.id value:pi.defaultNormalizedValue]; 1418 [self setControllerParameter:pi.id value:pi.defaultNormalizedValue]; 1419 1420 // add parameter to the paramArrayWithHierarchy (with hierarchy/AUParameterGroups) 1421 // initialize paramArrayWithHierarchy once (if i == 0) 1422 if (i == 0) 1423 { 1424 bool rootInitialized = false; 1425 for (auto it = unitInfos.begin (); it != unitInfos.end (); ++it) 1426 { 1427 [paramArrayWithHierarchy addObject:[[NSMutableArray alloc] init]]; 1428 1429 if (it->second.parentUnitId == -1) 1430 rootInitialized = true; 1431 } 1432 1433 if (!rootInitialized) 1434 [paramArrayWithHierarchy addObject:[[NSMutableArray alloc] init]]; 1435 } 1436 1437 NSUInteger groupOfParam = (NSUInteger)groupIdx; 1438 [[paramArrayWithHierarchy objectAtIndex:groupOfParam] addObject:sPar]; 1439 [overviewParams addObject:[NSNumber numberWithUnsignedLongLong:address]]; 1440 } 1441 } 1442} 1443 1444//------------------------------------------------------------------------ 1445- (int32)buildParameterGroup:(ParameterInfo)pi 1446{ 1447 int32 groupIdx = 0; // Zero means parameter is on top level node of parameter tree 1448 1449 FUnknownPtr<IUnitInfo> unitInfoController (_editcontroller); 1450 if (unitInfoController) 1451 { 1452 if (unitInfos.empty ()) 1453 buildUnitInfos (unitInfoController, unitInfos); 1454 1455 String fullParamName; 1456 ConstString separator (STR (".")); 1457 bool insertSeparator = false; 1458 1459 UnitInfoMap::const_iterator it = unitInfos.find (pi.unitId); 1460 while (it != unitInfos.end () && it->second.id != kRootUnitId) 1461 { 1462 ConstString unitName (it->second.name); 1463 if (unitName.length () > 0) 1464 { 1465 if (insertSeparator) 1466 fullParamName.insertAt (0, separator); 1467 insertSeparator = true; 1468 fullParamName.insertAt (0, unitName); 1469 } 1470 it = unitInfos.find (it->second.parentUnitId); 1471 } 1472 if (!fullParamName.isEmpty ()) 1473 { 1474 bool insertGroup = true; 1475 groupIdx = 1; 1476 for (int32 i = 0; i < parameterGroups.size (); i++) 1477 { 1478 const String& str = parameterGroups.at (i); 1479 if (str.compare (fullParamName) == 0) 1480 break; 1481 1482 ++groupIdx; 1483 } 1484 1485 if (insertGroup) 1486 parameterGroups.push_back (fullParamName); 1487 } 1488 } 1489 return groupIdx; 1490} 1491 1492//------------------------------------------------------------------------ 1493- (void)setupProcessing 1494{ 1495 if (audioProcessor && _editcontroller) 1496 { 1497 FUnknownPtr<IComponent> component (audioProcessor); 1498 1499 // after set Bus Arrangement, the channelbuffers may need to be reallocated -> hence the 1500 // second prepare! 1501 processData.prepare (*component, 0, kSample32); 1502 1503 ProcessSetup ps; 1504 ps.sampleRate = sampleRate; 1505 ps.maxSamplesPerBlock = self.maximumFramesToRender; 1506 ps.symbolicSampleSize = kSample32; 1507 ps.processMode = kRealtime; 1508 1509 audioProcessor->setupProcessing (ps); 1510 1511 component->setActive (true); 1512 1513 audioProcessor->setProcessing (true); 1514 } 1515} 1516 1517//------------------------------------------------------------------------ 1518- (bool)getProgramListAndUnit:(int32)midiChannel 1519 unitId:(UnitID&)unitId 1520 programListId:(ProgramListID&)programListId 1521{ 1522 programListId = kNoProgramListId; 1523 unitId = -1; 1524 1525 IUnitInfo* unitInfo = NULL; 1526 1527 if (_editcontroller && 1528 _editcontroller->queryInterface (IUnitInfo::iid, (void**)&unitInfo) == kResultTrue && 1529 unitInfo) 1530 { 1531 if (unitInfo->getUnitByBus (kEvent, kInput, 0, midiChannel, unitId) == kResultTrue) 1532 { 1533 int32 unitCount = unitInfo->getUnitCount (); 1534 for (int32 i = 0; i < unitCount; i++) 1535 { 1536 UnitInfo unitInfoStruct = {0}; 1537 if (unitInfo->getUnitInfo (i, unitInfoStruct) == kResultTrue) 1538 { 1539 if (unitId == unitInfoStruct.id) 1540 { 1541 programListId = unitInfoStruct.programListId; 1542 unitInfo->release (); 1543 return programListId != kNoProgramListId; 1544 } 1545 } 1546 } 1547 } 1548 1549 unitInfo->release (); 1550 } 1551 return false; 1552} 1553 1554//------------------------------------------------------------------------ 1555- (void)loadPresetList 1556{ 1557 std::vector<ParameterInfo> programParameters; 1558 bool noPresets = true; 1559 1560 // for each VST3 parameter 1561 int32 parameterCount = _editcontroller->getParameterCount (); 1562 for (int32 i = 0; i < parameterCount; i++) 1563 { 1564 ParameterInfo pi = {0}; 1565 _editcontroller->getParameterInfo (i, pi); 1566 1567 // do not register bypass 1568 if ((pi.flags & ParameterInfo::kIsBypass) != 0) 1569 { 1570 continue; 1571 } 1572 else if ((pi.flags & ParameterInfo::kIsProgramChange) != 0) 1573 { 1574 // see if parameter is programChange 1575 noPresets = false; 1576 programParameters.push_back (pi); 1577 } 1578 } 1579 1580 if (noPresets) 1581 return; 1582 1583 // assign programChanges 1584 for (int32 midiChannel = 0; midiChannel < 16; ++midiChannel) 1585 { 1586 mpeHandlerContext.programChangeParameters[midiChannel] = kNoParamId; 1587 UnitID unitId; 1588 ProgramListID programListId; 1589 if (![self getProgramListAndUnit:midiChannel unitId:unitId programListId:programListId]) 1590 continue; 1591 for (int32 i = 0; i < (int32)programParameters.size (); i++) 1592 { 1593 const ParameterInfo& paramInfo = programParameters.at (i); 1594 if (paramInfo.unitId == unitId) 1595 { 1596 mpeHandlerContext.programChangeParameters[midiChannel] = paramInfo.id; 1597 mpeHandlerContext.programChangeParameterStepCount[midiChannel] = 1598 paramInfo.stepCount; 1599 break; 1600 } 1601 } 1602 } 1603 1604 FUnknownPtr<IUnitInfo> unitInfoController (_editcontroller); 1605 1606 factoryPresetsVar = [[NSMutableArray<AUAudioUnitPreset*> alloc] init]; 1607 1608 // let's see if there's a preset list (take the first one) 1609 if (!unitInfoController) 1610 return; 1611 1612 ProgramListInfo programListInfo; 1613 if (unitInfoController->getProgramListInfo (0, programListInfo) != kResultTrue) 1614 return; 1615 1616 factoryProgramChangedID = -1; 1617 numPresets = programListInfo.programCount; 1618 if (programListInfo.programCount > 0) 1619 { 1620 UnitID unitId = -1; 1621 1622 // find the unit supporting this ProgramList 1623 IUnitInfo* unitInfo = NULL; 1624 if (_editcontroller->queryInterface (IUnitInfo::iid, (void**)&unitInfo) == kResultTrue && 1625 unitInfo) 1626 { 1627 int32 unitCount = unitInfo->getUnitCount (); 1628 for (int32 i = 0; i < unitCount; i++) 1629 { 1630 UnitInfo unitInfoStruct = {0}; 1631 if (unitInfo->getUnitInfo (i, unitInfoStruct) == kResultTrue) 1632 { 1633 if (programListInfo.id == unitInfoStruct.programListId) 1634 { 1635 unitId = unitInfoStruct.id; 1636 break; 1637 } 1638 } 1639 } 1640 1641 unitInfo->release (); 1642 } 1643 1644 if (unitId != -1) 1645 { 1646 // find the associated ProgramChange parameter ID 1647 for (int32 i = 0; i < (int32)programParameters.size (); i++) 1648 { 1649 const ParameterInfo& paramInfo = programParameters.at (i); 1650 if (paramInfo.unitId == unitId) 1651 { 1652 factoryProgramChangedID = paramInfo.id; 1653 break; 1654 } 1655 } 1656 1657 if (factoryProgramChangedID != -1) 1658 { 1659 for (int32 i = 0; i < programListInfo.programCount; i++) 1660 { 1661 String128 name; 1662 unitInfoController->getProgramName (programListInfo.id, i, name); 1663 1664 UString128 str (name); 1665 NSString* convertedNSString = 1666 [NSString stringWithCharacters:(const UniChar*)name 1667 length:str.getLength ()]; 1668 1669 AUAudioUnitPreset* preset = [[AUAudioUnitPreset alloc] init]; 1670 [preset setName:convertedNSString]; 1671 [preset setNumber:static_cast<NSInteger> (i)]; 1672 1673 [factoryPresetsVar addObject:preset]; 1674 } 1675 } 1676 } 1677 } 1678} 1679 1680//------------------------------------------------------------------------ 1681- (void)syncParameterValues 1682{ 1683 if (!_editcontroller) 1684 return; 1685 1686 int32 parameterCount = _editcontroller->getParameterCount (); 1687 1688 for (int32 i = 0; i < parameterCount; i++) 1689 { 1690 ParameterInfo pi; 1691 _editcontroller->getParameterInfo (i, pi); 1692 1693 if (pi.flags & ParameterInfo::kIsBypass) 1694 { 1695 bypassParamID = pi.id; 1696 } 1697 else 1698 { 1699 ParamValue value = _editcontroller->getParamNormalized (pi.id); 1700 // set the AU parameter value 1701 AUParameter* parameterToChange = [parameterTreeVar parameterWithAddress:pi.id]; 1702 parameterToChange.value = value; 1703 } 1704 } 1705} 1706 1707//------------------------------------------------------------------------ 1708- (void)setParameter:(int)tag value:(double)value 1709{ 1710 if (tag == factoryProgramChangedID) 1711 { 1712 // load factory preset here 1713 float normalizedValue = (float)value / (float)numPresets; 1714 transferParamChanges.addChange (factoryProgramChangedID, normalizedValue, 0); 1715 } 1716 1717 transferParamChanges.addChange (tag, value, 0); 1718} 1719 1720//------------------------------------------------------------------------ 1721- (void)setControllerParameter:(int)tag value:(double)value 1722{ 1723 if (_editcontroller && tag != factoryProgramChangedID) 1724 _editcontroller->setParamNormalized (tag, value); 1725} 1726 1727//------------------------------------------------------------------------ 1728- (void)performEdit:(int)tag value:(double)value 1729{ 1730 AUParameter* parameterToChange = [parameterTreeVar parameterWithAddress:tag]; 1731 1732 if (parameterObserverToken != nullptr) 1733 [parameterToChange setValue:value originator:parameterObserverToken]; 1734 else 1735 [parameterToChange setValue:value]; 1736} 1737 1738//------------------------------------------------------------------------ 1739- (void)onTimer 1740{ 1741 ParamID pid; 1742 ParamValue value; 1743 int32 sampleOffset; 1744 1745 while (outputParamTransfer.getNextChange (pid, value, sampleOffset)) 1746 { 1747 _editcontroller->setParamNormalized (pid, value); 1748 AUParameter* parameterToChange = [parameterTreeVar parameterWithAddress:pid]; 1749 parameterToChange.value = value; 1750 } 1751 1752 if (!isBypassed) 1753 return; 1754 1755 ProcessData bypassData = processData; 1756 bypassData.numSamples = 0; 1757 inputParamChanges.clearQueue (); 1758 transferParamChanges.transferChangesTo (inputParamChanges); 1759 1760 if (inputParamChanges.getParameterCount () > 0) 1761 { 1762 audioProcessor->process (bypassData); 1763 outputParamTransfer.transferChangesFrom (outputParamChanges); 1764 outputParamChanges.clearQueue (); 1765 } 1766} 1767 1768//------------------------------------------------------------------------ 1769- (BOOL)validateChannelConfig 1770{ 1771 FUnknownPtr<IComponent> component (audioProcessor); 1772 int32 inputBusCount = component->getBusCount (kAudio, kInput); 1773 int32 outputBusCount = component->getBusCount (kAudio, kOutput); 1774 SpeakerArrangement inputs[inputBusCount]; 1775 SpeakerArrangement outputs[outputBusCount]; 1776 int32 maxBusCount = std::max (inputBusCount, outputBusCount); 1777 BOOL didChannelConfigPass = YES; 1778 1779 for (int32 i = 0; i < maxBusCount; i++) 1780 { 1781 int32 inChannelCount = 0; 1782 int32 outChannelCount = 0; 1783 if (inputBusCount > i) 1784 inChannelCount = _outputBusArray[i].format.channelCount; 1785 if (outputBusCount > i) 1786 outChannelCount = _outputBusArray[i].format.channelCount; 1787 1788 didChannelConfigPass = [self validateChannelPair:inChannelCount 1789 inChannelsOut:outChannelCount 1790 info:channelCapabilitiesArray 1791 numChanInfo:([channelCapabilitiesArray count] / 2)]; 1792 } 1793 1794 for (int32 element = 0; element < inputBusCount; element++) 1795 inputs[element] = 1796 numChannelsToSpeakerArrangement (_inputBusArray[element].format.channelCount); 1797 1798 for (int32 element = 0; element < outputBusCount; element++) 1799 outputs[element] = 1800 numChannelsToSpeakerArrangement (_outputBusArray[element].format.channelCount); 1801 1802 if (audioProcessor->setBusArrangements (inputs, inputBusCount, outputs, outputBusCount) != 1803 kResultTrue) 1804 didChannelConfigPass = NO; 1805 1806 return didChannelConfigPass; 1807} 1808 1809//------------------------------------------------------------------------ 1810- (BOOL)validateChannelPair:(int)inChannelsIn 1811 inChannelsOut:(int)inChannelsOut 1812 info:(NSArray<NSNumber*>*)info 1813 numChanInfo:(long)numChanInfo 1814{ 1815 // we've the following cases (some combinations) to test here: 1816 /* 1817 >0 An explicit number of channels on either side 1818 0 that side (generally input!) has no elements 1819 -1 wild card: 1820 -1,-1 any num channels as long as same channels on in and out 1821 -1,-2 any num channels channels on in and out - special meaning 1822 -2+ indicates total num channs AU can handle 1823 - elements configurable to any num channels, 1824 - element count in scope must be writable 1825 */ 1826 1827 // now chan layout can contain -1 for either scope (ie. doesn't care) 1828 for (unsigned int i = 0; i < numChanInfo; ++i) 1829 { 1830 int inputValue = (int)[info[(i * 2)] integerValue]; 1831 int outputValue = (int)[info[(i * 2) + 1] integerValue]; 1832 1833 // less than zero on both sides - check for special attributes 1834 if ((inputValue < 0) && (outputValue < 0)) 1835 { 1836 // these are our wild card matches 1837 if (inputValue == -1 && outputValue == -1) 1838 { 1839 if (inChannelsIn && inChannelsOut) 1840 { 1841 if (inChannelsOut == inChannelsIn) 1842 return true; 1843 } 1844 else 1845 return true; // if one of these is zero, then a -1 means any 1846 } 1847 else if ((inputValue == -1 && outputValue == -2) || 1848 (inputValue == -2 && outputValue == -1)) 1849 { 1850 return true; 1851 } 1852 // these are our total num channels matches 1853 // element count MUST be writable 1854 else 1855 { 1856 bool outWrite = false; 1857 bool inWrite = false; 1858 // IsElementCountWritable (kAudioUnitScope_Output, outWrite); 1859 // IsElementCountWritable (kAudioUnitScope_Input, inWrite); 1860 if (inWrite && outWrite) 1861 { 1862 if ((inChannelsOut <= abs (outputValue)) && (inChannelsIn <= abs (inputValue))) 1863 return true; 1864 } 1865 } 1866 } 1867 1868 // special meaning on input, specific num on output 1869 else if (inputValue < 0) 1870 { 1871 if (outputValue == inChannelsOut) 1872 { 1873 // can do any in channels 1874 if (inputValue == -1) 1875 { 1876 return true; 1877 } 1878 // total chans on input 1879 else 1880 { 1881 bool inWrite = false; 1882 // IsElementCountWritable (kAudioUnitScope_Input, inWrite); 1883 if (inWrite && (inChannelsIn <= abs (inputValue))) 1884 return true; 1885 } 1886 } 1887 } 1888 1889 // special meaning on output, specific num on input 1890 else if (outputValue < 0) 1891 { 1892 if (inputValue == inChannelsIn) 1893 { 1894 // can do any out channels 1895 if (outputValue == -1) 1896 { 1897 return true; 1898 } 1899 // total chans on output 1900 else 1901 { 1902 bool outWrite = false; 1903 // IsElementCountWritable (kAudioUnitScope_Output, outWrite); 1904 if (outWrite && (inChannelsOut <= abs (outputValue))) 1905 { 1906 return true; 1907 } 1908 } 1909 } 1910 } 1911 1912 // both chans in struct >= 0 - thus has to explicitly match 1913 else if ((inputValue == inChannelsIn) && (outputValue == inChannelsOut)) 1914 { 1915 return true; 1916 } 1917 1918 // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) 1919 // is found 1920 // tells us to match just one side of the scopes 1921 else if (inChannelsIn == 0) 1922 { 1923 if (outputValue == inChannelsOut) 1924 return true; 1925 } 1926 else if (inChannelsOut == 0) 1927 { 1928 if (inputValue == inChannelsIn) 1929 return true; 1930 } 1931 } 1932 1933 return false; 1934} 1935 1936//------------------------------------------------------------------------ 1937// MARK: AUAudioUnit Overrides 1938//------------------------------------------------------------------------ 1939- (AUParameterTree*)parameterTree 1940{ 1941 return parameterTreeVar; 1942} 1943 1944//------------------------------------------------------------------------ 1945- (NSArray<AUAudioUnitPreset*>*)factoryPresets 1946{ 1947 return factoryPresetsVar; 1948} 1949 1950//------------------------------------------------------------------------ 1951- (NSArray<NSNumber*>*)channelCapabilities 1952{ 1953 return channelCapabilitiesArray; 1954} 1955 1956//------------------------------------------------------------------------ 1957- (AUAudioUnitBusArray*)inputBusses 1958{ 1959 return _inputBusArray; 1960} 1961 1962//------------------------------------------------------------------------ 1963- (AUAudioUnitBusArray*)outputBusses 1964{ 1965 return _outputBusArray; 1966} 1967 1968//------------------------------------------------------------------------ 1969- (BOOL)canProcessInPlace 1970{ 1971 return canProcessInPlaceValue; 1972} 1973 1974//------------------------------------------------------------------------ 1975- (BOOL)isRenderingOffline 1976{ 1977 return renderingOfflineValue; 1978} 1979 1980//------------------------------------------------------------------------ 1981- (BOOL)supportsMPE 1982{ 1983 if (_editcontroller) 1984 { 1985 FUnknownPtr<INoteExpressionController> nec (_editcontroller); 1986 if (nec) 1987 return YES; 1988 } 1989 return NO; 1990} 1991 1992//------------------------------------------------------------------------ 1993- (void)setRenderingOffline:(BOOL)renderingOffline 1994{ 1995 // set offline rendering of vst3 to true 1996} 1997 1998//------------------------------------------------------------------------ 1999- (NSTimeInterval)latency 2000{ 2001 if (audioProcessor) 2002 return (audioProcessor->getLatencySamples () / sampleRate); 2003 return 0.0; 2004} 2005 2006//------------------------------------------------------------------------ 2007- (NSTimeInterval)tailTime 2008{ 2009 if (audioProcessor) 2010 return (audioProcessor->getTailSamples () / sampleRate); 2011 return 0.0; 2012} 2013 2014//------------------------------------------------------------------------ 2015- (BOOL)shouldChangeToFormat:(AVAudioFormat*)format forBus:(AUAudioUnitBus*)bus 2016{ 2017 // implement ChangeStreamFormat from AUv2 Wrapper here 2018 return [super shouldChangeToFormat:format forBus:bus]; 2019} 2020 2021//------------------------------------------------------------------------ 2022- (NSArray<NSNumber*>*)parametersForOverviewWithCount:(NSInteger)count 2023{ 2024 NSInteger n = [overviewParams count]; 2025 2026 if (count >= n) 2027 return overviewParams; 2028 2029 NSMutableArray<NSNumber*>* overviewParamsWithRange = 2030 [[NSMutableArray<NSNumber*> alloc] initWithArray:overviewParams]; 2031 NSRange range = NSMakeRange (count, (n - count)); 2032 [overviewParamsWithRange removeObjectsInRange:range]; 2033 2034 return overviewParamsWithRange; 2035} 2036 2037//------------------------------------------------------------------------ 2038- (AUAudioUnitPreset*)currentPreset 2039{ 2040 if (currentPreset.number >= 0) 2041 // factory preset 2042 return [factoryPresetsVar objectAtIndex:currentFactoryPresetIndex]; 2043 else 2044 // custom preset 2045 return currentPreset; 2046} 2047 2048//------------------------------------------------------------------------ 2049- (void)setCurrentPreset:(AUAudioUnitPreset*)presentPreset 2050{ 2051 if (nil == presentPreset) 2052 return; 2053 2054 // if it is a factory preset 2055 if (presentPreset.number >= 0) 2056 { 2057 for (AUAudioUnitPreset* factoryPreset in factoryPresetsVar) 2058 { 2059 if (presentPreset.number == factoryPreset.number) 2060 { 2061 2062 if (numPresets > 0) 2063 { 2064 float normalizedValue = (float)presentPreset.number / (float)numPresets; 2065 transferParamChanges.addChange (factoryProgramChangedID, normalizedValue, 0); 2066 _editcontroller->setParamNormalized (factoryProgramChangedID, normalizedValue); 2067 } 2068 2069 // set factory preset as current 2070 currentPreset = presentPreset; 2071 currentFactoryPresetIndex = factoryPreset.number; 2072 NSLog (@"currentPreset Factory: %ld, %@\n", (long)currentFactoryPresetIndex, 2073 factoryPreset.name); 2074 2075 break; 2076 } 2077 } 2078 } 2079 else if (nil != presentPreset.name) 2080 // set custom preset as current 2081 currentPreset = presentPreset; 2082} 2083 2084//------------------------------------------------------------------------ 2085- (NSDictionary<NSString*, id>*)fullState 2086{ 2087 // should flush parameters of VST to save correct state (when not in playback mode) 2088 2089 NSMutableDictionary<NSString*, id>* dict = [[NSMutableDictionary<NSString*, id> alloc] init]; 2090 2091 NSDictionary<NSString*, id>* superDict = [super fullState]; 2092 2093 if (superDict != nullptr) 2094 [dict addEntriesFromDictionary:superDict]; 2095 2096 NSMutableData* processorData = [[NSMutableData alloc] init]; 2097 NSMutableData* controllerData = [[NSMutableData alloc] init]; 2098 2099 if (audioProcessor) 2100 { 2101 NSMutableDataIBStream stream (processorData); 2102 2103 if (FUnknownPtr<IComponent> (audioProcessor)->getState (&stream) != kResultTrue) 2104 [processorData setLength:0]; 2105 } 2106 2107 if (_editcontroller) 2108 { 2109 NSMutableDataIBStream stream (controllerData); 2110 2111 if (_editcontroller->getState (&stream) != kResultTrue) 2112 [controllerData setLength:0]; 2113 } 2114 2115 [dict setObject:processorData forKey:@"Processor State"]; 2116 [dict setObject:controllerData forKey:@"Controller State"]; 2117 2118 return dict; 2119} 2120 2121//------------------------------------------------------------------------ 2122- (void)setFullState:(NSDictionary<NSString*, id>*)newFullState 2123{ 2124 2125 if (newFullState == nullptr) 2126 return; 2127 2128 bool fromProject = false; 2129 2130 fullStateVar = newFullState; 2131 2132 if (!(audioProcessor && _editcontroller)) 2133 return; 2134 2135 // Note: the bypass state is not part of the AU state 2136 bool wasBypassed = false; 2137 if (bypassParamID != -1) 2138 wasBypassed = _editcontroller->getParamNormalized (bypassParamID) >= 0.5 ? true : false; 2139 2140 NSMutableDictionary<NSString*, id>* modifiedState = 2141 [[NSMutableDictionary<NSString*, id> alloc] init]; 2142 [modifiedState addEntriesFromDictionary:newFullState]; 2143 2144 NSString* nsPresetKey = [[NSString alloc] initWithUTF8String:kAUPresetDataKey]; 2145 [modifiedState removeObjectForKey:nsPresetKey]; 2146 2147 NSData* processorData = [modifiedState valueForKey:@"Processor State"]; 2148 int processLen = (int)[processorData length]; 2149 if (processLen == 0) 2150 return; 2151 2152 if (processorData) 2153 { 2154 NSDataIBStream stream (processorData); 2155 if (fromProject) 2156 stream.getAttributes ()->setString (Vst::PresetAttributes::kStateType, 2157 String (Vst::StateType::kProject)); 2158 FUnknownPtr<IComponent> (audioProcessor)->setState (&stream); 2159 } 2160 2161 NSData* controllerData = [modifiedState valueForKey:@"Controller State"]; 2162 2163 if (controllerData) 2164 { 2165 NSDataIBStream processorStream (processorData); 2166 _editcontroller->setComponentState (&processorStream); 2167 2168 NSDataIBStream stream (controllerData); 2169 if (fromProject) 2170 stream.getAttributes ()->setString (Vst::PresetAttributes::kStateType, 2171 String (Vst::StateType::kProject)); 2172 _editcontroller->setState (&stream); 2173 2174 [self syncParameterValues]; 2175 } 2176 2177 if (bypassParamID != -1) 2178 { 2179 transferParamChanges.addChange (bypassParamID, wasBypassed ? 1 : 0, 0); 2180 _editcontroller->setParamNormalized (bypassParamID, wasBypassed ? 1 : 0); 2181 } 2182} 2183 2184//------------------------------------------------------------------------ 2185- (BOOL)allocateRenderResourcesAndReturnError:(NSError**)outError 2186{ 2187 if (![super allocateRenderResourcesAndReturnError:outError]) 2188 return NO; 2189 2190 if (![self validateChannelConfig]) 2191 { 2192 if (outError) 2193 { 2194 *outError = [NSError errorWithDomain:NSOSStatusErrorDomain 2195 code:kAudioUnitErr_FormatNotSupported 2196 userInfo:nil]; 2197 } 2198 2199 // Notify superclass that initialization was not successful 2200 self.renderResourcesAllocated = NO; 2201 2202 return NO; 2203 } 2204 2205 [self allocateBusBuffers]; 2206 2207 [self setupProcessing]; 2208 2209 if (self.musicalContextBlock) 2210 musicalContext = self.musicalContextBlock; 2211 else 2212 musicalContext = nil; 2213 2214 if (self.transportStateBlock) 2215 transportContext = self.transportStateBlock; 2216 else 2217 transportContext = nil; 2218 2219 return YES; 2220} 2221 2222//------------------------------------------------------------------------ 2223- (void)deallocateRenderResources 2224{ 2225 musicalContext = nullptr; 2226 transportContext = nullptr; 2227 2228 for (int i = 0; i > inputBusBuffers.size (); i++) 2229 inputBusBuffers.at (i).deallocateRenderResources (); 2230 2231 for (int i = 0; i > outputBusBuffers.size (); i++) 2232 outputBusBuffers.at (i).deallocateRenderResources (); 2233 2234 inputBusBuffers.clear (); 2235 outputBusBuffers.clear (); 2236 2237 if (audioProcessor) 2238 { 2239 audioProcessor->setProcessing (false); 2240 2241 FUnknownPtr<IComponent> component (audioProcessor); 2242 component->setActive (false); 2243 } 2244 2245 [super deallocateRenderResources]; 2246} 2247 2248//------------------------------------------------------------------------ 2249- (AUInternalRenderBlock)internalRenderBlock 2250{ 2251 return ^AUAudioUnitStatus ( 2252 AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp, 2253 AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList* outputData, 2254 const AURenderEvent* realtimeEventListHead, AURenderPullInputBlock pullInputBlock) { 2255 2256 // process events/params 2257 for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; 2258 event = event->head.next) 2259 { 2260 switch (event->head.eventType) 2261 { 2262 case AURenderEventMIDI: 2263 { 2264 mpeHandler.process (mpeHandlerContext, &event->MIDI, timestamp); 2265 break; 2266 } 2267 2268 case AURenderEventParameter: 2269 case AURenderEventParameterRamp: 2270 { 2271 componentHelper->performEdit ((int)event->parameter.parameterAddress, 2272 event->parameter.value); 2273 } 2274 break; 2275 2276 default: break; 2277 } 2278 } 2279 2280 // prepare contexts 2281 RenderProcessContext renderProcessContext = RenderProcessContext (); 2282 2283 renderProcessContext.musicalContext = musicalContext; 2284 renderProcessContext.transportContext = transportContext; 2285 renderProcessContext.processContext = &(processContext); 2286 renderProcessContext.sampleRate = sampleRate; 2287 renderProcessContext.timestamp = timestamp; 2288 2289 renderProcessContext.updateProcessContext (renderProcessContext); 2290 2291 inputParamChanges.clearQueue (); 2292 transferParamChanges.transferChangesTo (inputParamChanges); 2293 processData.numSamples = frameCount; 2294 2295 if (frameCount > 0) 2296 { 2297 FUnknownPtr<IComponent> component (audioProcessor); 2298 int32 inputBusCount = component->getBusCount (kAudio, kInput); 2299 int32 outputBusCount = component->getBusCount (kAudio, kOutput); 2300 AudioUnitRenderActionFlags pullFlags = 0; 2301 2302 // pull input buffer 2303 for (int32 i = 0; i < inputBusCount; i++) 2304 { 2305 UInt32 byteSize = frameCount * sizeof (float); 2306 2307 if (pullInputBlock == nullptr || 2308 inputBusBuffers.at (i).pullInput (&pullFlags, timestamp, frameCount, i, 2309 pullInputBlock) != noErr) 2310 { 2311 for (int32 channel = 0; channel < inputBusBuffers.at (i).bus.format.channelCount; 2312 channel++) 2313 memset ( 2314 inputBusBuffers.at (i).mutableAudioBufferList->mBuffers[channel].mData, 0, 2315 byteSize); 2316 } 2317 2318 if (actionFlags != nullptr && 2319 (*actionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0) 2320 { 2321 for (int32 channel = 0; channel < inputBusBuffers.at (i).bus.format.channelCount; 2322 channel++) 2323 memset ( 2324 inputBusBuffers.at (i).mutableAudioBufferList->mBuffers[channel].mData, 0, 2325 byteSize); 2326 } 2327 } 2328 2329 // prepare output buffer 2330 for (int32 i = 0; i < outputBusCount; i++) 2331 outputBusBuffers.at (i).prepareOutputBufferList (outputData, frameCount, 2332 i == outputBusNumber ? true : false); 2333 2334 if (outputData->mBuffers[0].mData == nullptr) 2335 { 2336 for (UInt32 channel = 0; channel < outputData->mNumberBuffers; channel++) 2337 outputData->mBuffers[channel].mData = 2338 inputBusBuffers.at (outputBusNumber) 2339 .mutableAudioBufferList->mBuffers[channel] 2340 .mData; 2341 } 2342 2343 // copy input buffers 2344 for (int32 i = 0; i < inputBusCount; i++) 2345 { 2346 AVAudioChannelCount channelCount = inputBusBuffers.at (i).bus.format.channelCount; 2347 processData.inputs[i].numChannels = int32 (channelCount); 2348 2349 for (int32 channel = 0; channel < channelCount; channel++) 2350 processData.inputs[i].channelBuffers32[channel] = 2351 (Sample32*)inputBusBuffers.at (i) 2352 .mutableAudioBufferList->mBuffers[channel] 2353 .mData; 2354 } 2355 2356 // copy output buffers 2357 for (int32 i = 0; i < outputBusCount; i++) 2358 { 2359 AVAudioChannelCount channelCount = outputBusBuffers.at (i).bus.format.channelCount; 2360 processData.outputs[i].numChannels = int32 (channelCount); 2361 2362 for (int32 channel = 0; channel < channelCount; channel++) 2363 { 2364 if (i == outputBusNumber) 2365 { 2366 processData.outputs[i].channelBuffers32[channel] = 2367 (Sample32*)outputData->mBuffers[channel].mData; 2368 } 2369 else 2370 { 2371 processData.outputs[i].channelBuffers32[channel] = 2372 (Sample32*)outputBusBuffers.at (i) 2373 .mutableAudioBufferList->mBuffers[channel] 2374 .mData; 2375 } 2376 } 2377 } 2378 2379 // process audio 2380 audioProcessor->process (processData); 2381 2382 outputParamTransfer.transferChangesFrom (outputParamChanges); 2383 outputParamChanges.clearQueue (); 2384 inputEvents.clear (); 2385 2386 pullFlags &= ~kAudioUnitRenderAction_OutputIsSilence; 2387 } 2388 return noErr; 2389 }; 2390} 2391@end 2392 2393//------------------------------------------------------------------------ 2394// AUv3WrapperViewController 2395//------------------------------------------------------------------------ 2396#pragma mark - ViewController (implementing AUViewController and AUAudioUnitFactory) 2397@interface AUv3WrapperViewController () 2398{ 2399 IPlugView* plugView; 2400 FObject* dynlib; 2401 AUPlugFrame* plugFrame; 2402 IEditController* editController; 2403 BOOL isAttached; 2404} 2405@end 2406 2407//------------------------------------------------------------------------ 2408// AUv3WrapperViewController 2409//------------------------------------------------------------------------ 2410@implementation AUv3WrapperViewController 2411 2412//------------------------------------------------------------------------ 2413- (void)loadView 2414{ 2415 SMTG_IOS_MAC_VIEW* view = [[SMTG_IOS_MAC_VIEW alloc] initWithFrame:CGRectMake (0, 0, 0, 0)]; 2416 [self setView:view]; 2417} 2418 2419//------------------------------------------------------------------------ 2420- (void)setFrame:(CGRect)newSize 2421{ 2422 [super.view setFrame:newSize]; 2423 ViewRect viewRect (0, 0, newSize.size.width, newSize.size.height); 2424 2425 if (plugView) 2426 plugView->onSize (&viewRect); 2427} 2428 2429//------------------------------------------------------------------------ 2430- (AUv3Wrapper*)getAudioUnit 2431{ 2432 return _audioUnit; 2433} 2434 2435//------------------------------------------------------------------------ 2436- (void)setAudioUnit:(AUv3Wrapper*)audioUnit 2437{ 2438 if (audioUnit == nil) 2439 return; 2440 2441 _audioUnit = audioUnit; 2442 2443 editController = [_audioUnit editcontroller]; 2444 if (editController) 2445 editController->addRef (); 2446 2447 dispatch_async (dispatch_get_main_queue (), ^{ 2448 //------------------------------------------------------------------------ 2449 // attach from VST3Editor.mm 2450 //------------------------------------------------------------------------ 2451 FUnknownPtr<IEditController2> ec2 (editController); 2452 if (ec2) 2453 ec2->setKnobMode (kLinearMode); 2454 2455 // create view 2456 plugView = editController->createView (ViewType::kEditor); 2457 if (plugView) 2458 { 2459 if (plugView->isPlatformTypeSupported (SMTG_IOS_MAC_PLATFORMTYPE) == kResultTrue) 2460 { 2461 plugFrame = NEW AUPlugFrame (self.view); 2462 plugView->setFrame (plugFrame); 2463 2464 if (plugView->attached ((__bridge void*)self.view, SMTG_IOS_MAC_PLATFORMTYPE) == 2465 kResultTrue) 2466 { 2467 ViewRect vr; 2468 if (plugView->getSize (&vr) == kResultTrue) 2469 { 2470 int viewWidth = vr.right - vr.left; 2471 int viewHeight = vr.bottom - vr.top; 2472 CGRect newSize = CGRectMake (0, 0, viewWidth, viewHeight); 2473 [self setFrame:newSize]; 2474 self.preferredContentSize = CGSizeMake (viewWidth, viewHeight); 2475 } 2476 } 2477 } 2478 else 2479 { 2480 plugView->release (); 2481 plugView = 0; 2482 } 2483 } 2484 }); 2485} 2486 2487//------------------------------------------------------------------------ 2488- (void)dealloc 2489{ 2490 if (plugView) 2491 { 2492 // remove plugFrame from plugView 2493 if (isAttached) 2494 { 2495 plugView->setFrame (0); 2496 plugView->removed (); 2497 } 2498 2499 // release plugView 2500 plugView->release (); 2501 2502 // release plugFrame 2503 if (plugFrame) 2504 plugFrame->release (); 2505 2506 // release editController 2507 if (editController) 2508 { 2509 editController->release (); 2510 editController = 0; 2511 } 2512 } 2513 2514 if (dynlib) 2515 dynlib->release (); 2516 2517 self.audioUnit = nil; 2518} 2519 2520@end 2521