Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename :
// Created by : Steinberg, 03/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
int main (int argc, const char* argv[])
{
return NSApplicationMain (argc, argv);
}
@@ -0,0 +1,75 @@
include(SMTG_AddVST3AuV3)
# iOS target
if(SMTG_MAC)
if(XCODE)
set(auv3wrapperlib_sources
${SDK_ROOT}/public.sdk/source/vst/auv3wrapper/Shared/AUv3Wrapper.mm
${SDK_ROOT}/public.sdk/source/vst/auv3wrapper/Shared/AUv3Wrapper.h
${SDK_ROOT}/public.sdk/source/vst/auv3wrapper/Shared/AUv3AudioEngine.mm
${SDK_ROOT}/public.sdk/source/vst/auv3wrapper/Shared/AUv3AudioEngine.h
${SDK_ROOT}/public.sdk/source/vst/auwrapper/NSDataIBStream.mm
${SDK_ROOT}/public.sdk/source/vst/auwrapper/NSDataIBStream.h
${SDK_ROOT}/public.sdk/source/vst/utility/mpeprocessor.cpp
${SDK_ROOT}/public.sdk/source/vst/utility/mpeprocessor.h
)
# --------------------------------------------------------------------------------------------------------
set(target auv3_wrapper_macos)
add_library(${target}
STATIC
${auv3wrapperlib_sources}
)
set_target_properties(${target}
PROPERTIES
${SDK_IDE_LIBS_FOLDER} XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
)
target_compile_features(${target}
PUBLIC
cxx_std_17
)
target_link_libraries(${target}
PRIVATE
sdk_hosting
)
if (SMTG_AUV3_WRAPPER_EXTERNAL_PLUGIN_FACTORY)
target_compile_definitions(${target}
PRIVATE
SMTG_AUV3_WRAPPER_EXTERNAL_PLUGIN_FACTORY=1)
endif()
# --------------------------------------------------------------------------------------------------------
if(SMTG_ENABLE_IOS_TARGETS)
set(target auv3_wrapper_ios)
add_library(${target}
STATIC
${auv3wrapperlib_sources}
)
set_target_properties(${target}
PROPERTIES
${SDK_IDE_LIBS_FOLDER} XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
)
set_target_properties(${target}
PROPERTIES
LINK_FLAGS "-Wl,-F/Library/Frameworks"
)
smtg_target_set_platform_ios(${target})
target_compile_features(${target}
PUBLIC
cxx_std_17
)
target_link_libraries(${target}
PRIVATE
sdk_hosting_ios
)
if (SMTG_AUV3_WRAPPER_EXTERNAL_PLUGIN_FACTORY)
target_compile_definitions(${target}
PRIVATE
SMTG_AUV3_WRAPPER_EXTERNAL_PLUGIN_FACTORY=1
)
endif()
endif()
else()
message("* To enable building the AUv3 Wrapper example for iOS you need to set the SMTG_IOS_DEVELOPMENT_TEAM and use the Xcode generator")
endif()
endif()
@@ -0,0 +1,31 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : AUv3AudioEngine.h
// Created by : Steinberg, 07/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#import <AVFoundation/AVFoundation.h>
@interface AUv3AudioEngine : NSObject
@property (assign) AUAudioUnit* currentAudioUnit;
- (NSError*)loadAudioFile:(NSURL*)url;
- (instancetype)initWithComponentType:(uint32_t)unitComponentType;
- (void)loadAudioUnitWithComponentDescription:(AudioComponentDescription)desc
completion:(void (^) (void))completionBlock;
- (BOOL)startStop;
- (void)shutdown;
@end
@@ -0,0 +1,424 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : AUv3AudioEngine.mm
// Created by : Steinberg, 07/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#import "AUv3AudioEngine.h"
#import <CoreMIDI/CoreMIDI.h>
#import <functional>
#import <vector>
#import <utility>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
class MidiIO
{
public:
using ReadCallback = std::function<void (const MIDIPacketList* pktlist)>;
MidiIO (ReadCallback&& callback) : readCallback (std::move (callback)) { activate (); }
~MidiIO () = default;
private:
bool activate ();
bool deactivate ();
void onSourceAdded (MIDIObjectRef source);
void onSetupChanged ();
void disconnectSources ();
void onInput (const MIDIPacketList* pktlist);
static void readProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* srcConnRefCon);
static void notifyProc (const MIDINotification* message, void* refCon);
MIDIClientRef client {0};
MIDIPortRef inputPort {0};
MIDIEndpointRef destPort {0};
ReadCallback readCallback;
using ConnectionList = std::vector<MIDIEndpointRef>;
ConnectionList connectedSources;
};
//------------------------------------------------------------------------
bool MidiIO::activate ()
{
if (client)
return true;
OSStatus err;
NSString* name = [[NSBundle mainBundle] bundleIdentifier];
if ((err = MIDIClientCreate ((__bridge CFStringRef)name, notifyProc, this, &client) != noErr))
return false;
if ((err = MIDIInputPortCreate (client, CFSTR ("Input"), readProc, this, &inputPort) != noErr))
{
MIDIClientDispose (client);
client = 0;
return false;
}
name = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleName"];
if ((err = MIDIDestinationCreate (client, (__bridge CFStringRef)name, readProc, this,
&destPort) != noErr))
{
MIDIPortDispose (inputPort);
inputPort = 0;
MIDIClientDispose (client);
client = 0;
return false;
}
onSetupChanged ();
return true;
}
//------------------------------------------------------------------------
bool MidiIO::deactivate ()
{
if (client == 0)
return true;
disconnectSources ();
auto status = MIDIEndpointDispose (destPort);
destPort = 0;
status |= MIDIPortDispose (inputPort);
inputPort = 0;
status |= MIDIClientDispose (client);
client = 0;
return status == noErr;
}
//------------------------------------------------------------------------
void MidiIO::onSourceAdded (MIDIObjectRef source)
{
connectedSources.push_back ((MIDIEndpointRef)source);
MIDIPortConnectSource (inputPort, (MIDIEndpointRef)source, NULL);
}
//------------------------------------------------------------------------
void MidiIO::onSetupChanged ()
{
disconnectSources ();
ItemCount numSources = MIDIGetNumberOfSources ();
for (ItemCount i = 0; i < numSources; i++)
{
onSourceAdded (MIDIGetSource (i));
}
}
//------------------------------------------------------------------------
void MidiIO::disconnectSources ()
{
for (auto source : connectedSources)
MIDIPortDisconnectSource (inputPort, source);
connectedSources.clear ();
}
//------------------------------------------------------------------------
void MidiIO::onInput (const MIDIPacketList* pktlist)
{
if (readCallback)
readCallback (pktlist);
}
//------------------------------------------------------------------------
void MidiIO::readProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* srcConnRefCon)
{
MidiIO* io = static_cast<MidiIO*> (readProcRefCon);
io->onInput (pktlist);
}
//------------------------------------------------------------------------
void MidiIO::notifyProc (const MIDINotification* message, void* refCon)
{
if (message->messageID == kMIDIMsgSetupChanged)
{
MidiIO* mio = (MidiIO*)refCon;
mio->onSetupChanged ();
}
}
using MidiIOPtr = std::unique_ptr<MidiIO>;
//------------------------------------------------------------------------
} // Vst
} // Steinberg
//------------------------------------------------------------------------
@implementation AUv3AudioEngine
{
AVAudioEngine* audioEngine;
AVAudioFile* audioFile;
AVAudioPlayerNode* playerNode;
AVAudioUnit* avAudioUnit;
Steinberg::Vst::MidiIOPtr midi;
UInt32 componentType;
BOOL playing;
BOOL isDone;
}
//------------------------------------------------------------------------
- (instancetype)initWithComponentType:(uint32_t)unitComponentType
{
self = [super init];
isDone = false;
if (self)
{
audioEngine = [[AVAudioEngine alloc] init];
componentType = unitComponentType;
}
#if TARGET_OS_IPHONE
NSError* error = nil;
BOOL success =
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (NO == success)
{
NSLog (@"Error setting category: %@", [error localizedDescription]);
}
#endif
playing = false;
return self;
}
//------------------------------------------------------------------------
- (void)shutdown
{
if (playing)
[self stopPlaying];
audioEngine = nil;
midi.reset ();
}
//------------------------------------------------------------------------
- (void)onAudioUnitInstantiated:(AVAudioUnit* __nullable)audioUnit
error:(NSError* __nullable)error
completion:(void (^) (void))completionBlock
{
if (audioUnit == nil)
return;
avAudioUnit = audioUnit;
_currentAudioUnit = avAudioUnit.AUAudioUnit;
[audioEngine attachNode:avAudioUnit];
[audioEngine connect:avAudioUnit to:audioEngine.outputNode format:audioFile.processingFormat];
completionBlock ();
}
//------------------------------------------------------------------------
- (void)loadAudioUnitWithComponentDescription:(AudioComponentDescription)desc
completion:(void (^) (void))completionBlock
{
[AVAudioUnit instantiateWithComponentDescription:desc
options:0
completionHandler:^(AVAudioUnit* __nullable audioUnit,
NSError* __nullable error) {
[self onAudioUnitInstantiated:audioUnit
error:error
completion:completionBlock];
}];
if (componentType == kAudioUnitType_MusicDevice)
{
midi = Steinberg::Vst::MidiIOPtr (
new Steinberg::Vst::MidiIO ([=] (const MIDIPacketList* pktlist) {
[self scheduleMIDIPackets:pktlist];
}));
}
}
//------------------------------------------------------------------------
- (NSError*)loadAudioFile:(NSURL*)url
{
BOOL isPlaying = playing;
if (isPlaying)
[self startStop];
if (playerNode)
{
[playerNode stop];
[audioEngine detachNode:playerNode];
}
NSError* error = nil;
audioFile = [[AVAudioFile alloc] initForReading:url error:&error];
if (error)
return error;
[audioEngine detachNode:avAudioUnit];
[audioEngine attachNode:avAudioUnit];
[audioEngine connect:avAudioUnit to:audioEngine.outputNode format:audioFile.processingFormat];
playerNode = [[AVAudioPlayerNode alloc] init];
[audioEngine attachNode:playerNode];
[audioEngine connect:playerNode to:avAudioUnit format:audioFile.processingFormat];
if (isPlaying)
[self startStop];
return nil;
}
//------------------------------------------------------------------------
- (BOOL)startStop
{
playing = !playing;
playing ? ([self startPlaying]) : ([self stopPlaying]);
return playing;
}
//------------------------------------------------------------------------
- (void)startPlaying
{
[self activateSession:true];
NSError* error = nil;
if (![audioEngine startAndReturnError:&error])
{
NSLog (@"engine failed to start: %@", error);
return;
}
if (playerNode)
{
[self loopAudioFile];
[playerNode play];
}
}
//------------------------------------------------------------------------
- (void)stopPlaying
{
if (playerNode)
[playerNode stop];
[audioEngine stop];
[self activateSession:false];
}
//------------------------------------------------------------------------
- (void)loopAudioFile
{
if (playerNode)
{
[playerNode scheduleFile:audioFile
atTime:nil
completionHandler:^{
if (playerNode.playing)
[self loopAudioFile];
}];
}
}
//------------------------------------------------------------------------
- (void)scheduleMIDIPackets:(const MIDIPacketList*) pktlist
{
if (!_currentAudioUnit || _currentAudioUnit.scheduleMIDIEventBlock == nil)
return;
auto packet = &pktlist->packet[0];
for (auto i = 0u; i < pktlist->numPackets; i++)
{
_currentAudioUnit.scheduleMIDIEventBlock (AUEventSampleTimeImmediate, 0, packet->length,
packet->data);
packet = MIDIPacketNext (packet);
}
}
//------------------------------------------------------------------------
- (void)loopMIDIsequence
{
UInt8 cbytes[3], *cbytesPtr;
cbytesPtr = cbytes;
dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
cbytesPtr[0] = 0xB0;
cbytesPtr[1] = 123;
cbytesPtr[2] = 0;
if (_currentAudioUnit.scheduleMIDIEventBlock == nil)
return;
_currentAudioUnit.scheduleMIDIEventBlock (AUEventSampleTimeImmediate, 0, 3, cbytesPtr);
usleep (useconds_t (0.1 * 1e6));
float releaseTime = 0.05;
usleep (useconds_t (0.1 * 1e6));
int i = 0;
@synchronized (self)
{
while (playing)
{
if (releaseTime < 10.0)
releaseTime = (releaseTime * 1.05) > 10.0 ? (releaseTime * 1.05) : 10.0;
cbytesPtr[0] = 0x90;
cbytesPtr[1] = UInt8 (60 + i);
cbytesPtr[2] = UInt8 (64); // note on
_currentAudioUnit.scheduleMIDIEventBlock (AUEventSampleTimeImmediate, 0, 3,
cbytesPtr);
usleep (useconds_t (0.2 * 1e6));
cbytesPtr[0] = 0x80;
cbytesPtr[1] = UInt8 (60 + i);
cbytesPtr[2] = UInt8 (0); // note off
_currentAudioUnit.scheduleMIDIEventBlock (AUEventSampleTimeImmediate, 0, 3,
cbytesPtr);
i += 2;
if (i >= 24)
{
i = -12;
}
}
cbytesPtr[0] = 0xB0;
cbytesPtr[1] = 123;
cbytesPtr[2] = 0;
_currentAudioUnit.scheduleMIDIEventBlock (AUEventSampleTimeImmediate, 0, 3, cbytesPtr);
isDone = true;
}
});
}
//------------------------------------------------------------------------
- (void)activateSession:(BOOL)active
{
#if TARGET_OS_IPHONE
NSError* error = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive:active error:nil];
if (NO == success)
{
NSLog (@"Error setting category: %@", [error localizedDescription]);
}
#endif
}
@end
@@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : AUv3Wrapper.h
// Created by : Steinberg, 07/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#import <CoreAudioKit/AUViewController.h>
@class AUv3Wrapper;
//------------------------------------------------------------------------
@interface AUv3WrapperViewController : AUViewController
@property (nonatomic, strong) AUv3Wrapper* audioUnit;
@end
//------------------------------------------------------------------------
@interface AUv3Wrapper : AUAudioUnit
- (void)beginEdit:(int32_t)tag;
- (void)endEdit:(int32_t)tag;
- (void)performEdit:(int32_t)tag value:(double)value;
- (void)syncParameterValues;
- (void)updateParameters;
- (void)onTimer;
- (void)onParamTitlesChanged;
- (void)onNoteExpressionChanged;
- (void)onLatencyChanged;
- (BOOL)enableMPESupport:(BOOL)state;
- (BOOL)setMPEInputDeviceMasterChannel:(NSInteger)masterChannel
memberBeginChannel:(NSInteger)memberBeginChannel
memberEndChannel:(NSInteger)memberEndChannel;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename :
// Created by : Steinberg, 07/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#import "AUv3Wrapper.h"
@interface AUv3WrapperViewController (AUAudioUnitFactory) <AUAudioUnitFactory>
@end
@@ -0,0 +1,41 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename :
// Created by : Steinberg, 07/2017.
// Description : VST 3 AUv3Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#import "AUv3WrapperFactory.h"
@implementation AUv3WrapperViewController (AUAudioUnitFactory)
- (AUv3Wrapper *) createAudioUnitWithComponentDescription:(AudioComponentDescription) desc error:(NSError **)error {
@synchronized (self)
{
if (!self.audioUnit)
{
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(), [&]{
self.audioUnit = [[AUv3Wrapper alloc] initWithComponentDescription:desc error:error];
});
}
else
{
self.audioUnit = [[AUv3Wrapper alloc] initWithComponentDescription:desc error:error];
}
}
}
return self.audioUnit;
}
@end