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,67 @@
function(smtg_target_setup_options target)
set(options)
set(oneValueArgs
BUNDLE_IDENTIFIER
COMPANY_NAME
)
set(multiValueArgs)
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}: The following parameters are unrecognized: ${ARG_UNPARSED_ARGUMENTS}")
endif()
if(NOT ARG_BUNDLE_IDENTIFIER)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}: BUNDLE_IDENTIFIER must be specified")
endif()
if(NOT ARG_COMPANY_NAME)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}: ARG_COMPANY_NAME must be specified")
endif()
smtg_target_configure_version_file(${target})
if(SMTG_MAC)
smtg_target_set_bundle(${target}
BUNDLE_IDENTIFIER "${ARG_BUNDLE_IDENTIFIER}"
COMPANY_NAME "${ARG_COMPANY_NAME}"
)
elseif(SMTG_WIN)
target_sources(${target}
PRIVATE
resource/info.rc
)
endif()
target_link_libraries(${target}
PRIVATE
sdk
)
endfunction()
function(smtg_target_setup_as_vst3_example target)
set_target_properties(${target}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}
)
target_compile_features(${target}
PUBLIC
cxx_std_17
)
smtg_target_setup_options(${target}
BUNDLE_IDENTIFIER "com.steinberg.vst3.${target}"
COMPANY_NAME "Steinberg Media Technologies"
)
endfunction()
if(ANDROID)
add_subdirectory(adelay)
return()
endif(ANDROID)
include(SMTG_AddSubDirectories)
smtg_add_subdirectories()
@@ -0,0 +1,2 @@
/DerivedData
/build
@@ -0,0 +1,102 @@
# iOS target
if(SMTG_MAC AND SMTG_BUILD_INTERAPPAUDIO)
if(XCODE AND SMTG_ENABLE_IOS_TARGETS)
set(target noteexpressionsynth_iaa_ios)
set(${target}_xib_resources
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/InterAppAudio/Images.xcassets
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/InterAppAudio/LaunchScreen.storyboard
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/InterAppAudio/noteexpressionsynth_ios.entitlements
${SDK_ROOT}/public.sdk/source/vst/interappaudio/PresetBrowserView.xib
${SDK_ROOT}/public.sdk/source/vst/interappaudio/PresetSaveView.xib
${SDK_ROOT}/public.sdk/source/vst/interappaudio/SettingsView.xib
InterAppAudioExample/VSTInterAppAudioHostUIControllerView.xib
)
set(${target}_sources
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/brownnoise.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/factory.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/filter.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_controller.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_controller.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_processor.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_processor.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_ui.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_ui.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_voice.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_expression_synth_voice.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_touch_controller.cpp
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/note_touch_controller.h
${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/source/version.h
${SDK_ROOT}/public.sdk/source/main/macmain.cpp
${SDK_ROOT}/public.sdk/source/vst/auwrapper/NSDataIBStream.mm
${SDK_ROOT}/public.sdk/source/vst/hosting/eventlist.cpp
${SDK_ROOT}/public.sdk/source/vst/hosting/hostclasses.cpp
${SDK_ROOT}/public.sdk/source/vst/hosting/parameterchanges.cpp
${SDK_ROOT}/public.sdk/source/vst/hosting/pluginterfacesupport.cpp
${SDK_ROOT}/public.sdk/source/vst/hosting/processdata.cpp
${SDK_ROOT}/public.sdk/source/vst/vstguieditor.cpp
${VSTGUI_ROOT}/vstgui4/vstgui/contrib/keyboardview.cpp
${VSTGUI_ROOT}/vstgui4/vstgui/contrib/keyboardview.h
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3editor.cpp
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3editor.h
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3groupcontroller.cpp
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3groupcontroller.h
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3padcontroller.cpp
${VSTGUI_ROOT}/vstgui4/vstgui/plugin-bindings/vst3padcontroller.h
${VSTGUI_ROOT}/vstgui4/vstgui/vstgui_ios.mm
${VSTGUI_ROOT}/vstgui4/vstgui/vstgui_uidescription.cpp
InterAppAudioExample/VSTInterAppAudioAppDelegate.mm
InterAppAudioExample/VSTInterAppAudioHostUIControllerViewController.mm
InterAppAudioExample/main.m
)
set(prefix_header ${SDK_ROOT}/public.sdk/samples/vst/InterAppAudio/InterAppAudioExample/InterAppAudioExample-Prefix.pch)
add_executable(${target} ${${target}_sources} ${${target}_xib_resources})
smtg_target_set_platform_ios(${target})
target_compile_options(${target}
PUBLIC
-DVSTGUI_LIVE_EDITING=0
) # NO VSTGUI LIVE EDITING SUPPORT FOR iOS
set_target_properties(${target}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}
)
set_target_properties(${target}
PROPERTIES
BUNDLE TRUE
RESOURCE "${${target}_xib_resources}"
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_LIST_DIR}/../note_expression_synth/resource/InterAppAudio/noteexpressionsynth_ios.entitlements"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${SMTG_CODE_SIGN_IDENTITY_IOS}"
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" # prevent warning
XCODE_ATTRIBUTE_GCC_PREFIX_HEADER ${prefix_header}
XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE "YES"
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${SMTG_IOS_DEVELOPMENT_TEAM}
)
target_link_libraries(${target}
PRIVATE
interappaudio
"-framework QuartzCore"
"-framework MobileCoreServices"
"-framework Accelerate"
"-framework ImageIO"
"-framework GLKit"
"-framework CoreText"
)
smtg_target_set_bundle(${target} INFOPLIST "${CMAKE_CURRENT_LIST_DIR}/../note_expression_synth/resource/InterAppAudio/NoteExpressionSynthExample.plist" PREPROCESS)
target_include_directories(${target}
PUBLIC
${ROOT}/vstgui4
)
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/about.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/background.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/groupframe.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/knob big.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/knob.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/knob2.png")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/note_expression_synth.uidesc")
smtg_target_add_vst3_resource(${target} "${SDK_ROOT}/public.sdk/samples/vst/note_expression_synth/resource/vst3_logo_small.png")
else()
message("[SMTG] * To enable building the InterAppAudio NoteExpressionSynth example for iOS you need to set the SMTG_IOS_DEVELOPMENT_TEAM and use the Xcode generator")
endif(XCODE AND SMTG_ENABLE_IOS_TARGETS)
endif(SMTG_MAC AND SMTG_BUILD_INTERAPPAUDIO)
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AudioComponents</key>
<array>
<dict>
<key>manufacturer</key>
<string>SMTG</string>
<key>name</key>
<string>ADelay VST3</string>
<key>subtype</key>
<string>adly</string>
<key>type</key>
<string>aurx</string>
<key>version</key>
<integer>1</integer>
</dict>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.steinberg.interappaudioexamples.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UIStatusBarHidden~ipad</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/InterAppAudioExample-Prefix.pch
// Created by : Steinberg, 08/2013
// Description :
//
//-----------------------------------------------------------------------------
// 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 <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>inter-app-audio</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,26 @@
// clang-format off
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/VSTInterAppAudioAppDelegate.h
// Created by : Steinberg, 08/2013
// Description :
// Flags : clang-format SMTGSequencer
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// clang-format on
#import "public.sdk/source/vst/interappaudio/VSTInterAppAudioAppDelegateBase.h"
//------------------------------------------------------------------------
@interface VSTInterAppAudioAppDelegate : VSTInterAppAudioAppDelegateBase
//------------------------------------------------------------------------
@end
@@ -0,0 +1,119 @@
// clang-format off
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/VSTInterAppAudioAppDelegate.mm
// Created by : Steinberg, 08/2013
// Description :
// Flags : clang-format SMTGSequencer
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// clang-format on
#import "VSTInterAppAudioAppDelegate.h"
#import "VSTInterAppAudioHostUIControllerViewController.h"
#import "public.sdk/source/vst/interappaudio/AudioIO.h"
using namespace Steinberg::Vst::InterAppAudio;
//------------------------------------------------------------------------
@interface VSTInterAppAudioAppDelegate ()
//------------------------------------------------------------------------
{
UIButton* showHostView;
}
@end
//------------------------------------------------------------------------
@implementation VSTInterAppAudioAppDelegate
//------------------------------------------------------------------------
//------------------------------------------------------------------------
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
if ([super application:application didFinishLaunchingWithOptions:launchOptions])
{
[self performSelector:@selector (createShowHostViewButton) withObject:nil afterDelay:0.2];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector (audioIOConnectionChanged)
name:AudioIO::kConnectionStateChange
object:nil];
return YES;
}
return NO;
}
//------------------------------------------------------------------------
- (NSUInteger)application:(UIApplication*)application
supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
//------------------------------------------------------------------------
- (void)audioIOConnectionChanged
{
showHostView.hidden = AudioIO::instance ()->getInterAppAudioConnected () == false;
if (showHostView.hidden)
{
for (id childController in [self.window.rootViewController childViewControllers])
{
if ([childController
isKindOfClass:[VSTInterAppAudioHostUIControllerViewController class]])
{
[childController hideView:self];
}
}
}
}
//------------------------------------------------------------------------
- (void)createShowHostViewButton
{
showHostView = [UIButton buttonWithType:UIButtonTypeInfoDark];
[showHostView addTarget:self
action:@selector (showHostViewAction:)
forControlEvents:UIControlEventTouchDown];
const CGFloat margin = 15;
CGRect frame = showHostView.frame;
frame.origin.y =
[self.window.rootViewController.view bounds].size.height - (frame.size.height + margin);
frame.origin.x = margin;
showHostView.frame = frame;
[self.window.rootViewController.view addSubview:showHostView];
if (AudioIO::instance ()->getInterAppAudioConnected () == false)
{
showHostView.hidden = YES;
}
}
//------------------------------------------------------------------------
- (void)showHostViewAction:(id)sender
{
VSTInterAppAudioHostUIControllerViewController* controller =
[[VSTInterAppAudioHostUIControllerViewController alloc] init];
[self.window.rootViewController addChildViewController:controller];
CGRect frame = controller.view.frame;
frame.origin.y = [self.window.rootViewController.view bounds].size.height;
controller.view.frame = frame;
[self.window.rootViewController.view addSubview:controller.view];
frame.origin.y = [self.window.rootViewController.view bounds].size.height - frame.size.height;
[UIView animateWithDuration:0.3 animations:^{ controller.view.frame = frame; }];
}
@end
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="3.0" toolsVersion="4471.1" systemVersion="12E55" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3697.3"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="VSTInterAppAudioHostUIControllerViewController">
<connections>
<outlet property="hostButton" destination="vf0-Cd-0Xg" id="wcF-LJ-CxA"/>
<outlet property="view" destination="2" id="3"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="2">
<rect key="frame" x="0.0" y="0.0" width="492" height="104"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vf0-Cd-0Xg">
<rect key="frame" x="408" y="20" width="64" height="64"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
<state key="normal" title="Goto Host">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="switchToHost:" destination="-1" eventType="touchUpInside" id="ttD-Qy-eUd"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="s4k-Xf-tiu">
<rect key="frame" x="0.0" y="60" width="73" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" title="Close">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="hideView:" destination="-1" eventType="touchUpInside" id="MDK-lh-cXb"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="b7T-FM-ORL">
<rect key="frame" x="286" y="20" width="64" height="64"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="37"/>
<state key="normal" title="▶">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="play:" destination="-1" eventType="touchUpInside" id="sTf-N9-aIV"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iQU-IE-WGe">
<rect key="frame" x="214" y="20" width="64" height="64"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="37"/>
<state key="normal" title="⏪">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="rewind:" destination="-1" eventType="touchUpInside" id="wCj-ym-Zbp"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oIG-ts-Ybg">
<rect key="frame" x="142" y="20" width="64" height="64"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="37"/>
<state key="normal" title="🔴">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="record:" destination="-1" eventType="touchUpInside" id="FDc-fT-H5V"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="0.80000000000000004" colorSpace="calibratedRGB"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</view>
</objects>
</document>
@@ -0,0 +1,34 @@
// clang-format off
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/VSTInterAppAudioHostUIControllerViewController.h
// Created by : Steinberg, 08/2013
// Description :
// Flags : clang-format SMTGSequencer
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// clang-format on
#import <UIKit/UIKit.h>
//------------------------------------------------------------------------
@interface VSTInterAppAudioHostUIControllerViewController : UIViewController
//------------------------------------------------------------------------
- (IBAction)hideView:(id)sender;
- (IBAction)switchToHost:(id)sender;
- (IBAction)play:(id)sender;
- (IBAction)rewind:(id)sender;
- (IBAction)record:(id)sender;
@end
@@ -0,0 +1,116 @@
// clang-format off
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/VSTInterAppAudioHostUIControllerViewController.mm
// Created by : Steinberg, 08/2013
// Description :
// Flags : clang-format SMTGSequencer
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
// clang-format on
#import "VSTInterAppAudioHostUIControllerViewController.h"
#import "public.sdk/source/vst/interappaudio/AudioIO.h"
using namespace Steinberg::Vst::InterAppAudio;
//------------------------------------------------------------------------
static UIImage* scaleImageToSize (UIImage* image, CGSize newSize)
{
UIGraphicsBeginImageContextWithOptions (newSize, NO, 0.0);
[image drawInRect:CGRectMake (0, 0, newSize.width, newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext ();
UIGraphicsEndImageContext ();
return newImage;
}
//------------------------------------------------------------------------
@interface VSTInterAppAudioHostUIControllerViewController ()
//------------------------------------------------------------------------
@property (assign) IBOutlet UIButton* hostButton;
@end
//------------------------------------------------------------------------
@implementation VSTInterAppAudioHostUIControllerViewController
//------------------------------------------------------------------------
//------------------------------------------------------------------------
- (id)init
{
self = [super initWithNibName:@"VSTInterAppAudioHostUIControllerView" bundle:nil];
if (self)
{
}
return self;
}
//------------------------------------------------------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage* image = AudioIO::instance ()->getHostIcon ();
if (image)
{
image = scaleImageToSize (image, self.hostButton.bounds.size);
[self.hostButton setTitle:@"" forState:UIControlStateNormal];
[self.hostButton setImage:image forState:UIControlStateNormal];
}
self.view.layer.shadowColor = [[UIColor blackColor] CGColor];
self.view.layer.shadowOpacity = 0.5;
self.view.layer.shadowRadius = 5;
self.view.layer.shadowOffset = CGSizeMake (5, -5);
}
//------------------------------------------------------------------------
- (IBAction)hideView:(id)sender
{
[UIView animateWithDuration:0.3
animations:^{
CGRect frame = self.view.frame;
frame.origin.y += frame.size.height;
self.view.frame = frame;
}
completion:^(BOOL finished) {
[self.view removeFromSuperview];
[self removeFromParentViewController];
}];
}
//------------------------------------------------------------------------
- (IBAction)switchToHost:(id)sender
{
AudioIO::instance ()->switchToHost ();
}
//------------------------------------------------------------------------
- (IBAction)play:(id)sender
{
AudioIO::instance ()->sendRemoteControlEvent (kAudioUnitRemoteControlEvent_TogglePlayPause);
}
//------------------------------------------------------------------------
- (IBAction)rewind:(id)sender
{
AudioIO::instance ()->sendRemoteControlEvent (kAudioUnitRemoteControlEvent_Rewind);
}
//------------------------------------------------------------------------
- (IBAction)record:(id)sender
{
AudioIO::instance ()->sendRemoteControlEvent (kAudioUnitRemoteControlEvent_ToggleRecord);
}
@end
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/interappaudio/InterAppAudioExample/main.m
// Created by : Steinberg, 08/2013
// Description :
//
//-----------------------------------------------------------------------------
// 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 <UIKit/UIKit.h>
#import "VSTInterAppAudioAppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain (argc, argv, nil, NSStringFromClass ([VSTInterAppAudioAppDelegate class]));
}
}
@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-adelay
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 ADelay example"
)
smtg_add_vst3plugin(adelay
source/adelaycontroller.cpp
source/adelaycontroller.h
source/adelayids.h
source/adelayprocessor.cpp
source/adelayprocessor.h
source/exampletest.cpp
source/factory.cpp
source/version.h
${SDK_ROOT}/public.sdk/source/vst/utility/test/ringbuffertest.cpp
${SDK_ROOT}/public.sdk/source/vst/utility/test/versionparsertest.cpp
)
smtg_target_setup_as_vst3_example(adelay)
@@ -0,0 +1,18 @@
# ADelay
## Introduction
**ADelay** is a simple FX plug-in with just one parameter for delay control.
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#adelay).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/adelaycontroller.cpp
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "adelaycontroller.h"
#include "adelayids.h"
#include "pluginterfaces/base/ibstream.h"
#if TARGET_OS_IPHONE
#include "interappaudio/iosEditor.h"
#endif
#include "base/source/fstreamer.h"
namespace Steinberg {
namespace Vst {
DEF_CLASS_IID (IDelayTestController)
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayController::initialize (FUnknown* context)
{
tresult result = EditController::initialize (context);
if (result == kResultTrue)
{
parameters.addParameter (STR16 ("Bypass"), nullptr, 1, 0, ParameterInfo::kCanAutomate|ParameterInfo::kIsBypass, kBypassId);
parameters.addParameter (STR16 ("Delay"), STR16 ("sec"), 0, 1, ParameterInfo::kCanAutomate, kDelayId);
}
return kResultTrue;
}
#if TARGET_OS_IPHONE
//-----------------------------------------------------------------------------
IPlugView* PLUGIN_API ADelayController::createView (FIDString name)
{
if (FIDStringsEqual (name, ViewType::kEditor))
{
return new ADelayEditorForIOS (this);
}
return 0;
}
#endif
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayController::setComponentState (IBStream* state)
{
// we receive the current state of the component (processor part)
// we read only the gain and bypass value...
if (!state)
return kResultFalse;
IBStreamer streamer (state, kLittleEndian);
float savedDelay = 0.f;
if (streamer.readFloat (savedDelay) == false)
return kResultFalse;
setParamNormalized (kDelayId, static_cast<ParamValue> (savedDelay));
int32 bypassState = 0;
if (streamer.readInt32 (bypassState) == false)
{
// could be an old version, continue
}
setParamNormalized (kBypassId, bypassState ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
bool PLUGIN_API ADelayController::doTest ()
{
// this is called when running thru the validator
// we can now run our own test cases
return true;
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,70 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/adelaycontroller.h
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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
#include "public.sdk/source/vst/vsteditcontroller.h"
#if SMTG_OS_MACOS
#include <TargetConditionals.h>
#endif
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
class IDelayTestController : public FUnknown
{
public:
virtual bool PLUGIN_API doTest () = 0;
//------------------------------------------------------------------------
static const FUID iid;
};
DECLARE_CLASS_IID (IDelayTestController, 0x9FC98F39, 0x27234512, 0x84FBC4AD, 0x618A14FD)
//-----------------------------------------------------------------------------
class ADelayController : public EditController, public IDelayTestController
{
public:
//------------------------------------------------------------------------
// create function required for plug-in factory,
// it will be called to create new instances of this controller
//------------------------------------------------------------------------
static FUnknown* createInstance (void*) { return (IEditController*)new ADelayController (); }
//---from IPluginBase--------
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
//---from EditController-----
#if TARGET_OS_IPHONE
IPlugView* PLUGIN_API createView (FIDString name) SMTG_OVERRIDE;
#endif
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
bool PLUGIN_API doTest () SMTG_OVERRIDE;
//---Interface---------
OBJ_METHODS (ADelayController, EditController)
DEFINE_INTERFACES
DEF_INTERFACE (IDelayTestController)
END_DEFINE_INTERFACES (EditController)
REFCOUNT_METHODS (EditController)
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/adelayids.h
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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
namespace Steinberg {
namespace Vst {
// parameter tags
enum {
kDelayId = 100,
kBypassId = 101
};
// unique class ids
static DECLARE_UID (ADelayProcessorUID, 0x0CDBB669, 0x85D548A9, 0xBFD83719, 0x09D24BB3);
static DECLARE_UID (ADelayControllerUID, 0x038E7FA9, 0x629A4EAA, 0x8541B889, 0x18E8952C);
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,226 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/adelayprocessor.cpp
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "adelayprocessor.h"
#include "adelayids.h"
#include "base/source/fstreamer.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include <algorithm>
#include <cstdlib>
namespace Steinberg {
namespace Vst {
//-----------------------------------------------------------------------------
ADelayProcessor::ADelayProcessor ()
{
setControllerClass (FUID::fromTUID (ADelayControllerUID));
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::initialize (FUnknown* context)
{
tresult result = AudioEffect::initialize (context);
if (result == kResultTrue)
{
addAudioInput (STR16 ("AudioInput"), SpeakerArr::kStereo);
addAudioOutput (STR16 ("AudioOutput"), SpeakerArr::kStereo);
mNumChannels = 2;
}
return result;
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs, int32 numOuts)
{
// we only support one in and output bus and these busses must have the same number of channels
if (numIns == 1 && numOuts == 1 && inputs[0] == outputs[0])
{
tresult res = AudioEffect::setBusArrangements (inputs, numIns, outputs, numOuts);
if (res == kResultOk)
mNumChannels = SpeakerArr::getChannelCount (outputs[0]);
return res;
}
return kResultFalse;
}
//-----------------------------------------------------------------------------
bool ADelayProcessor::resetDelay ()
{
if (!mBuffer)
return false;
size_t size = static_cast<size_t> (processSetup.sampleRate * sizeof (float) + 0.5);
for (int32 channel = 0; channel < mNumChannels; channel++)
{
if (mBuffer[channel])
memset (mBuffer[channel], 0, size);
}
mBufferPos = 0;
return true;
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::setActive (TBool state)
{
if (mBuffer)
{
for (int32 channel = 0; channel < mNumChannels; channel++)
{
std::free (mBuffer[channel]);
}
std::free (mBuffer);
mBuffer = nullptr;
}
if (state)
{
mBuffer = (float**)std::malloc (mNumChannels * sizeof (float*));
if (mBuffer)
{
size_t size = static_cast<size_t> (processSetup.sampleRate * sizeof (float) + 0.5);
for (int32 channel = 0; channel < mNumChannels; channel++)
{
mBuffer[channel] = (float*)std::malloc (size); // 1 second delay max
}
resetDelay ();
}
}
return AudioEffect::setActive (state);
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::setProcessing (TBool state)
{
if (state)
{
resetDelay ();
}
return kResultOk;
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::process (ProcessData& data)
{
if (data.inputParameterChanges)
{
int32 numParamsChanged = data.inputParameterChanges->getParameterCount ();
for (int32 index = 0; index < numParamsChanged; index++)
{
if (IParamValueQueue* paramQueue = data.inputParameterChanges->getParameterData (index))
{
ParamValue value;
int32 sampleOffset;
int32 numPoints = paramQueue->getPointCount ();
switch (paramQueue->getParameterId ())
{
case kDelayId:
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) ==
kResultTrue)
mDelay = value;
break;
case kBypassId:
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) ==
kResultTrue)
{
mBypass = (value > 0.5f);
}
break;
}
}
}
}
if (data.numSamples > 0)
{
SpeakerArrangement arr;
getBusArrangement (kOutput, 0, arr);
int32 numChannels = SpeakerArr::getChannelCount (arr);
// TODO do something in Bypass : copy input to output if necessary...
// you could use a BypassProcessor which is used in the SyncDelay example
// apply delay
// we have a minimum of 1 sample delay here
int32 delayInSamples = std::max<int32> (1, (int32) (mDelay * processSetup.sampleRate));
for (int32 channel = 0; channel < numChannels; channel++)
{
float* inputChannel = data.inputs[0].channelBuffers32[channel];
float* outputChannel = data.outputs[0].channelBuffers32[channel];
int32 tempBufferPos = mBufferPos;
for (int32 sample = 0; sample < data.numSamples; sample++)
{
float tempSample = inputChannel[sample];
outputChannel[sample] = mBuffer[channel][tempBufferPos];
mBuffer[channel][tempBufferPos] = tempSample;
tempBufferPos++;
if (tempBufferPos >= delayInSamples)
tempBufferPos = 0;
}
}
mBufferPos += data.numSamples;
while (delayInSamples && mBufferPos >= delayInSamples)
mBufferPos -= delayInSamples;
}
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::setState (IBStream* state)
{
if (!state)
return kResultFalse;
// called when we load a preset, the model has to be reloaded
IBStreamer streamer (state, kLittleEndian);
float savedDelay = 0.f;
if (streamer.readFloat (savedDelay) == false)
return kResultFalse;
int32 savedBypass = 0;
if (streamer.readInt32 (savedBypass) == false)
{
// could be an old version, continue
}
mDelay = static_cast<ParamValue> (savedDelay);
mBypass = savedBypass > 0;
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayProcessor::getState (IBStream* state)
{
// here we need to save the model
IBStreamer streamer (state, kLittleEndian);
streamer.writeFloat (static_cast<float> (mDelay));
streamer.writeInt32 (mBypass ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/adelayprocessor.cpp
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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
#include "public.sdk/source/vst/vstaudioeffect.h"
namespace Steinberg {
namespace Vst {
//-----------------------------------------------------------------------------
class ADelayProcessor : public AudioEffect
{
public:
ADelayProcessor ();
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
tresult PLUGIN_API setActive (TBool state) SMTG_OVERRIDE;
tresult PLUGIN_API setProcessing (TBool state) SMTG_OVERRIDE;
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
//------------------------------------------------------------------------
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
static FUnknown* createInstance (void*) { return (IAudioProcessor*)new ADelayProcessor (); }
protected:
bool resetDelay ();
ParamValue mDelay {1.};
float** mBuffer {nullptr};
int32 mBufferPos {0};
int32 mNumChannels {0};
bool mBypass {false};
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/exampletest.cpp
// Created by : Steinberg, 10/2010
// Description :
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "adelaycontroller.h"
#include "adelayprocessor.h"
#include "base/source/fstring.h"
#include "public.sdk/source/main/moduleinit.h"
#include "public.sdk/source/vst/testsuite/vsttestsuite.h"
#include "public.sdk/source/vst/utility/testing.h"
#include "pluginterfaces/base/funknownimpl.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
static ModuleInitializer InitTests ([] () {
registerTest ("ExampleTest", nullptr, [] (FUnknown* context, ITestResult* testResult) {
auto plugProvider = U::cast<ITestPlugProvider> (context);
if (plugProvider)
{
auto controller = plugProvider->getController ();
auto testController = U::cast<IDelayTestController> (controller);
if (!controller)
{
testResult->addErrorMessage (String ("Unknown IEditController"));
return false;
}
bool result = testController->doTest ();
plugProvider->releasePlugIn (nullptr, controller);
return (result);
}
return false;
});
});
//------------------------------------------------------------------------
}} // namespaces
@@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/factory.cpp
// Created by : Steinberg, 06/2009
// Description :
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "adelaycontroller.h"
#include "adelayids.h"
#include "adelayprocessor.h"
#include "version.h" // for versioning
#include "public.sdk/source/main/pluginfactory_constexpr.h"
#include "public.sdk/source/vst/utility/testing.h"
#define stringPluginName "ADelay"
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail, 3)
DEF_CLASS (Steinberg::Vst::ADelayProcessorUID, Steinberg::PClassInfo::kManyInstances,
kVstAudioEffectClass,
stringPluginName,
Steinberg::Vst::kDistributable,
"Fx|Delay",
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString,
Steinberg::Vst::ADelayProcessor::createInstance,
nullptr)
DEF_CLASS (Steinberg::Vst::ADelayControllerUID, Steinberg::PClassInfo::kManyInstances,
kVstComponentControllerClass,
stringPluginName "Controller", // controller name (can be the same as the component name)
0, // not used here
"", // not used here
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString,
Steinberg::Vst::ADelayController::createInstance,
nullptr)
// add Test Factory
DEF_CLASS (Steinberg::Vst::TestFactoryUID,
Steinberg::PClassInfo::kManyInstances,
kTestClass,
stringPluginName "Test Factory",
0,
"",
"",
"",
Steinberg::Vst::createTestFactoryInstance,
nullptr)
END_FACTORY
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="3.0" toolsVersion="4488.2" systemVersion="12E55" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3715.3"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ADelayViewController">
<connections>
<outlet property="slider" destination="8qe-I8-OQ4" id="zbQ-xw-Cls"/>
<outlet property="view" destination="1" id="cvV-er-vQe"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="1">
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<slider opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="8qe-I8-OQ4">
<rect key="frame" x="146" y="370" width="777" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<connections>
<action selector="sliderChanged:" destination="-1" eventType="valueChanged" id="dXh-wG-NCY"/>
</connections>
</slider>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="blackOpaque"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
</view>
</objects>
</document>
@@ -0,0 +1,85 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/interappaudio/iosEditor.h
// Created by : Steinberg, 08/2013
// Description :
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Steinberg Media Technologies nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#ifndef __iosEditor__
#define __iosEditor__
#include "base/source/fobject.h"
#include "pluginterfaces/gui/iplugview.h"
#if __OBJC__
@class ADelayViewController;
#else
struct ADelayViewController;
#endif
namespace Steinberg {
namespace Vst {
class EditController;
class ADelayEditorForIOS : public FObject, public IPlugView
{
public:
ADelayEditorForIOS (EditController* editController);
OBJ_METHODS(ADelayEditorForIOS, FObject)
REFCOUNT_METHODS(FObject)
DEFINE_INTERFACES
DEF_INTERFACE(IPlugView)
END_DEFINE_INTERFACES(FObject)
protected:
tresult PLUGIN_API isPlatformTypeSupported (FIDString type) override;
tresult PLUGIN_API attached (void* parent, FIDString type) override;
tresult PLUGIN_API removed () override;
tresult PLUGIN_API onWheel (float distance) override;
tresult PLUGIN_API onKeyDown (char16 key, int16 keyCode, int16 modifiers) override;
tresult PLUGIN_API onKeyUp (char16 key, int16 keyCode, int16 modifiers) override;
tresult PLUGIN_API getSize (ViewRect* size) override;
tresult PLUGIN_API onSize (ViewRect* newSize) override;
tresult PLUGIN_API onFocus (TBool state) override;
tresult PLUGIN_API setFrame (IPlugFrame* frame) override;
tresult PLUGIN_API canResize () override;
tresult PLUGIN_API checkSizeConstraint (ViewRect* rect) override;
void PLUGIN_API update (FUnknown* changedUnknown, int32 message) override;
EditController* editController;
ADelayViewController* viewController;
};
}}
#endif // __iosEditor__
@@ -0,0 +1,203 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/interappaudio/iosEditor.mm
// Created by : Steinberg, 08/2013
// Description :
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Steinberg Media Technologies nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#import "iosEditor.h"
#import "public.sdk/source/vst/vsteditcontroller.h"
#import "adelayids.h"
using namespace Steinberg::Vst;
//------------------------------------------------------------------------
@interface ADelayViewController : UIViewController
{
EditController* editController;
}
@property (assign) IBOutlet UISlider* slider;
@end
//------------------------------------------------------------------------
@implementation ADelayViewController
//------------------------------------------------------------------------
- (id)initWithVstEditController:(EditController*)_editController
{
self = [super initWithNibName:@"ADelayIPAD" bundle:nil];
if (self)
{
editController = _editController;
}
return self;
}
//------------------------------------------------------------------------
- (void)updateSlider
{
[self.slider setValue:editController->getParamNormalized (kDelayId)];
}
//------------------------------------------------------------------------
- (IBAction)sliderChanged:(id)sender
{
editController->setParamNormalized (kDelayId, self.slider.value);
editController->performEdit(kDelayId, self.slider.value);
}
@end
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
ADelayEditorForIOS::ADelayEditorForIOS (EditController* editController)
: editController (editController)
, viewController (nil)
{
}
//------------------------------------------------------------------------
void PLUGIN_API ADelayEditorForIOS::update (FUnknown* changedUnknown, int32 message)
{
Parameter* param = FCast<Parameter> (changedUnknown);
if (param && viewController)
{
[viewController updateSlider];
}
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::isPlatformTypeSupported (FIDString type)
{
if (strcmp (type, kPlatformTypeUIView) == 0)
return kResultTrue;
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::attached (void* parent, FIDString type)
{
if (strcmp (type, kPlatformTypeUIView) != 0)
return kResultFalse;
UIView* parentView = (__bridge UIView*)parent;
viewController = [[ADelayViewController alloc] initWithVstEditController:editController];
if (viewController && viewController.view)
{
[parentView addSubview:viewController.view];
[viewController updateSlider];
Parameter* delayParam = editController->getParameterObject (kDelayId);
if (delayParam)
{
delayParam->addDependent (this);
}
}
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::removed ()
{
[viewController.view removeFromSuperview];
Parameter* delayParam = editController->getParameterObject (kDelayId);
if (delayParam)
{
delayParam->removeDependent (this);
}
viewController = nil;
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::onWheel (float distance)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::onKeyDown (char16 key, int16 keyCode, int16 modifiers)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::onKeyUp (char16 key, int16 keyCode, int16 modifiers)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::getSize (ViewRect* size)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::onSize (ViewRect* newSize)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::onFocus (TBool state)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::setFrame (IPlugFrame* frame)
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::canResize ()
{
return kNotImplemented;
}
//------------------------------------------------------------------------
tresult PLUGIN_API ADelayEditorForIOS::checkSizeConstraint (ViewRect* rect)
{
return kNotImplemented;
}
}}
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/adelay/source/version.h
// Created by : Steinberg, 06/2009
// Description : Example of handle the versioning and copyright info of adelay plugin
// used for the resources (RC file for example)
//
//-----------------------------------------------------------------------------
// 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
#include "pluginterfaces/base/fplatform.h"
// Plain project version file generated by cmake
#include "projectversion.h"
#define stringOriginalFilename "adelay.vst3"
#if SMTG_PLATFORM_64
#define stringFileDescription "ADelay VST3-SDK (64Bit)"
#else
#define stringFileDescription "ADelay VST3-SDK"
#endif
#define stringCompanyWeb "http://www.steinberg.net"
#define stringCompanyEmail "mailto:info@steinberg.de"
#define stringCompanyName "Steinberg Media Technologies"
#define stringLegalCopyright "© 2025 Steinberg Media Technologies"
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"
@@ -0,0 +1,192 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-again
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 AGain example"
)
if(NOT SMTG_ENABLE_VSTGUI_SUPPORT)
return()
endif()
set(again_sources
source/again.cpp
source/again.h
source/againcids.h
source/againcontroller.cpp
source/againcontroller.h
source/againentry.cpp
source/againparamids.h
source/againprocess.h
source/againsidechain.cpp
source/againsidechain.h
source/againuimessagecontroller.h
source/version.h
resource/again.uidesc
)
set(again_simple_sources
${SDK_ROOT}/public.sdk/source/vst/vstsinglecomponenteffect.cpp
${SDK_ROOT}/public.sdk/source/vst/vstsinglecomponenteffect.h
source/againparamids.h
source/againsimple.cpp
source/againsimple.h
source/version.h
)
set(target again)
smtg_add_vst3plugin(${target} ${again_sources})
smtg_target_configure_version_file(${target})
#smtg_add_vst3plugin(${target} PACKAGE_NAME "A Gain" SOURCES_LIST ${again_sources})
set_target_properties(${target}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}
)
target_compile_features(${target}
PUBLIC
cxx_std_17
)
target_link_libraries(${target}
PRIVATE
sdk
vstgui_support
)
smtg_target_add_plugin_resources(${target}
RESOURCES
resource/again.uidesc
resource/background.png
resource/slider_background.png
resource/slider_handle.png
resource/slider_handle_2.0x.png
resource/vu_on.png
resource/vu_off.png
)
smtg_target_add_plugin_snapshots (${target}
RESOURCES
resource/84E8DE5F92554F5396FAE4133C935A18_snapshot.png
resource/84E8DE5F92554F5396FAE4133C935A18_snapshot_2.0x.png
resource/41347FD6FED64094AFBB12B7DBA1D441_snapshot.png
resource/41347FD6FED64094AFBB12B7DBA1D441_snapshot_2.0x.png
)
if(SMTG_MAC)
smtg_target_set_bundle(${target}
BUNDLE_IDENTIFIER "com.steinberg.vst3.${target}"
COMPANY_NAME "Steinberg Media Technologies"
)
elseif(SMTG_WIN)
target_sources(${target}
PRIVATE
resource/again.rc
)
endif(SMTG_MAC)
# Add an AUv2 target
if (SMTG_MAC AND XCODE AND SMTG_ENABLE_AUV2_BUILDS)
include(SMTG_AddVST3AuV2)
smtg_target_add_auv2(again-au
BUNDLE_NAME again
BUNDLE_IDENTIFIER com.steinberg.vst3plugin.again.audiounit
INFO_PLIST_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/resource/au-info.plist
VST3_PLUGIN_TARGET again)
endif(SMTG_MAC AND XCODE AND SMTG_ENABLE_AUV2_BUILDS)
if(SMTG_MAC AND XCODE AND SMTG_ENABLE_IOS_TARGETS)
set(target again_ios)
smtg_add_ios_vst3plugin(${target} "${SMTG_CODE_SIGN_IDENTITY_IOS}" "${target}" "${again_sources}")
smtg_target_configure_version_file(${target})
set_target_properties(${target}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}
)
target_include_directories(${target}
PUBLIC
${SMTG_VSTGUI_SOURCE_DIR}
)
target_link_libraries(${target}
PRIVATE
base_ios
sdk_ios
"-framework UIKit"
"-framework CoreGraphics"
"-framework QuartzCore"
"-framework CoreText"
"-framework Accelerate"
"-framework ImageIO"
"-framework MobileCoreServices"
)
smtg_target_add_plugin_resources(${target}
RESOURCES
resource/again.uidesc
resource/background.png
resource/slider_background.png
resource/slider_handle.png
resource/slider_handle_2.0x.png
resource/vu_on.png
resource/vu_off.png
)
smtg_target_set_bundle(${target}
BUNDLE_IDENTIFIER "com.steinberg.vst3.again"
COMPANY_NAME "Steinberg Media Technologies"
)
target_sources(${target}
PRIVATE
${SMTG_VSTGUI_SOURCE_DIR}/vstgui/vstgui_uidescription.cpp
${SMTG_VSTGUI_SOURCE_DIR}/vstgui/vstgui_ios.mm
${SMTG_VSTGUI_SOURCE_DIR}/vstgui/plugin-bindings/vst3editor.cpp
${SDK_ROOT}/public.sdk/source/vst/vstguieditor.cpp
)
target_compile_features(${target}
PUBLIC
cxx_std_17
)
endif(SMTG_MAC AND XCODE AND SMTG_ENABLE_IOS_TARGETS)
set(targetsimple again-simple)
smtg_add_vst3plugin(${targetsimple} ${again_simple_sources})
smtg_target_configure_version_file(${targetsimple})
set_target_properties(${targetsimple}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER})
target_link_libraries(${targetsimple}
PUBLIC
sdk
vstgui_support
)
smtg_target_add_plugin_resources(${targetsimple}
RESOURCES
resource/again.uidesc
resource/background.png
resource/slider_background.png
resource/slider_handle.png
resource/slider_handle_2.0x.png
resource/vu_on.png
resource/vu_off.png
)
target_compile_features(${targetsimple}
PUBLIC
cxx_std_17
)
if(SMTG_MAC)
smtg_target_set_bundle(${targetsimple}
BUNDLE_IDENTIFIER "com.steinberg.vst3.again-simple"
COMPANY_NAME "Steinberg Media Technologies"
)
elseif(SMTG_WIN)
target_sources(${targetsimple}
PRIVATE
resource/again.rc
)
endif(SMTG_MAC)
@@ -0,0 +1,25 @@
# AGain VST 3
## Introduction
AGain VST 3 is the most simple FX plug-in with just one parameter for gain control.
There are several targets to show how the AGain plug-in can be built for different use cases.
* AGain VST 3
* AGain VST 3 Simple (SingleComponent approach)
* AGain AU (Audio Unit)
* AGain iOS
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#again).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 Steinberg Media Technologies. All rights reserved.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<vstgui-ui-description version="1">
<fonts>
</fonts>
<colors>
<color name="Focus" rgba="#279bffff"/>
<color name="Title Background" rgba="#39393944"/>
</colors>
<template background-color="~ BlackCColor" background-color-draw-style="filled and stroked" bitmap="background" class="CViewContainer" maxSize="350, 120" minSize="350, 120" mouse-enabled="true" name="view" opacity="1" origin="0, 0" size="350, 120" transparent="false">
<view back-color="Title Background" background-offset="0, 0" class="CTextLabel" default-value="0.5" font="~ NormalFontVeryBig" font-antialias="true" font-color="~ WhiteCColor" frame-color="Title Background" frame-width="1" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="10, 10" round-rect-radius="10" shadow-color="~ RedCColor" size="310, 28" style-3D-in="false" style-3D-out="false" style-no-draw="false" style-no-frame="false" style-no-text="false" style-round-rect="true" style-shadow-text="false" text-alignment="center" text-inset="0, 0" text-rotation="0" title="VST3 AGain" transparent="false" value-precision="2" wheel-inc-value="0.1"/>
<view background-color="~ BlackCColor" background-color-draw-style="filled and stroked" class="CViewContainer" mouse-enabled="true" opacity="1" origin="0, 45" size="330, 38" sub-controller="MessageController" transparent="true">
<view back-color="~ BlackCColor" background-offset="0, 0" class="CTextLabel" default-value="0.5" font="~ NormalFont" font-antialias="true" font-color="~ WhiteCColor" frame-color="~ BlackCColor" frame-width="1" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="10, 10" round-rect-radius="6" shadow-color="~ BlackCColor" size="80, 18" style-3D-in="false" style-3D-out="false" style-no-draw="false" style-no-frame="false" style-no-text="false" style-round-rect="false" style-shadow-text="true" text-alignment="left" text-inset="5, 0" text-rotation="0" title="IMessage:" transparent="true" value-precision="2" wheel-inc-value="0.1"/>
<view back-color="~ BlackCColor" background-offset="0, 0" class="CTextEdit" default-value="0.5" font="~ NormalFontSmall" font-antialias="true" font-color="~ WhiteCColor" frame-color="~ GreyCColor" frame-width="1" immediate-text-change="false" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="90, 10" round-rect-radius="6" shadow-color="~ RedCColor" size="130, 18" style-3D-in="false" style-3D-out="false" style-doubleclick="false" style-no-draw="false" style-no-frame="false" style-no-text="false" style-round-rect="false" style-shadow-text="false" text-alignment="center" text-inset="0, 0" text-rotation="0" transparent="false" value-precision="2" wheel-inc-value="0.1"/>
<view background-offset="0, 0" class="CTextButton" control-tag="UI::SendMessage" default-value="0.5" font="~ SystemFont" frame-color="~ BlackCColor" frame-color-highlighted="~ BlackCColor" frame-width="1" gradient="Default TextButton Gradient" gradient-highlighted="Default TextButton Gradient Highlighted" icon-position="left" icon-text-margin="0" kick-style="false" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="230, 10" round-radius="6" size="90, 18" text-alignment="center" text-color="~ BlackCColor" text-color-highlighted="~ WhiteCColor" title="Send!" transparent="false" wheel-inc-value="0.1"/>
</view>
<view back-color="~ BlackCColor" background-offset="0, 0" class="CTextLabel" default-value="0.5" font="~ NormalFont" font-antialias="true" font-color="~ WhiteCColor" frame-color="~ BlackCColor" frame-width="1" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="10, 90" round-rect-radius="6" shadow-color="~ BlackCColor" size="80, 18" style-3D-in="false" style-3D-out="false" style-no-draw="false" style-no-frame="false" style-no-text="false" style-round-rect="false" style-shadow-text="true" text-alignment="left" text-inset="5, 0" text-rotation="0" title="Gain:" transparent="true" value-precision="2" wheel-inc-value="0.1"/>
<view background-offset="0, 0" bitmap="slider_background" bitmap-offset="0, 0" class="CSlider" control-tag="Unit1::Gain" default-value="0.5" draw-back="false" draw-back-color="~ WhiteCColor" draw-frame="false" draw-frame-color="~ WhiteCColor" draw-value="false" draw-value-color="~ WhiteCColor" draw-value-from-center="false" draw-value-inverted="false" handle-bitmap="slider_handle" handle-offset="0, 2" max-value="1" min-value="0" mode="free click" mouse-enabled="true" opacity="1" orientation="horizontal" origin="90, 90" reverse-orientation="false" size="130, 18" transparent="false" transparent-handle="true" wheel-inc-value="0.1" zoom-factor="10"/>
<view back-color="~ BlackCColor" background-offset="0, 0" class="CTextEdit" control-tag="Unit1::Gain" default-value="0.5" font="~ NormalFontSmall" font-antialias="true" font-color="~ WhiteCColor" frame-color="~ GreyCColor" frame-width="1" immediate-text-change="false" max-value="1" min-value="0" mouse-enabled="true" opacity="1" origin="230, 90" round-rect-radius="6" shadow-color="~ BlackCColor" size="90, 18" style-3D-in="false" style-3D-out="false" style-doubleclick="false" style-no-draw="false" style-no-frame="false" style-no-text="false" style-round-rect="true" style-shadow-text="false" text-alignment="center" text-inset="5, 0" text-rotation="0" title="0.00" transparent="false" value-precision="2" wheel-inc-value="0.1"/>
<view background-offset="0, 0" bitmap="vu_on" class="CVuMeter" control-tag="Root::VuPPM" decrease-step-value="0.1" default-value="0" max-value="1" min-value="0" mouse-enabled="false" num-led="100" off-bitmap="vu_off" opacity="1" orientation="vertical" origin="330, 7" size="12, 105" transparent="false" wheel-inc-value="0.1"/>
</template>
<variables/>
<custom>
<attributes color="Focus" enabled="true" name="FocusDrawing" width="1"/>
<attributes Size="5, 5" name="UIGridController"/>
<attributes SelectedTemplate="view" name="UITemplateController"/>
<attributes EditViewScale="1" EditorSize="0, 0, 882, 716" SplitViewSize_0_0="0.6402877697841726778449356061173602938652" SplitViewSize_0_1="0.3309352517985611474848894886235939338803" SplitViewSize_1_0="0.506474820143884896239683257590513676405" SplitViewSize_1_1="0.486330935251798546214985208280268125236" SplitViewSize_2_0="0.636054421768707523021646466077072545886" SplitViewSize_2_1="0.3582766439909297329080573035753332078457" TabSwitchValue="0" Version="1" name="UIEditController"/>
<attributes name="UIAttributesController"/>
<attributes SelectedRow="23" name="UIViewCreatorDataSource"/>
<attributes SelectedRow="4" name="UIBitmapsDataSource"/>
<attributes Path="/Volumes/git_brauhaus/VST3Linux/public.sdk/samples/vst/again/resource/again.uidesc" name="VST3Editor"/>
<attributes SelectedRow="2" name="UITagsDataSource"/>
<attributes SelectedRow="0" name="UIColorsDataSource"/>
<attributes SelectedRow="-1" name="UIGradientsDataSource"/>
<attributes SelectedRow="-1" name="UIFontsDataSource"/>
</custom>
<bitmaps>
<bitmap name="background" path="background.png"/>
<bitmap name="slider_background" path="slider_background.png"/>
<bitmap name="slider_handle" path="slider_handle.png"/>
<bitmap name="slider_handle#2x" path="slider_handle_2.0x.png" scale-factor="2"/>
<bitmap name="vu_off" path="vu_off.png"/>
<bitmap name="vu_on" path="vu_on.png"/>
</bitmaps>
<control-tags>
<control-tag name="Root::Bypass" tag="2"/>
<control-tag name="Root::VuPPM" tag="1"/>
<control-tag name="UI::SendMessage" tag="1000"/>
<control-tag name="Unit1::Gain" tag="0"/>
</control-tags>
<gradients>
<gradient name="Default TextButton Gradient">
<color-stop rgba="#dcdcdcff" start="0"/>
<color-stop rgba="#b4b4b4ff" start="1"/>
</gradient>
<gradient name="Default TextButton Gradient Highlighted">
<color-stop rgba="#b4b4b4ff" start="0"/>
<color-stop rgba="#646464ff" start="1"/>
</gradient>
</gradients>
</vstgui-ui-description>
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>AudioComponents</key>
<array>
<dict>
<key>factoryFunction</key>
<string>AUWrapperFactory</string>
<key>description</key>
<string>AGain</string>
<key>manufacturer</key>
<string>Stgb</string>
<key>name</key>
<string>Steinberg: AGain</string>
<key>subtype</key>
<string>gain</string>
<key>type</key>
<string>aufx</string>
<key>version</key>
<integer>0xFFFFFFFF</integer>
</dict>
</array>
<key>AudioUnit SupportedNumChannels</key>
<array>
<dict>
<key>Outputs</key>
<string>2</string>
<key>Inputs</key>
<string>2</string>
</dict>
<dict>
<key>Outputs</key>
<string>0</string>
<key>Inputs</key>
<string>1</string>
</dict>
<dict>
<key>Outputs</key>
<string>1</string>
<key>Inputs</key>
<string>1</string>
</dict>
</array>
</dict>
</plist>
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

@@ -0,0 +1,471 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/again.cpp
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST SDK 3
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "again.h"
#include "againcids.h" // for class ids
#include "againparamids.h"
#include "againprocess.h"
#include "public.sdk/source/vst/vstaudioprocessoralgo.h"
#include "public.sdk/source/vst/vsthelpers.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include "pluginterfaces/vst/vstpresetkeys.h" // for use of IStreamAttributes
#include "base/source/fstreamer.h"
#include <cstdio>
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// AGain Implementation
//------------------------------------------------------------------------
AGain::AGain ()
{
// register its editor class (the same than used in againentry.cpp)
setControllerClass (AGainControllerUID);
}
//------------------------------------------------------------------------
AGain::~AGain ()
{
// nothing to do here yet..
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::initialize (FUnknown* context)
{
//---always initialize the parent-------
tresult result = AudioEffect::initialize (context);
// if everything Ok, continue
if (result != kResultOk)
{
return result;
}
//---create Audio In/Out busses------
// we want a stereo Input and a Stereo Output
addAudioInput (STR16 ("Stereo In"), SpeakerArr::kStereo);
addAudioOutput (STR16 ("Stereo Out"), SpeakerArr::kStereo);
//---create Event In/Out busses (1 bus with only 1 channel)------
addEventInput (STR16 ("Event In"), 1);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::terminate ()
{
// nothing to do here yet...except calling our parent terminate
return AudioEffect::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::setActive (TBool state)
{
if (state)
{
sendTextMessage ("AGain::setActive (true)");
}
else
{
sendTextMessage ("AGain::setActive (false)");
}
// reset the VuMeter value
fVuPPMOld = 0.f;
// call our parent setActive
return AudioEffect::setActive (state);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::process (ProcessData& data)
{
// finally the process function
// In this example there are 4 steps:
// 1) Read inputs parameters coming from host (in order to adapt our model values)
// 2) Read inputs events coming from host (we apply a gain reduction depending of the velocity
// of pressed key) 3) Process the gain of the input buffer to the output buffer 4) Write the new
// VUmeter value to the output Parameters queue
//---1) Read inputs parameter changes-----------
if (IParameterChanges* paramChanges = data.inputParameterChanges)
{
int32 numParamsChanged = paramChanges->getParameterCount ();
// for each parameter which are some changes in this audio block:
for (int32 i = 0; i < numParamsChanged; i++)
{
if (IParamValueQueue* paramQueue = paramChanges->getParameterData (i))
{
ParamValue value;
int32 sampleOffset;
int32 numPoints = paramQueue->getPointCount ();
switch (paramQueue->getParameterId ())
{
case kGainId:
// we use in this example only the last point of the queue.
// in some wanted case for specific kind of parameter it makes sense to
// retrieve all points and process the whole audio block in small blocks.
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) ==
kResultTrue)
{
fGain = (float)value;
}
break;
case kBypassId:
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) ==
kResultTrue)
{
bBypass = (value > 0.5f);
}
break;
}
}
}
}
//---2) Read input events-------------
if (IEventList* eventList = data.inputEvents)
{
int32 numEvent = eventList->getEventCount ();
for (int32 i = 0; i < numEvent; i++)
{
Event event {};
if (eventList->getEvent (i, event) == kResultOk)
{
switch (event.type)
{
//--- -------------------
case Event::kNoteOnEvent:
// use the velocity as gain modifier
fGainReduction = event.noteOn.velocity;
break;
//--- -------------------
case Event::kNoteOffEvent:
// noteOff reset the reduction
fGainReduction = 0.f;
break;
}
}
}
}
//--- ----------------------------------
//---3) Process Audio---------------------
//--- ----------------------------------
if (data.numInputs == 0 || data.numOutputs == 0)
{
// nothing to do
return kResultOk;
}
// (simplification) we suppose in this example that we have the same input channel count than
// the output
int32 numChannels = data.inputs[0].numChannels;
//---get audio buffers----------------
uint32 sampleFramesSize = getSampleFramesSizeInBytes (processSetup, data.numSamples);
void** in = getChannelBuffersPointer (processSetup, data.inputs[0]);
void** out = getChannelBuffersPointer (processSetup, data.outputs[0]);
float fVuPPM = 0.f;
//---check if silence---------------
// check if all channel are silent then process silent
if (data.inputs[0].silenceFlags == getChannelMask (data.inputs[0].numChannels))
{
// mark output silence too (it will help the host to propagate the silence)
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
// the plug-in has to be sure that if it sets the flags silence that the output buffer are
// clear
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be cleared if the buffers are the same (in this case input buffer are
// already cleared by the host)
if (in[i] != out[i])
{
memset (out[i], 0, sampleFramesSize);
}
}
fVuPPM = 0.f;
}
else // we have to process (no silence)
{
// mark our outputs has not silent
data.outputs[0].silenceFlags = 0;
//---in bypass mode outputs should be like inputs-----
if (bBypass)
{
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be copied if the buffers are the same
if (in[i] != out[i])
{
memcpy (out[i], in[i], sampleFramesSize);
}
}
if (data.symbolicSampleSize == kSample32)
fVuPPM = processVuPPM<Sample32> ((Sample32**)in, numChannels, data.numSamples);
else
fVuPPM = static_cast<float> (
processVuPPM<Sample64> ((Sample64**)(in), numChannels, data.numSamples));
}
else
{
//---apply gain factor----------
float gain = (fGain - fGainReduction);
if (bHalfGain)
{
gain = gain * 0.5f;
}
// if the applied gain is nearly zero, we could say that the outputs are zeroed and we set
// the silence flags.
if (gain < 0.0000001)
{
for (int32 i = 0; i < numChannels; i++)
{
memset (out[i], 0, sampleFramesSize);
}
// this will set to 1 all channels
data.outputs[0].silenceFlags = getChannelMask (data.outputs[0].numChannels);
}
else
{
if (data.symbolicSampleSize == kSample32)
fVuPPM = processAudio<Sample32> ((Sample32**)in, (Sample32**)out, numChannels,
data.numSamples, gain);
else
fVuPPM = static_cast<float> (processAudio<Sample64> (
(Sample64**)in, (Sample64**)out, numChannels, data.numSamples, gain));
}
}
}
//---3) Write outputs parameter changes-----------
IParameterChanges* outParamChanges = data.outputParameterChanges;
// a new value of VuMeter will be send to the host
// (the host will send it back in sync to our controller for updating our editor)
if (outParamChanges && fVuPPMOld != fVuPPM)
{
int32 index = 0;
IParamValueQueue* paramQueue = outParamChanges->addParameterData (kVuPPMId, index);
if (paramQueue)
{
int32 index2 = 0;
paramQueue->addPoint (0, fVuPPM, index2);
}
}
fVuPPMOld = fVuPPM;
return kResultOk;
}
//------------------------------------------------------------------------
tresult AGain::receiveText (const char* text)
{
// received from Controller
fprintf (stderr, "[AGain] received: ");
fprintf (stderr, "%s", text);
fprintf (stderr, "\n");
bHalfGain = !bHalfGain;
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::setState (IBStream* state)
{
// called when we load a preset, the model has to be reloaded
IBStreamer streamer (state, kLittleEndian);
float savedGain = 0.f;
if (streamer.readFloat (savedGain) == false)
return kResultFalse;
float savedGainReduction = 0.f;
if (streamer.readFloat (savedGainReduction) == false)
return kResultFalse;
int32 savedBypass = 0;
if (streamer.readInt32 (savedBypass) == false)
return kResultFalse;
fGain = savedGain;
fGainReduction = savedGainReduction;
bBypass = savedBypass > 0;
if (Helpers::isProjectState (state) == kResultTrue)
{
// we are in project loading context...
// Example of using the IStreamAttributes interface
if (auto stream = U::cast<IStreamAttributes> (state))
{
if (IAttributeList* list = stream->getAttributes ())
{
// get the full file path of this state
TChar fullPath[1024];
memset (fullPath, 0, 1024 * sizeof (TChar));
if (list->getString (PresetAttributes::kFilePathStringType, fullPath,
1024 * sizeof (TChar)) == kResultTrue)
{
// here we have the full path ...
}
}
}
}
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::getState (IBStream* state)
{
// here we need to save the model
IBStreamer streamer (state, kLittleEndian);
streamer.writeFloat (fGain);
streamer.writeFloat (fGainReduction);
streamer.writeInt32 (bBypass ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::setupProcessing (ProcessSetup& newSetup)
{
// called before the process call, always in a disable state (not active)
// here we keep a trace of the processing mode (offline,...) for example.
currentProcessMode = newSetup.processMode;
return AudioEffect::setupProcessing (newSetup);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs, int32 numOuts)
{
if (numIns == 1 && numOuts == 1)
{
// the host wants Mono => Mono (or 1 channel -> 1 channel)
if (SpeakerArr::getChannelCount (inputs[0]) == 1 &&
SpeakerArr::getChannelCount (outputs[0]) == 1)
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
// check if we are Mono => Mono, if not we need to recreate the busses
if (bus->getArrangement () != inputs[0])
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioInput (0)->setName (STR16 ("Mono In"));
getAudioOutput (0)->setArrangement (outputs[0]);
getAudioOutput (0)->setName (STR16 ("Mono Out"));
}
return kResultOk;
}
}
// the host wants something else than Mono => Mono,
// in this case we are always Stereo => Stereo
else
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
tresult result = kResultFalse;
// the host wants 2->2 (could be LsRs -> LsRs)
if (SpeakerArr::getChannelCount (inputs[0]) == 2 &&
SpeakerArr::getChannelCount (outputs[0]) == 2)
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioInput (0)->setName (STR16 ("Stereo In"));
getAudioOutput (0)->setArrangement (outputs[0]);
getAudioOutput (0)->setName (STR16 ("Stereo Out"));
result = kResultTrue;
}
// the host want something different than 1->1 or 2->2 : in this case we want stereo
else if (bus->getArrangement () != SpeakerArr::kStereo)
{
getAudioInput (0)->setArrangement (SpeakerArr::kStereo);
getAudioInput (0)->setName (STR16 ("Stereo In"));
getAudioOutput (0)->setArrangement (SpeakerArr::kStereo);
getAudioOutput (0)->setName (STR16 ("Stereo Out"));
result = kResultFalse;
}
return result;
}
}
}
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::canProcessSampleSize (int32 symbolicSampleSize)
{
if (symbolicSampleSize == kSample32)
return kResultTrue;
// we support double processing
if (symbolicSampleSize == kSample64)
return kResultTrue;
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGain::notify (IMessage* message)
{
if (!message)
return kInvalidArgument;
if (strcmp (message->getMessageID (), "BinaryMessage") == 0)
{
const void* data;
uint32 size;
if (message->getAttributes ()->getBinary ("MyData", data, size) == kResultOk)
{
// we are in UI thread
// size should be 100
if (size == 100 && ((char*)data)[1] == 1) // yeah...
{
fprintf (stderr, "[AGain] received the binary message!\n");
}
return kResultOk;
}
}
return AudioEffect::notify (message);
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,101 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/again.h
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST SDK 3.0
// Simple gain plug-in with gain, bypass values and 1 midi input
// and the same plug-in with sidechain
//
//-----------------------------------------------------------------------------
// 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
#include "public.sdk/source/vst/vstaudioeffect.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// AGain: directly derived from the helper class AudioEffect
//------------------------------------------------------------------------
class AGain : public AudioEffect
{
public:
AGain ();
~AGain () override;
//--- ---------------------------------------------------------------------
// create function required for plug-in factory,
// it will be called to create new instances of this plug-in
//--- ---------------------------------------------------------------------
static FUnknown* createInstance (void* /*context*/) { return (IAudioProcessor*)new AGain; }
//--- ---------------------------------------------------------------------
// AudioEffect overrides:
//--- ---------------------------------------------------------------------
/** Called at first after constructor */
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
/** Called at the end before destructor */
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
/** Switch the plug-in on/off */
tresult PLUGIN_API setActive (TBool state) SMTG_OVERRIDE;
/** Here we go...the process call */
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
/** Test of a communication channel between controller and component */
tresult receiveText (const char* text) SMTG_OVERRIDE;
/** For persistence */
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
/** Will be called before any process call */
tresult PLUGIN_API setupProcessing (ProcessSetup& newSetup) SMTG_OVERRIDE;
/** Bus arrangement managing: in this example the 'again' will be mono for mono input/output and
* stereo for other arrangements. */
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
/** Asks if a given sample size is supported see \ref SymbolicSampleSizes. */
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) SMTG_OVERRIDE;
/** We want to receive message. */
tresult PLUGIN_API notify (IMessage* message) SMTG_OVERRIDE;
//------------------------------------------------------------------------
protected:
//==============================================================================
template <typename SampleType>
SampleType processAudio (SampleType** input, SampleType** output, int32 numChannels,
int32 sampleFrames, float gain);
template <typename SampleType>
SampleType processVuPPM (SampleType** input, int32 numChannels, int32 sampleFrames);
// our model values
float fGain {1.f};
float fGainReduction {0.f};
float fVuPPMOld {0.f};
int32 currentProcessMode {-1}; // -1 means not initialized
bool bHalfGain {false};
bool bBypass {false};
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,32 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againcids.h
// Created by : Steinberg, 12/2007
// Description : define the class IDs for AGain
//
//-----------------------------------------------------------------------------
// 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
namespace Steinberg {
namespace Vst {
// Here are defined the UIDs for the 2 processors (2 plug-ins) and 1 controller (shared by the 2 plug-ins)
static const FUID AGainProcessorUID (0x84E8DE5F, 0x92554F53, 0x96FAE413, 0x3C935A18);
static const FUID AGainWithSideChainProcessorUID (0x41347FD6, 0xFED64094, 0xAFBB12B7, 0xDBA1D441);
static const FUID AGainControllerUID (0xD39D5B65, 0xD7AF42FA, 0x843F4AC8, 0x41EB04F0);
#define AGainVST3Category "Fx"
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,393 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againcontroller.cpp
// Created by : Steinberg, 04/2005
// Description : AGain Controller Example for VST 3
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "againcontroller.h"
#include "againparamids.h"
#include "againuimessagecontroller.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/base/ustring.h"
#include "pluginterfaces/vst/ivstmidicontrollers.h"
#include "base/source/fstreamer.h"
#include "base/source/fstring.h"
#include "vstgui/uidescription/delegationcontroller.h"
#include <cmath>
#include <cstdio>
using namespace VSTGUI;
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// GainParameter Declaration
// example of custom parameter (overwriting to and fromString)
//------------------------------------------------------------------------
class GainParameter : public Parameter
{
public:
GainParameter (int32 flags, int32 id);
void toString (ParamValue normValue, String128 string) const SMTG_OVERRIDE;
bool fromString (const TChar* string, ParamValue& normValue) const SMTG_OVERRIDE;
};
//------------------------------------------------------------------------
// GainParameter Implementation
//------------------------------------------------------------------------
GainParameter::GainParameter (int32 flags, int32 id)
{
Steinberg::UString (info.title, USTRINGSIZE (info.title)).assign (USTRING ("Gain"));
Steinberg::UString (info.units, USTRINGSIZE (info.units)).assign (USTRING ("dB"));
info.flags = flags;
info.id = id;
info.stepCount = 0;
info.defaultNormalizedValue = 0.5f;
info.unitId = kRootUnitId;
setNormalized (1.f);
}
//------------------------------------------------------------------------
void GainParameter::toString (ParamValue normValue, String128 string) const
{
char text[32];
if (normValue > 0.0001)
{
snprintf (text, 32, "%.2f", 20 * log10f ((float)normValue));
}
else
{
strcpy (text, "-oo");
}
Steinberg::UString (string, 128).fromAscii (text);
}
//------------------------------------------------------------------------
bool GainParameter::fromString (const TChar* string, ParamValue& normValue) const
{
String wrapper ((TChar*)string); // don't know buffer size here!
double tmp = 0.0;
if (wrapper.scanFloat (tmp))
{
// allow only values between -oo and 0dB
if (tmp > 0.0)
{
tmp = -tmp;
}
normValue = expf (logf (10.f) * (float)tmp / 20.f);
return true;
}
return false;
}
//------------------------------------------------------------------------
// AGainController Implementation
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::initialize (FUnknown* context)
{
tresult result = EditControllerEx1::initialize (context);
if (result != kResultOk)
{
return result;
}
//--- Create Units-------------
UnitInfo unitInfo {};
Unit* unit;
// create root only if you want to use the programListId
/* unitInfo.id = kRootUnitId; // always for Root Unit
unitInfo.parentUnitId = kNoParentUnitId; // always for Root Unit
Steinberg::UString (unitInfo.name, USTRINGSIZE (unitInfo.name)).assign (USTRING ("Root"));
unitInfo.programListId = kNoProgramListId;
unit = new Unit (unitInfo);
addUnitInfo (unit);*/
// create a unit1 for the gain
unitInfo.id = 1;
unitInfo.parentUnitId = kRootUnitId; // attached to the root unit
Steinberg::UString (unitInfo.name, USTRINGSIZE (unitInfo.name)).assign (USTRING ("Unit1"));
unitInfo.programListId = kNoProgramListId;
unit = new Unit (unitInfo);
addUnit (unit);
//---Create Parameters------------
//---Gain parameter--
auto* gainParam = new GainParameter (ParameterInfo::kCanAutomate, kGainId);
parameters.addParameter (gainParam);
gainParam->setUnitID (1);
//---VuMeter parameter---
int32 stepCount = 0;
ParamValue defaultVal = 0;
int32 flags = ParameterInfo::kIsReadOnly;
int32 tag = kVuPPMId;
parameters.addParameter (STR16 ("VuPPM"), nullptr, stepCount, defaultVal, flags, tag);
//---Bypass parameter---
stepCount = 1;
defaultVal = 0;
flags = ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass;
tag = kBypassId;
parameters.addParameter (STR16 ("Bypass"), nullptr, stepCount, defaultVal, flags, tag);
//---Custom state init------------
String str ("Hello World!");
str.copyTo16 (defaultMessageText, 0, 127);
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::terminate ()
{
return EditControllerEx1::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::setComponentState (IBStream* state)
{
// we receive the current state of the component (processor part)
// we read only the gain and bypass value...
if (!state)
return kResultFalse;
IBStreamer streamer (state, kLittleEndian);
float savedGain = 0.f;
if (streamer.readFloat (savedGain) == false)
return kResultFalse;
setParamNormalized (kGainId, savedGain);
// jump the GainReduction
streamer.seek (sizeof (float), kSeekCurrent);
int32 bypassState = 0;
if (streamer.readInt32 (bypassState) == false)
return kResultFalse;
setParamNormalized (kBypassId, bypassState ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
IPlugView* PLUGIN_API AGainController::createView (const char* _name)
{
// someone wants my editor
ConstString name (_name);
if (name == ViewType::kEditor)
{
auto* view = new VST3Editor (this, "view", "again.uidesc");
return view;
}
return nullptr;
}
//------------------------------------------------------------------------
IController* AGainController::createSubController (UTF8StringPtr name,
const IUIDescription* /*description*/,
VST3Editor* /*editor*/)
{
if (UTF8StringView (name) == "MessageController")
{
auto* controller = new UIMessageController (this);
addUIMessageController (controller);
return controller;
}
return nullptr;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::setState (IBStream* state)
{
IBStreamer streamer (state, kLittleEndian);
int8 byteOrder;
if (streamer.readInt8 (byteOrder) == false)
return kResultFalse;
if (streamer.readRaw (defaultMessageText, 128 * sizeof (TChar)) == false)
return kResultFalse;
// if the byteorder doesn't match, byte swap the text array ...
if (byteOrder != BYTEORDER)
{
for (int32 i = 0; i < 128; i++)
{
SWAP_16 (defaultMessageText[i])
}
}
// update our editors
for (auto& uiMessageController : uiMessageControllers)
uiMessageController->setMessageText (defaultMessageText);
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::getState (IBStream* state)
{
// here we can save UI settings for example
// as we save a Unicode string, we must know the byteorder when setState is called
IBStreamer streamer (state, kLittleEndian);
int8 byteOrder = BYTEORDER;
if (streamer.writeInt8 (byteOrder) == false)
return kResultFalse;
if (streamer.writeRaw (defaultMessageText, 128 * sizeof (TChar)) == false)
return kResultFalse;
return kResultTrue;
}
//------------------------------------------------------------------------
tresult AGainController::receiveText (const char* text)
{
// received from Component
if (text)
{
fprintf (stderr, "[AGainController] received: ");
fprintf (stderr, "%s", text);
fprintf (stderr, "\n");
}
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::setParamNormalized (ParamID tag, ParamValue value)
{
// called from host to update our parameters state
tresult result = EditControllerEx1::setParamNormalized (tag, value);
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::getParamStringByValue (ParamID tag, ParamValue valueNormalized,
String128 string)
{
/* example, but better to use a custom Parameter as seen in GainParameter
switch (tag)
{
case kGainId:
{
char text[32];
if (valueNormalized > 0.0001)
{
sprintf (text, "%.2f", 20 * log10f ((float)valueNormalized));
}
else
strcpy (text, "-oo");
Steinberg::UString (string, 128).fromAscii (text);
return kResultTrue;
}
}*/
return EditControllerEx1::getParamStringByValue (tag, valueNormalized, string);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::getParamValueByString (ParamID tag, TChar* string,
ParamValue& valueNormalized)
{
/* example, but better to use a custom Parameter as seen in GainParameter
switch (tag)
{
case kGainId:
{
Steinberg::UString wrapper ((TChar*)string, -1); // don't know buffer size here!
double tmp = 0.0;
if (wrapper.scanFloat (tmp))
{
valueNormalized = expf (logf (10.f) * (float)tmp / 20.f);
return kResultTrue;
}
return kResultFalse;
}
}*/
return EditControllerEx1::getParamValueByString (tag, string, valueNormalized);
}
//------------------------------------------------------------------------
void AGainController::addUIMessageController (UIMessageController* controller)
{
uiMessageControllers.push_back (controller);
}
//------------------------------------------------------------------------
void AGainController::removeUIMessageController (UIMessageController* controller)
{
UIMessageControllerList::const_iterator it =
std::find (uiMessageControllers.begin (), uiMessageControllers.end (), controller);
if (it != uiMessageControllers.end ())
uiMessageControllers.erase (it);
}
//------------------------------------------------------------------------
void AGainController::setDefaultMessageText (String128 text)
{
String tmp (text);
tmp.copyTo16 (defaultMessageText, 0, 127);
}
//------------------------------------------------------------------------
TChar* AGainController::getDefaultMessageText ()
{
return defaultMessageText;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::queryInterface (const char* iid, void** obj)
{
QUERY_INTERFACE (iid, obj, IMidiMapping::iid, IMidiMapping)
return EditControllerEx1::queryInterface (iid, obj);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainController::getMidiControllerAssignment (int32 busIndex,
int16 /*midiChannel*/,
CtrlNumber midiControllerNumber,
ParamID& tag)
{
// we support for the Gain parameter all MIDI Channel but only first bus (there is only one!)
if (busIndex == 0 && midiControllerNumber == kCtrlVolume)
{
tag = kGainId;
return kResultTrue;
}
return kResultFalse;
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,98 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againcontroller.h
// Created by : Steinberg, 04/2005
// Description : AGain Editor Example for VST 3
//
//-----------------------------------------------------------------------------
// 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
#include "vstgui/plugin-bindings/vst3editor.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include <vector>
namespace Steinberg {
namespace Vst {
template <typename T>
class AGainUIMessageController;
//------------------------------------------------------------------------
// AGainController
//------------------------------------------------------------------------
class AGainController : public EditControllerEx1, public IMidiMapping, public VSTGUI::VST3EditorDelegate
{
public:
using UIMessageController = AGainUIMessageController<AGainController>;
using UTF8StringPtr = VSTGUI::UTF8StringPtr;
using IUIDescription = VSTGUI::IUIDescription;
using IController = VSTGUI::IController;
using VST3Editor = VSTGUI::VST3Editor;
//--- ---------------------------------------------------------------------
// create function required for plug-in factory,
// it will be called to create new instances of this controller
//--- ---------------------------------------------------------------------
static FUnknown* createInstance (void* /*context*/)
{
return (IEditController*)new AGainController;
}
//---from IPluginBase--------
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
//---from EditController-----
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
IPlugView* PLUGIN_API createView (const char* name) SMTG_OVERRIDE;
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API setParamNormalized (ParamID tag, ParamValue value) SMTG_OVERRIDE;
tresult PLUGIN_API getParamStringByValue (ParamID tag, ParamValue valueNormalized,
String128 string) SMTG_OVERRIDE;
tresult PLUGIN_API getParamValueByString (ParamID tag, TChar* string,
ParamValue& valueNormalized) SMTG_OVERRIDE;
//---from ComponentBase-----
tresult receiveText (const char* text) SMTG_OVERRIDE;
//---from IMidiMapping-----------------
tresult PLUGIN_API getMidiControllerAssignment (int32 busIndex, int16 channel,
CtrlNumber midiControllerNumber,
ParamID& tag) SMTG_OVERRIDE;
//---from VST3EditorDelegate-----------
IController* createSubController (UTF8StringPtr name, const IUIDescription* description,
VST3Editor* editor) SMTG_OVERRIDE;
DELEGATE_REFCOUNT (EditController)
tresult PLUGIN_API queryInterface (const char* iid, void** obj) SMTG_OVERRIDE;
//---Internal functions-------
void addUIMessageController (UIMessageController* controller);
void removeUIMessageController (UIMessageController* controller);
void setDefaultMessageText (String128 text);
TChar* getDefaultMessageText ();
//------------------------------------------------------------------------
private:
using UIMessageControllerList = std::vector<UIMessageController*>;
UIMessageControllerList uiMessageControllers;
String128 defaultMessageText {};
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,80 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againentry.cpp
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST 3
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "again.h" // for AGain
#include "againsidechain.h" // for AGain SideChain
#include "againcontroller.h" // for AGainController
#include "againcids.h" // for class ids and category
#include "version.h" // for versioning
#include "public.sdk/source/main/pluginfactory.h"
#define stringPluginName "AGain VST3"
#define stringPluginSideChainName "AGain SideChain VST3"
#if TARGET_OS_IPHONE
#include "public.sdk/source/vst/vstguieditor.h"
extern void* moduleHandle;
#endif
using namespace Steinberg::Vst;
//------------------------------------------------------------------------
// VST Plug-in Entry
//------------------------------------------------------------------------
// Windows: do not forget to include a .def file in your project to export
// GetPluginFactory function!
//------------------------------------------------------------------------
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail)
//---First plug-in included in this factory-------
// its kVstAudioEffectClass component
DEF_CLASS2 (INLINE_UID_FROM_FUID(AGainProcessorUID),
PClassInfo::kManyInstances, // cardinality
kVstAudioEffectClass, // the component category (do not change this)
stringPluginName, // here the plug-in name (to be changed)
Vst::kDistributable, // means that component and controller could be distributed on different computers
AGainVST3Category, // Subcategory for this plug-in (to be changed)
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (do not change this, always use this define)
Steinberg::Vst::AGain::createInstance) // function pointer called when this component should be instantiated
// its kVstComponentControllerClass component
DEF_CLASS2 (INLINE_UID_FROM_FUID (AGainControllerUID),
PClassInfo::kManyInstances, // cardinality
kVstComponentControllerClass,// the Controller category (do not change this)
stringPluginName "Controller", // controller name (can be the same as the component name)
0, // not used here
"", // not used here
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (do not change this, always use this define)
Steinberg::Vst::AGainController::createInstance)// function pointer called when this component should be instantiated
//---Second plug-in (AGain with sidechain (only component, use the same controller) included in this factory-------
DEF_CLASS2 (INLINE_UID_FROM_FUID(AGainWithSideChainProcessorUID),
PClassInfo::kManyInstances, // cardinality
kVstAudioEffectClass, // the component category (do not change this)
stringPluginSideChainName, // here the plug-in name (to be changed)
Vst::kDistributable, // means that component and controller could be distributed on different computers
AGainVST3Category, // Subcategory for this plug-in (to be changed)
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (do not change this, always use this define)
Steinberg::Vst::AGainWithSideChain::createInstance) // function pointer called when this component should be instantiated
//----for others plug-ins contained in this factory, put like for the first plug-in different DEF_CLASS2---
END_FACTORY
@@ -0,0 +1,25 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againparamids.h
// Created by : Steinberg, 12/2007
// Description : define the parameter IDs used by AGain
//
//-----------------------------------------------------------------------------
// 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
enum
{
/** parameter ID */
kGainId = 0, ///< for the gain value (is automatable)
kVuPPMId, ///< for the Vu value return to host (ReadOnly parameter for our UI)
kBypassId ///< Bypass value (we will handle the bypass process) (is automatable)
};
@@ -0,0 +1,81 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againprocess.h
// Created by : Steinberg, 11/2016
// Description : AGain Example for VST SDK 3.0
// Simple gain plug-in with gain, bypass values and 1 midi input
// and the same plug-in with sidechain
//
//-----------------------------------------------------------------------------
// 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
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
template <typename SampleType>
SampleType AGain::processAudio (SampleType** in, SampleType** out, int32 numChannels,
int32 sampleFrames, float gain)
{
SampleType vuPPM = 0;
// in real Plug-in it would be better to do dezippering to avoid jump (click) in gain value
for (int32 i = 0; i < numChannels; i++)
{
int32 samples = sampleFrames;
SampleType* ptrIn = (SampleType*)in[i];
SampleType* ptrOut = (SampleType*)out[i];
SampleType tmp;
while (--samples >= 0)
{
// apply gain
tmp = (*ptrIn++) * gain;
(*ptrOut++) = tmp;
// check only positive values
if (tmp > vuPPM)
{
vuPPM = tmp;
}
}
}
return vuPPM;
}
//------------------------------------------------------------------------
template <typename SampleType>
SampleType AGain::processVuPPM (SampleType** in, int32 numChannels, int32 sampleFrames)
{
SampleType vuPPM = 0;
for (int32 i = 0; i < numChannels; i++)
{
int32 samples = sampleFrames;
SampleType* ptrIn = (SampleType*)in[i];
SampleType tmp;
while (--samples >= 0)
{
tmp = (*ptrIn++);
// check only positive values
if (tmp > vuPPM)
{
vuPPM = tmp;
}
}
}
return vuPPM;
}
} // Vst
} // Steinberg
@@ -0,0 +1,365 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againsidechain.cpp
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST SDK 3
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "againsidechain.h"
#include "againcids.h" // for class ids
#include "againparamids.h"
#include "againprocess.h"
#include "public.sdk/source/vst/vstaudioprocessoralgo.h"
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include <cstdio>
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// AGainWithSideChain Implementation
//------------------------------------------------------------------------
//------------------------------------------------------------------------
tresult PLUGIN_API AGainWithSideChain::initialize (FUnknown* context)
{
//---always initialize the parent-------
tresult result = AGain::initialize (context);
// if everything Ok, continue
if (result != kResultOk)
{
return result;
}
// create a Mono SideChain input bus (this will be the 2cd input)
addAudioInput (STR16 ("Mono Aux In"), SpeakerArr::kMono, kAux, 0);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainWithSideChain::process (ProcessData& data)
{
// finally the process function
// In this example there are 4 steps:
// 1) Read inputs parameters coming from host (in order to adapt our model values)
// 2) Read inputs events coming from host (we apply a gain reduction depending of the velocity
// of pressed key) 3) Process the gain of the input buffer to the output buffer 4) Write the new
// VUmeter value to the output Parameters queue
//---1) Read inputs parameter changes-----------
if (IParameterChanges* paramChanges = data.inputParameterChanges)
{
int32 numParamsChanged = paramChanges->getParameterCount ();
// for each parameter which are some changes in this audio block:
for (int32 i = 0; i < numParamsChanged; i++)
{
if (IParamValueQueue* paramQueue = paramChanges->getParameterData (i))
{
int32 offsetSamples;
double value;
int32 numPoints = paramQueue->getPointCount ();
switch (paramQueue->getParameterId ())
{
case kGainId:
// we use in this example only the last point of the queue.
// in some wanted case for specific kind of parameter it makes sense to
// retrieve all points and process the whole audio block in small blocks.
if (paramQueue->getPoint (numPoints - 1, offsetSamples, value) ==
kResultTrue)
{
fGain = (float)value;
}
break;
case kBypassId:
if (paramQueue->getPoint (numPoints - 1, offsetSamples, value) ==
kResultTrue)
{
bBypass = (value > 0.5f);
}
break;
}
}
}
}
//---2) Read input events-------------
if (IEventList* eventList = data.inputEvents)
{
int32 numEvent = eventList->getEventCount ();
for (int32 i = 0; i < numEvent; i++)
{
Event event {};
if (eventList->getEvent (i, event) == kResultOk)
{
switch (event.type)
{
//--- -------------------
case Event::kNoteOnEvent:
// use the velocity as gain modifier
fGainReduction = event.noteOn.velocity;
break;
//--- -------------------
case Event::kNoteOffEvent:
// noteOff reset the reduction
fGainReduction = 0.f;
break;
}
}
}
}
//--- ----------------------------------
//---3) Process Audio---------------------
//--- ----------------------------------
if (data.numInputs == 0 || data.numOutputs == 0)
{
// nothing to do
return kResultOk;
}
// (simplification) we suppose in this example that we have the same input channel count than
// the output
int32 numChannels = data.inputs[0].numChannels;
//---get audio buffers----------------
uint32 sampleFramesSize = getSampleFramesSizeInBytes (processSetup, data.numSamples);
void** in = getChannelBuffersPointer (processSetup, data.inputs[0]);
void** out = getChannelBuffersPointer (processSetup, data.outputs[0]);
void** auxIn = nullptr;
bool auxActive = false;
// check if our sidechain input is active (here our sidechain is the 2cd input)
if (getAudioInput (1)->isActive ())
{
auxIn = getChannelBuffersPointer (processSetup, data.inputs[1]);
auxActive = true;
}
float fVuPPM = 0.f;
//---check if silence---------------
// check if all channel are silent then process silent
if (data.inputs[0].silenceFlags == getChannelMask (data.inputs[0].numChannels))
{
// mark output silence too
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
// the plug-in has to be sure that if it sets the flags silence that the output buffer are
// clear
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be cleared if the buffers are the same (in this case input buffer are
// already cleared by the host)
if (in[i] != out[i])
{
memset (out[i], 0, sampleFramesSize);
}
}
fVuPPM = 0.f;
}
else // we have to process (no silence)
{
// mark our outputs has not silent
data.outputs[0].silenceFlags = 0;
//---in bypass mode outputs should be like inputs-----
if (bBypass)
{
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be copied if the buffers are the same
if (in[i] != out[i])
{
memcpy (out[i], in[i], sampleFramesSize);
}
}
// in this example we do not update the VuMeter in Bypass
}
else
{
//---apply gain factor----------
float gain = (fGain - fGainReduction);
if (bHalfGain)
{
gain = gain * 0.5f;
}
// if the applied gain is nearly zero, we could say that the outputs are zeroed and we set
// the silence flags.
if (gain < 0.0000001)
{
for (int32 i = 0; i < numChannels; i++)
{
memset (out[i], 0, sampleFramesSize);
}
// this will set to 1 all channels
data.outputs[0].silenceFlags = getChannelMask (data.outputs[0].numChannels);
fVuPPM = 0.f;
}
else
{
if (auxActive)
{
if (data.symbolicSampleSize == kSample32)
fVuPPM = processAudioWithSideChain<Sample32> (
(Sample32**)in, (Sample32**)out, (Sample32**)auxIn, numChannels,
data.numSamples, gain);
else
fVuPPM = static_cast<float> (processAudioWithSideChain<Sample64> (
(Sample64**)in, (Sample64**)out, (Sample64**)auxIn, numChannels,
data.numSamples, gain));
}
else
{
if (data.symbolicSampleSize == kSample32)
fVuPPM = processAudio<Sample32> ((Sample32**)in, (Sample32**)out,
numChannels, data.numSamples, gain);
else
fVuPPM = static_cast<float> (processAudio<Sample64> (
(Sample64**)in, (Sample64**)out, numChannels, data.numSamples, gain));
}
}
}
}
//---3) Write <outputs parameter changes-----------
IParameterChanges* outParamChanges = data.outputParameterChanges;
// a new value of VuMeter will be send to the host
// (the host will send it back in sync to our controller for updating our editor)
if (outParamChanges && fVuPPMOld != fVuPPM)
{
int32 index = 0;
IParamValueQueue* paramQueue = outParamChanges->addParameterData (kVuPPMId, index);
if (paramQueue)
{
int32 index2 = 0;
paramQueue->addPoint (0, fVuPPM, index2);
}
}
fVuPPMOld = fVuPPM;
return kResultOk;
}
//------------------------------------------------------------------------
template <typename SampleType>
SampleType AGainWithSideChain::processAudioWithSideChain (SampleType** in, SampleType** out,
SampleType** aux, int32 numChannels,
int32 sampleFrames, float gain)
{
SampleType vuPPM = 0;
// we add the sidechain to the input signal
for (int32 i = 0; i < numChannels; i++)
{
int32 samples = sampleFrames;
auto* ptrIn = (SampleType*)in[i];
auto* ptrAuxIn = (SampleType*)aux[0];
auto* ptrOut = (SampleType*)out[i];
SampleType tmp;
while (--samples >= 0)
{
// apply gain
tmp = (*ptrIn++ + *ptrAuxIn++) * gain;
(*ptrOut++) = tmp;
// check only positive values
if (tmp > vuPPM)
{
vuPPM = tmp;
}
}
}
return vuPPM;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainWithSideChain::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts)
{
// the first input is the Main Input and the second is the SideChain Input
if (numIns == 2 && numOuts == 1)
{
// the host wants Mono => Mono (or 1 channel -> 1 channel)
if (SpeakerArr::getChannelCount (inputs[0]) == 1 &&
SpeakerArr::getChannelCount (outputs[0]) == 1)
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
// check if we are Mono => Mono, if not we need to recreate the busses
if (bus->getArrangement () != inputs[0])
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioInput (0)->setName (STR16 ("Mono In"));
getAudioOutput (0)->setArrangement (outputs[0]);
getAudioOutput (0)->setName (STR16 ("Mono Out"));
}
// check if sidechain is mono
if (SpeakerArr::getChannelCount (inputs[1]) != 1)
return kResultFalse;
return kResultOk;
}
}
// the host wants something else than Mono => Mono, in this case we are always Stereo =>
// Stereo
else
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
tresult result = kResultFalse;
// the host wants 2->2 (could be LsRs -> LsRs)
if (SpeakerArr::getChannelCount (inputs[0]) == 2 &&
SpeakerArr::getChannelCount (outputs[0]) == 2)
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioInput (0)->setName (STR16 ("Stereo In"));
getAudioOutput (0)->setArrangement (outputs[0]);
getAudioOutput (0)->setName (STR16 ("Stereo Out"));
// check if sidechain is mono
if (SpeakerArr::getChannelCount (inputs[1]) != 1)
result = kResultFalse;
else
result = kResultTrue;
}
// the host want something different than 1->1 or 2->2 : in this case we want stereo
else if (bus->getArrangement () != SpeakerArr::kStereo)
{
getAudioInput (0)->setArrangement (SpeakerArr::kStereo);
getAudioInput (0)->setName (STR16 ("Stereo In"));
getAudioOutput (0)->setArrangement (SpeakerArr::kStereo);
getAudioOutput (0)->setName (STR16 ("Stereo Out"));
result = kResultFalse;
}
return result;
}
}
}
return kResultFalse;
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,53 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againsidechain.h
// Created by : Steinberg, 04/2016
// Description : AGain Example for VST SDK 3.0
// Simple gain plug-in with gain, bypass values and 1 midi input
// and a sidechain
//
//-----------------------------------------------------------------------------
// 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
#include "again.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// AGainWithSideChain: directly derived from AGain
//------------------------------------------------------------------------
class AGainWithSideChain : public AGain
{
public:
// just overwrite some functions
static FUnknown* createInstance (void* /*context*/)
{
return (IAudioProcessor*)new AGainWithSideChain;
}
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
protected:
//==============================================================================
template <typename SampleType>
SampleType processAudioWithSideChain (SampleType** in, SampleType** out, SampleType** aux,
int32 numChannels, int32 sampleFrames, float gain);
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,702 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againsimple.cpp
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST SDK 3.0
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "againsimple.h"
#include "againparamids.h"
#include "againuimessagecontroller.h"
#include "version.h" // for versioning
#include "public.sdk/source/main/pluginfactory.h"
#include "public.sdk/source/vst/vstaudioprocessoralgo.h"
#include "pluginterfaces/base/funknownimpl.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/base/ustring.h" // for UString128
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivstmidicontrollers.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include "pluginterfaces/vst/vstpresetkeys.h" // for use of IStreamAttributes
#include "base/source/fstreamer.h"
#include <cmath>
#include <cstdio>
// this allows to enable the communication example between again and its controller
#define AGAIN_TEST 1
using namespace VSTGUI;
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// GainParameter Declaration
// example of custom parameter (overwriting to and fromString)
//------------------------------------------------------------------------
class GainParameter : public Parameter
{
public:
GainParameter (int32 flags, int32 id);
void toString (ParamValue normValue, String128 string) const SMTG_OVERRIDE;
bool fromString (const TChar* string, ParamValue& normValue) const SMTG_OVERRIDE;
};
//------------------------------------------------------------------------
// GainParameter Implementation
//------------------------------------------------------------------------
GainParameter::GainParameter (int32 flags, int32 id)
{
Steinberg::UString (info.title, USTRINGSIZE (info.title)).assign (USTRING ("Gain"));
Steinberg::UString (info.units, USTRINGSIZE (info.units)).assign (USTRING ("dB"));
info.flags = flags;
info.id = id;
info.stepCount = 0;
info.defaultNormalizedValue = 0.5f;
info.unitId = kRootUnitId;
setNormalized (1.f);
}
//------------------------------------------------------------------------
void GainParameter::toString (ParamValue normValue, String128 string) const
{
char text[32];
if (normValue > 0.0001)
snprintf (text, 32, "%.2f", 20 * log10f ((float)normValue));
else
strcpy (text, "-oo");
Steinberg::UString (string, 128).fromAscii (text);
}
//------------------------------------------------------------------------
bool GainParameter::fromString (const TChar* string, ParamValue& normValue) const
{
Steinberg::UString wrapper ((TChar*)string, -1); // don't know buffer size here!
double tmp = 0.0;
if (wrapper.scanFloat (tmp))
{
// allow only values between -oo and 0dB
if (tmp > 0.0)
tmp = -tmp;
normValue = expf (logf (10.f) * (float)tmp / 20.f);
return true;
}
return false;
}
//------------------------------------------------------------------------
// AGain Implementation
//------------------------------------------------------------------------
AGainSimple::AGainSimple ()
: fGain (1.f)
, fGainReduction (0.f)
, fVuPPMOld (0.f)
, currentProcessMode (-1) // -1 means not initialized
, bHalfGain (false)
, bBypass (false)
{
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::initialize (FUnknown* context)
{
tresult result = SingleComponentEffect::initialize (context);
if (result != kResultOk)
return result;
//---create Audio In/Out busses------
// we want a stereo Input and a Stereo Output
addAudioInput (STR16 ("Stereo In"), SpeakerArr::kStereo);
addAudioOutput (STR16 ("Stereo Out"), SpeakerArr::kStereo);
//---create Event In/Out busses (1 bus with only 1 channel)------
addEventInput (STR16 ("Event In"), 1);
//---Create Parameters------------
//---Gain parameter--
auto* gainParam = new GainParameter (ParameterInfo::kCanAutomate, kGainId);
parameters.addParameter (gainParam);
//---VuMeter parameter---
int32 stepCount = 0;
ParamValue defaultVal = 0;
int32 flags = ParameterInfo::kIsReadOnly;
int32 tag = kVuPPMId;
parameters.addParameter (USTRING ("VuPPM"), nullptr, stepCount, defaultVal, flags, tag);
//---Bypass parameter---
stepCount = 1;
defaultVal = 0;
flags = ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass;
tag = kBypassId;
parameters.addParameter (USTRING ("Bypass"), nullptr, stepCount, defaultVal, flags, tag);
//---Custom state init------------
UString str (defaultMessageText, 128);
str.fromAscii ("Hello World!");
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::terminate ()
{
return SingleComponentEffect::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setActive (TBool state)
{
#if AGAIN_TEST
if (state)
fprintf (stderr, "[AGainSimple] Activated \n");
else
fprintf (stderr, "[AGainSimple] Deactivated \n");
#endif
// reset the VuMeter value
fVuPPMOld = 0.f;
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::process (ProcessData& data)
{
// finally the process function
// In this example there are 4 steps:
// 1) Read inputs parameters coming from host (in order to adapt our model values)
// 2) Read inputs events coming from host (we apply a gain reduction depending of the velocity of pressed key)
// 3) Process the gain of the input buffer to the output buffer
// 4) Write the new VUmeter value to the output Parameters queue
//---1) Read inputs parameter changes-----------
if (IParameterChanges* paramChanges = data.inputParameterChanges)
{
int32 numParamsChanged = paramChanges->getParameterCount ();
// for each parameter which are some changes in this audio block:
for (int32 i = 0; i < numParamsChanged; i++)
{
if (IParamValueQueue* paramQueue = paramChanges->getParameterData (i))
{
ParamValue value;
int32 sampleOffset;
int32 numPoints = paramQueue->getPointCount ();
switch (paramQueue->getParameterId ())
{
case kGainId:
// we use in this example only the last point of the queue.
// in some wanted case for specific kind of parameter it makes sense to retrieve all points
// and process the whole audio block in small blocks.
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) == kResultTrue)
{
fGain = (float)value;
}
break;
case kBypassId:
if (paramQueue->getPoint (numPoints - 1, sampleOffset, value) == kResultTrue)
{
bBypass = (value > 0.5f);
}
break;
}
}
}
}
//---2) Read input events-------------
if (IEventList* eventList = data.inputEvents)
{
int32 numEvent = eventList->getEventCount ();
for (int32 i = 0; i < numEvent; i++)
{
Event event {};
if (eventList->getEvent (i, event) == kResultOk)
{
switch (event.type)
{
//--- -------------------
case Event::kNoteOnEvent:
// use the velocity as gain modifier
fGainReduction = event.noteOn.velocity;
break;
//--- -------------------
case Event::kNoteOffEvent:
// noteOff reset the reduction
fGainReduction = 0.f;
break;
}
}
}
}
//--- ----------------------------------
//---3) Process Audio---------------------
//--- ----------------------------------
if (data.numInputs == 0 || data.numOutputs == 0)
{
// nothing to do
return kResultOk;
}
// (simplification) we suppose in this example that we have the same input channel count than
// the output
int32 numChannels = data.inputs[0].numChannels;
//---get audio buffers----------------
uint32 sampleFramesSize = getSampleFramesSizeInBytes (processSetup, data.numSamples);
void** in = getChannelBuffersPointer (processSetup, data.inputs[0]);
void** out = getChannelBuffersPointer (processSetup, data.outputs[0]);
float fVuPPM = 0.f;
//---check if silence---------------
// check if all channel are silent then process silent
if (data.inputs[0].silenceFlags == getChannelMask (data.inputs[0].numChannels))
{
// mark output silence too
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
// the plug-in has to be sure that if it sets the flags silence that the output buffer are
// clear
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be cleared if the buffers are the same (in this case input buffer are
// already cleared by the host)
if (in[i] != out[i])
{
memset (out[i], 0, sampleFramesSize);
}
}
fVuPPM = 0.f;
}
else
{
// mark our outputs has not silent
data.outputs[0].silenceFlags = 0;
//---in bypass mode outputs should be like inputs-----
if (bBypass)
{
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be copied if the buffers are the same
if (in[i] != out[i])
{
memcpy (out[i], in[i], sampleFramesSize);
}
}
// in this example we do not update the VuMeter in Bypass
}
else
{
//---apply gain factor----------
float gain = (fGain - fGainReduction);
if (bHalfGain)
{
gain = gain * 0.5f;
}
// if the applied gain is nearly zero, we could say that the outputs are zeroed and we set
// the silence flags.
if (gain < 0.0000001)
{
for (int32 i = 0; i < numChannels; i++)
{
memset (out[i], 0, sampleFramesSize);
}
// this will set to 1 all channels
data.outputs[0].silenceFlags = getChannelMask (data.outputs[0].numChannels);
fVuPPM = 0.f;
}
else
{
if (data.symbolicSampleSize == kSample32)
fVuPPM = processAudio<Sample32> ((Sample32**)in, (Sample32**)out, numChannels,
data.numSamples, gain);
else
fVuPPM = static_cast<float> (processAudio<Sample64> (
(Sample64**)in, (Sample64**)out, numChannels, data.numSamples, gain));
}
}
}
//---3) Write outputs parameter changes-----------
IParameterChanges* outParamChanges = data.outputParameterChanges;
// a new value of VuMeter will be send to the host
// (the host will send it back in sync to our controller for updating our editor)
if (outParamChanges && fVuPPMOld != fVuPPM)
{
int32 index = 0;
IParamValueQueue* paramQueue = outParamChanges->addParameterData (kVuPPMId, index);
if (paramQueue)
{
int32 index2 = 0;
paramQueue->addPoint (0, fVuPPM, index2);
}
}
fVuPPMOld = fVuPPM;
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setState (IBStream* state)
{
// we receive the current (processor part)
// called when we load a preset, the model has to be reloaded
IBStreamer streamer (state, kLittleEndian);
float savedGain = 0.f;
if (streamer.readFloat (savedGain) == false)
return kResultFalse;
float savedGainReduction = 0.f;
if (streamer.readFloat (savedGainReduction) == false)
return kResultFalse;
int32 savedBypass = 0;
if (streamer.readInt32 (savedBypass) == false)
return kResultFalse;
fGain = savedGain;
fGainReduction = savedGainReduction;
bBypass = savedBypass > 0;
setParamNormalized (kGainId, savedGain);
setParamNormalized (kBypassId, bBypass);
// Example of using the IStreamAttributes interface
if (auto stream = U::cast<IStreamAttributes> (state))
{
if (IAttributeList* list = stream->getAttributes ())
{
// get the current type (project/Default..) of this state
String128 string = {0};
if (list->getString (PresetAttributes::kStateType, string, 128 * sizeof (TChar)) ==
kResultTrue)
{
UString128 tmp (string);
char ascii[128];
tmp.toAscii (ascii, 128);
if (strncmp (ascii, StateType::kProject, strlen (StateType::kProject)) == 0)
{
// we are in project loading context...
}
}
// get the full file path of this state
TChar fullPath[1024];
memset (fullPath, 0, 1024 * sizeof (TChar));
if (list->getString (PresetAttributes::kFilePathStringType, fullPath,
1024 * sizeof (TChar)) == kResultTrue)
{
// here we have the full path ...
}
}
}
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::getState (IBStream* state)
{
// here we need to save the model
IBStreamer streamer (state, kLittleEndian);
streamer.writeFloat (fGain);
streamer.writeFloat (fGainReduction);
streamer.writeInt32 (bBypass ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setupProcessing (ProcessSetup& newSetup)
{
// called before the process call, always in a disable state (not active)
// here we keep a trace of the processing mode (offline,...) for example.
currentProcessMode = newSetup.processMode;
return SingleComponentEffect::setupProcessing (newSetup);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs, int32 numOuts)
{
if (numIns == 1 && numOuts == 1)
{
// the host wants Mono => Mono (or 1 channel -> 1 channel)
if (SpeakerArr::getChannelCount (inputs[0]) == 1 &&
SpeakerArr::getChannelCount (outputs[0]) == 1)
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
// check if we are Mono => Mono, if not we need to recreate the busses
if (bus->getArrangement () != inputs[0])
{
bus->setArrangement (inputs[0]);
bus->setName (STR16 ("Mono In"));
if (auto* busOut = FCast<AudioBus> (audioOutputs.at (0)))
{
busOut->setArrangement (outputs[0]);
busOut->setName (STR16 ("Mono Out"));
}
}
return kResultOk;
}
}
// the host wants something else than Mono => Mono, in this case we are always Stereo =>
// Stereo
else
{
auto* bus = FCast<AudioBus> (audioInputs.at (0));
if (bus)
{
tresult result = kResultFalse;
// the host wants 2->2 (could be LsRs -> LsRs)
if (SpeakerArr::getChannelCount (inputs[0]) == 2 &&
SpeakerArr::getChannelCount (outputs[0]) == 2)
{
bus->setArrangement (inputs[0]);
bus->setName (STR16 ("Stereo In"));
if (auto* busOut = FCast<AudioBus> (audioOutputs.at (0)))
{
busOut->setArrangement (outputs[0]);
busOut->setName (STR16 ("Stereo Out"));
}
result = kResultTrue;
}
// the host want something different than 1->1 or 2->2 : in this case we want stereo
else if (bus->getArrangement () != SpeakerArr::kStereo)
{
bus->setArrangement (SpeakerArr::kStereo);
bus->setName (STR16 ("Stereo In"));
if (auto* busOut = FCast<AudioBus> (audioOutputs.at (0)))
{
busOut->setArrangement (SpeakerArr::kStereo);
busOut->setName (STR16 ("Stereo Out"));
}
result = kResultFalse;
}
return result;
}
}
}
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::canProcessSampleSize (int32 symbolicSampleSize)
{
if (symbolicSampleSize == kSample32)
return kResultTrue;
// we support double processing
if (symbolicSampleSize == kSample64)
return kResultTrue;
return kResultFalse;
}
//------------------------------------------------------------------------
IPlugView* PLUGIN_API AGainSimple::createView (const char* name)
{
// someone wants my editor
if (name && FIDStringsEqual (name, ViewType::kEditor))
{
auto* view = new VST3Editor (this, "view", "again.uidesc");
return view;
}
return nullptr;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::getMidiControllerAssignment (int32 busIndex, int16 /*midiChannel*/,
CtrlNumber midiControllerNumber,
ParamID& tag)
{
// we support for the Gain parameter all MIDI Channel but only first bus (there is only one!)
if (busIndex == 0 && midiControllerNumber == kCtrlVolume)
{
tag = kGainId;
return kResultTrue;
}
return kResultFalse;
}
//------------------------------------------------------------------------
IController* AGainSimple::createSubController (UTF8StringPtr name,
const IUIDescription* /*description*/,
VST3Editor* /*editor*/)
{
if (UTF8StringView (name) == "MessageController")
{
auto* controller = new UIMessageController (this);
addUIMessageController (controller);
return controller;
}
return nullptr;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setEditorState (IBStream* state)
{
tresult result = kResultFalse;
int8 byteOrder;
if ((result = state->read (&byteOrder, sizeof (int8))) != kResultTrue)
return result;
if ((result = state->read (defaultMessageText, 128 * sizeof (TChar))) != kResultTrue)
return result;
// if the byteorder doesn't match, byte swap the text array ...
if (byteOrder != BYTEORDER)
{
for (int32 i = 0; i < 128; i++)
SWAP_16 (defaultMessageText[i])
}
for (auto& uiMessageController : uiMessageControllers)
uiMessageController->setMessageText (defaultMessageText);
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::getEditorState (IBStream* state)
{
// here we can save UI settings for example
IBStreamer streamer (state, kLittleEndian);
// as we save a Unicode string, we must know the byteorder when setState is called
int8 byteOrder = BYTEORDER;
if (streamer.writeInt8 (byteOrder) == false)
return kResultFalse;
if (streamer.writeRaw (defaultMessageText, 128 * sizeof (TChar)) == false)
return kResultFalse;
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::setParamNormalized (ParamID tag, ParamValue value)
{
// called from host to update our parameters state
tresult result = SingleComponentEffect::setParamNormalized (tag, value);
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::getParamStringByValue (ParamID tag, ParamValue valueNormalized,
String128 string)
{
return SingleComponentEffect::getParamStringByValue (tag, valueNormalized, string);
}
//------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::getParamValueByString (ParamID tag, TChar* string,
ParamValue& valueNormalized)
{
return SingleComponentEffect::getParamValueByString (tag, string, valueNormalized);
}
//------------------------------------------------------------------------
void AGainSimple::addUIMessageController (UIMessageController* controller)
{
uiMessageControllers.push_back (controller);
}
//------------------------------------------------------------------------
void AGainSimple::removeUIMessageController (UIMessageController* controller)
{
UIMessageControllerList::const_iterator it =
std::find (uiMessageControllers.begin (), uiMessageControllers.end (), controller);
if (it != uiMessageControllers.end ())
uiMessageControllers.erase (it);
}
//------------------------------------------------------------------------
void AGainSimple::setDefaultMessageText (String128 text)
{
UString str (defaultMessageText, 128);
str.assign (text, -1);
}
//------------------------------------------------------------------------
TChar* AGainSimple::getDefaultMessageText ()
{
return defaultMessageText;
}
//-----------------------------------------------------------------------------
tresult PLUGIN_API AGainSimple::queryInterface (const TUID iid, void** obj)
{
DEF_INTERFACE (IMidiMapping)
return SingleComponentEffect::queryInterface (iid, obj);
}
//------------------------------------------------------------------------
enum
{
// UI size
kEditorWidth = 350,
kEditorHeight = 120
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail)
//---First plug-in included in this factory-------
// its kVstAudioEffectClass component
DEF_CLASS2 (INLINE_UID (0xB9F9ADE1, 0xCD9C4B6D, 0xA57E61E3, 0x123535FD),
PClassInfo::kManyInstances, // cardinality
kVstAudioEffectClass, // the component category (do not change this)
"AGainSimple VST3", // here the plug-in name (to be changed)
0, // single component effects cannot be distributed so this is zero
"Fx", // Subcategory for this plug-in (to be changed)
FULL_VERSION_STR, // Plug-in version (to be changed)
kVstVersionString, // the VST 3 SDK version (do not change this, always use this define)
Steinberg::Vst::AGainSimple::createInstance)// function pointer called when this component should be instantiated
END_FACTORY
@@ -0,0 +1,148 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againsimple.h
// Created by : Steinberg, 04/2005
// Description : AGain Example for VST SDK 3.0
//
//-----------------------------------------------------------------------------
// 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
// must always come first
#include "public.sdk/source/vst/vstsinglecomponenteffect.h"
//------------------------------------------------------------------------
#include "public.sdk/source/vst/vstguieditor.h"
#include "pluginterfaces/vst/ivstcontextmenu.h"
#include "pluginterfaces/vst/ivstplugview.h"
#include "vstgui/plugin-bindings/vst3editor.h"
namespace Steinberg {
namespace Vst {
template <typename T>
class AGainUIMessageController;
//------------------------------------------------------------------------
// AGain as combined processor and controller
//------------------------------------------------------------------------
class AGainSimple : public SingleComponentEffect,
public VSTGUI::VST3EditorDelegate,
public IMidiMapping
{
public:
//------------------------------------------------------------------------
using UIMessageController = AGainUIMessageController<AGainSimple>;
using UTF8StringPtr = VSTGUI::UTF8StringPtr;
using IUIDescription = VSTGUI::IUIDescription;
using IController = VSTGUI::IController;
using VST3Editor = VSTGUI::VST3Editor;
AGainSimple ();
static FUnknown* createInstance (void* /*context*/) { return (IAudioProcessor*)new AGainSimple; }
//---from IComponent-----------------------
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
tresult PLUGIN_API setActive (TBool state) SMTG_OVERRIDE;
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) SMTG_OVERRIDE;
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API setupProcessing (ProcessSetup& newSetup) SMTG_OVERRIDE;
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
//---from IEditController-------
IPlugView* PLUGIN_API createView (const char* name) SMTG_OVERRIDE;
tresult PLUGIN_API setEditorState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getEditorState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API setParamNormalized (ParamID tag, ParamValue value) SMTG_OVERRIDE;
tresult PLUGIN_API getParamStringByValue (ParamID tag, ParamValue valueNormalized,
String128 string) SMTG_OVERRIDE;
tresult PLUGIN_API getParamValueByString (ParamID tag, TChar* string,
ParamValue& valueNormalized) SMTG_OVERRIDE;
//---from IMidiMapping-----------------
tresult PLUGIN_API getMidiControllerAssignment (int32 busIndex, int16 channel,
CtrlNumber midiControllerNumber,
ParamID& tag) SMTG_OVERRIDE;
//---from VST3EditorDelegate-----------
IController* createSubController (UTF8StringPtr name, const IUIDescription* description,
VST3Editor* editor) SMTG_OVERRIDE;
//---Interface---------
OBJ_METHODS (AGainSimple, SingleComponentEffect)
tresult PLUGIN_API queryInterface (const TUID iid, void** obj) SMTG_OVERRIDE;
REFCOUNT_METHODS (SingleComponentEffect)
//---Internal functions-------
void addUIMessageController (UIMessageController* controller);
void removeUIMessageController (UIMessageController* controller);
void setDefaultMessageText (String128 text);
TChar* getDefaultMessageText ();
//------------------------------------------------------------------------
template <typename SampleType>
SampleType processAudio (SampleType** in, SampleType** out, int32 numChannels,
int32 sampleFrames, float gain)
{
SampleType vuPPM = 0;
// in real plug-in it would be better to do dezippering to avoid jump (click) in gain value
for (int32 i = 0; i < numChannels; i++)
{
int32 samples = sampleFrames;
auto* ptrIn = (SampleType*)in[i];
auto* ptrOut = (SampleType*)out[i];
SampleType tmp;
while (--samples >= 0)
{
// apply gain
tmp = (*ptrIn++) * gain;
(*ptrOut++) = tmp;
// check only positive values
if (tmp > vuPPM)
{
vuPPM = tmp;
}
}
}
return vuPPM;
}
//------------------------------------------------------------------------
private:
// our model values
float fGain;
float fGainReduction;
float fVuPPMOld;
int32 currentProcessMode;
bool bHalfGain;
bool bBypass;
using UIMessageControllerList = std::vector<UIMessageController*>;
UIMessageControllerList uiMessageControllers;
String128 defaultMessageText;
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,159 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/againuimessagecontroller.h
// Created by : Steinberg, 04/2005
// Description : AGain UI Message Controller
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Steinberg Media Technologies nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#pragma once
#include "vstgui/lib/iviewlistener.h"
#include "vstgui/uidescription/icontroller.h"
#include "public.sdk/source/vst/utility/stringconvert.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// AGainUIMessageController
//------------------------------------------------------------------------
template <typename ControllerType>
class AGainUIMessageController : public VSTGUI::IController, public VSTGUI::ViewListenerAdapter
{
public:
enum Tags
{
kSendMessageTag = 1000
};
AGainUIMessageController (ControllerType* againController) : againController (againController), textEdit (nullptr)
{
}
~AGainUIMessageController () override
{
if (textEdit)
viewWillDelete (textEdit);
againController->removeUIMessageController (this);
}
void setMessageText (String128 msgText)
{
if (!textEdit)
return;
textEdit->setText (StringConvert::convert (msgText));
}
private:
using CControl = VSTGUI::CControl;
using CView = VSTGUI::CView;
using CTextEdit = VSTGUI::CTextEdit;
using UTF8String = VSTGUI::UTF8String;
using UIAttributes = VSTGUI::UIAttributes;
using IUIDescription = VSTGUI::IUIDescription;
//--- from IControlListener ----------------------
void valueChanged (CControl* /*pControl*/) override {}
void controlBeginEdit (CControl* /*pControl*/) override {}
void controlEndEdit (CControl* pControl) override
{
if (pControl->getTag () == kSendMessageTag)
{
if (pControl->getValueNormalized () > 0.5f)
{
againController->sendTextMessage (textEdit->getText ().data ());
pControl->setValue (0.f);
pControl->invalid ();
//---send a binary message
if (IPtr<IMessage> message = owned (againController->allocateMessage ()))
{
message->setMessageID ("BinaryMessage");
uint32 size = 100;
char8 data[100];
memset (data, 0, size * sizeof (char));
// fill my data with dummy stuff
for (uint32 i = 0; i < size; i++)
data[i] = i;
message->getAttributes ()->setBinary ("MyData", data, size);
againController->sendMessage (message);
}
}
}
}
//--- from IControlListener ----------------------
//--- is called when a view is created -----
CView* verifyView (CView* view, const UIAttributes& /*attributes*/,
const IUIDescription* /*description*/) override
{
if (CTextEdit* te = dynamic_cast<CTextEdit*> (view))
{
// this allows us to keep a pointer of the text edit view
textEdit = te;
// add this as listener in order to get viewWillDelete and viewLostFocus calls
textEdit->registerViewListener (this);
// initialize it content
textEdit->setText (
StringConvert::convert (againController->getDefaultMessageText ()));
}
return view;
}
//--- from IViewListenerAdapter ----------------------
//--- is called when a view will be deleted: the editor is closed -----
void viewWillDelete (CView* view) override
{
if (dynamic_cast<CTextEdit*> (view) == textEdit)
{
textEdit->unregisterViewListener (this);
textEdit = nullptr;
}
}
//--- is called when the view is loosing the focus -----------------
void viewLostFocus (CView* view) override
{
if (dynamic_cast<CTextEdit*> (view) == textEdit)
{
// save the last content of the text edit view
const auto& text = textEdit->getText ();
auto utf16Text = StringConvert::convert (text.getString ());
againController->setDefaultMessageText (utf16Text.data ());
}
}
ControllerType* againController;
CTextEdit* textEdit;
};
//------------------------------------------------------------------------
} // Vst
} // Steinberg
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again/source/version.h
// Created by : Steinberg, 01/2008
// Description : Example of handle the versioning and copyright info of again plug-in
// used for the resources (RC file for example)
//
//-----------------------------------------------------------------------------
// 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
#include "pluginterfaces/base/fplatform.h"
// Plain project version file generated by cmake
#include "projectversion.h"
#define stringOriginalFilename "again.vst3"
#if SMTG_PLATFORM_64
#define stringFileDescription "AGain VST3-SDK (64Bit)"
#else
#define stringFileDescription "AGain VST3-SDK"
#endif
#define stringCompanyWeb "http://www.steinberg.net"
#define stringCompanyEmail "mailto:info@steinberg.de"
#define stringCompanyName "Steinberg Media Technologies"
#define stringLegalCopyright "© 2025 Steinberg Media Technologies"
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"
@@ -0,0 +1,80 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-again
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 AGain AAX example"
)
if(NOT SMTG_AAX_SDK_PATH OR NOT SMTG_ENABLE_VSTGUI_SUPPORT)
return()
endif()
include(SMTG_AddAAXLibrary)
set(again_sources
source/againaax.cpp
../again/source/again.cpp
../again/source/again.h
../again/source/againcids.h
../again/source/againcontroller.cpp
../again/source/againcontroller.h
../again/source/againentry.cpp
../again/source/againparamids.h
../again/source/againprocess.h
../again/source/againsidechain.cpp
../again/source/againsidechain.h
../again/source/againuimessagecontroller.h
../again/source/version.h
../again/resource/again.uidesc
)
set(target again-aax)
smtg_add_aaxplugin(${target} ${again_sources})
smtg_target_configure_version_file(${target})
set_target_properties(${target}
PROPERTIES
${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}
)
target_include_directories(${target}
PUBLIC
${SDK_ROOT}/public.sdk/samples/vst/again/source
)
target_compile_features(${target}
PUBLIC
cxx_std_17
)
target_link_libraries(${target}
PRIVATE
sdk
vstgui_support
aax_wrapper
)
smtg_target_add_plugin_resources(${target}
RESOURCES
../again/resource/again.uidesc
../again/resource/background.png
../again/resource/slider_background.png
../again/resource/slider_handle.png
../again/resource/slider_handle_2.0x.png
../again/resource/vu_on.png
../again/resource/vu_off.png
)
if(SMTG_MAC)
smtg_target_set_bundle(${target}
BUNDLE_IDENTIFIER "com.steinberg.vst3.${target}"
INFOPLIST "${CMAKE_CURRENT_LIST_DIR}/../again/mac/Info.plist" PREPROCESS
)
elseif(SMTG_WIN)
target_sources(${target}
PRIVATE
../again/resource/again.rc
)
# remove warnings
if(NOT MINGW)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif(NOT MINGW)
endif(SMTG_MAC)
@@ -0,0 +1,19 @@
# AGain AAX
## Introduction
AGain AAX is the AAX version of the AGain plug-in by just adding a file (public.sdk/samples/vst/again_aax/source/againaax.cpp). It defines a mono and a stereo variant with a MIDI input.
> See also: [VST 3 - AAX Wrapper]((https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Wrappers/AAX+Wrapper.html) and [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#again).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,117 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_aax/source/againaax.cpp
// Created by : Steinberg, 03/2016
// Description : AGain AAX Example for VST SDK 3
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "public.sdk/source/vst/aaxwrapper/aaxwrapper_description.h"
#include "againcids.h"
#include "againparamids.h"
#include "pluginterfaces/base/futils.h"
//------------------------------------------------------------------------
#if 0 // for additional outputs
AAX_Aux_Desc effAux_stereo[] =
{
// name, channel count
{ "AGain AUX2", 2 },
{ nullptr }
};
#endif
//------------------------------------------------------------------------
#if 1 // MIDI inputs for instruments or Fx with MIDI input
AAX_MIDI_Desc effMIDI[] =
{
// port name, channel mask
{ "AGain", 0xffff },
{ nullptr }
};
#endif
//------------------------------------------------------------------------
// Input/Output meters
AAX_Meter_Desc effMeters[] =
{
// not used { "Input", CCONST ('A', 'G', 'I', 'n'), 0 /*AAX_eMeterOrientation_Default*/, 0 /*AAX_eMeterType_Input*/ },
{ "Output", kVuPPMId, 0 /*AAX_eMeterOrientation_Default*/, 1 /*AAX_eMeterType_Output*/ },
{ nullptr }
};
//------------------------------------------------------------------------
AAX_Plugin_Desc effPlugins[] = {
// effect-ID, name,
// Native ID, AudioSuite ID,
// InChannels, OutChannels, InSideChain channels,
// MIDI, Aux,
// Meters
// Latency
// note: IDs must be unique across plugins
// Mono variant
{"com.steinberg.again.mono",
"AGain",
CCONST ('A', 'G', 'N', '1'),
CCONST ('A', 'G', 'A', '1'),
1, /*mInputChannels*/
1, /*mOutputChannels*/
0, /*mSideChainInputChannels*/
effMIDI, /*effMIDI*/
nullptr, /*effAux*/
effMeters, /*effMeters*/
0 /*Latency*/
},
// Stereo variant
{"com.steinberg.again.stereo",
"AGain",
CCONST ('A', 'G', 'N', '2'),
CCONST ('A', 'G', 'A', '2'),
2, /*mInputChannels*/
2, /*mOutputChannels*/
0, /*mSideChainInputChannels*/
effMIDI, /*effMIDI*/
nullptr, /*effAux*/
effMeters, /*effMeters*/
0 /*Latency*/
},
{nullptr}
};
//------------------------------------------------------------------------
AAX_Effect_Desc effDesc = {
"Steinberg", // manufacturer
"AGain", // product
CCONST ('S', 'M', 'T', 'G'), // manufacturer ID
CCONST ('A', 'G', 'S', 'B'), // product ID
AGainVST3Category, // VST category (define againcids.h)
{0}, // VST3 class ID (set later)
1, // version
nullptr, // no pagetable file "again.xml",
effPlugins,
};
//------------------------------------------------------------------------
// this drag's in all the craft from the AAX library
int* forceLinkAAXWrapper = &AAXWrapper_linkAnchor;
//------------------------------------------------------------------------
AAX_Effect_Desc* AAXWrapper_GetDescription ()
{
// cannot initialize in global descriptor, and it might be link order dependent
memcpy (effDesc.mVST3PluginID, (const char*)Steinberg::Vst::AGainProcessorUID,
sizeof (effDesc.mVST3PluginID));
return &effDesc;
}
@@ -0,0 +1,47 @@
include(SMTG_AddVST3AuV3)
if(SMTG_MAC AND SMTG_ENABLE_VSTGUI_SUPPORT)
if(XCODE)
set(again_mac_app_sources
"macOS/Sources/ViewController.m"
"macOS/Sources/ViewController.h"
"macOS/Sources/AppDelegate.m"
"macOS/Sources/AppDelegate.h"
"audiounitconfig.h"
)
set(again_ios_app_sources
"iOS/Sources/ViewController.m"
"iOS/Sources/ViewController.h"
"iOS/Sources/AppDelegate.m"
"iOS/Sources/AppDelegate.h"
"iOS/Sources/main.mm"
"audiounitconfig.h"
)
set(again_mac_app_ui_resources
"macOS/Resources/Base.lproj/Main.storyboard"
"macOS/Resources/again.icns"
"Shared/drumLoop.wav"
)
set(again_ios_app_ui_resources
"iOS/Resources/Base.lproj/LaunchScreen.storyboard"
"iOS/Resources/Base.lproj/Main.storyboard"
"iOS/Resources/Assets.xcassets"
"Shared/drumLoop.wav"
)
# --------------------------------------------------------------------------------------------------------
# macOS target
# --------------------------------------------------------------------------------------------------------
smtg_add_auv3_app(again_auv3_macos "macOS" "AGain AUV3 macOS" "com.steinberg.sdk.auv3.againmac" audiounitconfig.h "macOS/again.entitlements" "${again_mac_app_sources}" "${again_mac_app_ui_resources}" "macOS/Resources/Info.plist" "Shared/Info.plist" again)
# --------------------------------------------------------------------------------------------------------
# iOS target
# --------------------------------------------------------------------------------------------------------
if(SMTG_ENABLE_IOS_TARGETS)
smtg_add_auv3_app(again_auv3_ios "iOS" "AGain AUV3 iOS" "com.steinberg.sdk.auv3.againios" "audiounitconfig.h" "iOS/again.entitlements" "${again_ios_app_sources}" "${again_ios_app_ui_resources}" "iOS/Resources/Info.plist" "Shared/Info.plist" again_ios)
endif(SMTG_ENABLE_IOS_TARGETS)
endif(XCODE)
endif(SMTG_MAC AND SMTG_ENABLE_VSTGUI_SUPPORT)
@@ -0,0 +1,19 @@
# AGain AUv3
## Introduction
AGain AUv3 is the AUv3 version of the AGain plug-in for macOS and iOS.
> See also: [VST 3 - AudioUnit v3 Wrapper](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Wrappers/AUv3+Wrapper.html) and [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#again).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>AUv3WrapperExtension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionServiceRoleType</key>
<string>NSExtensionServiceRoleTypeEditor</string>
<key>AudioComponents</key>
<array>
<dict>
<key>description</key>
<string>kAUcomponentDescription</string>
<key>manufacturer</key>
<string>kAUcomponentManufacturer1</string>
<key>name</key>
<string>kAUcomponentName</string>
<key>sandboxSafe</key>
<true/>
<key>subtype</key>
<string>kAUcomponentSubType1</string>
<key>tags</key>
<array>
<string>kAUcomponentTag</string>
</array>
<key>type</key>
<string>kAUcomponentType1</string>
<key>version</key>
<integer>kAUcomponentVersion</integer>
</dict>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.AudioUnit-UI</string>
<key>NSExtensionPrincipalClass</key>
<string>AUv3WrapperViewController</string>
</dict>
<key>SupportedNumChannels</key>
<string>kSupportedNumChannels</string>
</dict>
</plist>
@@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/audiounitconfig.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.
//-----------------------------------------------------------------------------
// AUWRAPPER_CHANGE: change all corresponding entries according to your plugin
// The specific variant of the Audio Unit app extension.
// The four possible types and their values are:
// Effect (aufx), Generator (augn), Instrument (aumu), and Music Effect (aufm)
#define kAUcomponentType 'aufx'
#define kAUcomponentType1 aufx
// A subtype code (unique ID) for the audio unit, such as gav3.
// This value must be exactly 4 alphanumeric characters
#define kAUcomponentSubType 'gav3'
#define kAUcomponentSubType1 gav3
// A manufacturer code for the audio unit, such as Aaud.
// This value must be exactly 4 alphanumeric characters
#define kAUcomponentManufacturer 'Stgb'
#define kAUcomponentManufacturer1 Stgb
// A product name for the audio unit
#define kAUcomponentDescription AUv3WrapperExtension
// The full name of the audio unit.
// This is derived from the manufacturer and description key values
#define kAUcomponentName Steinberg: AGainv3
// Displayed Tags
#define kAUcomponentTag Effects
// A version number for the Audio Unit app extension (decimal value of hexadecimal representation with zeros between subversions)
// Hexadecimal indexes representing: [0] = main version, [1] = 0 = dot, [2] = sub version, [3] = 0 = dot, [4] = sub-sub version,
// e.g. 1.0.0 == 0x10000 == 65536, 1.2.3 = 0x10203 = 66051
#define kAUcomponentVersion 65536
// Supported number of channels of your audio unit.
// Integer indexes representing: [0] = input count, [1] = output count, [2] = 2nd input count,
// [3]=2nd output count, etc.
// e.g. 1122 == config1: [mono input, mono output], config2: [stereo input, stereo output]
// see channelCapabilities for discussion
#define kSupportedNumChannels 1122
// The preview audio file name.
// To add your own custom audio file (for standalone effects), add an audio file to the project (AUv3WrappermacOS and AUv3WrapperiOS targets) and
// enter the file name here
#define kAudioFileName "drumLoop"
// The preview audio file format.
// To add your own custom audio file (for standalone effects), add an audio file to the project (AUv3WrappermacOS and AUv3WrapperiOS targets) and
// enter the file format here
#define kAudioFileFormat "wav"
// componentFlags (leave at 0)
#define kAUcomponentFlags 0
// componentFlagsMask (leave at 0)
#define kAUcomponentFlagsMask 0
// class name for the application delegate
#define kAUapplicationDelegateClassName AppDelegate
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="NO" initialViewController="01J-lp-oVM">
<dependencies>
<development version="7000" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="NO" initialViewController="BYZ-38-t0r">
<dependencies>
<development version="7000" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="751" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="awX-J2-WjW">
<rect key="frame" x="154.5" y="28" width="66" height="33"/>
<constraints>
<constraint firstAttribute="width" constant="66" id="mxM-10-2ZT"/>
<constraint firstAttribute="height" constant="33" id="oes-CK-W5k"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<state key="normal" title="Play"/>
<connections>
<action selector="togglePlay:" destination="BYZ-38-t0r" eventType="touchUpInside" id="L06-Zo-ks1"/>
</connections>
</button>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="65L-bj-7ja">
<rect key="frame" x="0.0" y="69" width="375" height="598"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
</view>
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DO8-U6-Fin">
<rect key="frame" x="16" y="20" width="59" height="30"/>
<state key="normal" title="Load file"/>
<connections>
<action selector="loadFile:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Mt3-w7-QRD"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="65L-bj-7ja" firstAttribute="top" secondItem="awX-J2-WjW" secondAttribute="bottom" constant="8" id="0pm-tA-HHv"/>
<constraint firstItem="DO8-U6-Fin" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leadingMargin" id="4k9-78-uI8"/>
<constraint firstItem="65L-bj-7ja" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="8DK-Kt-1aI"/>
<constraint firstItem="DO8-U6-Fin" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="B7m-Ac-uWD"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="65L-bj-7ja" secondAttribute="bottom" id="MGd-GL-poe"/>
<constraint firstItem="awX-J2-WjW" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="cDh-8H-Wf2"/>
<constraint firstItem="awX-J2-WjW" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="8" symbolic="YES" id="pzr-zC-F3E"/>
<constraint firstAttribute="trailing" secondItem="65L-bj-7ja" secondAttribute="trailing" id="yaU-Up-alA"/>
</constraints>
</view>
<connections>
<outlet property="auContainerView" destination="65L-bj-7ja" id="wVS-br-3wc"/>
<outlet property="playButton" destination="awX-J2-WjW" id="yBe-iR-A9Z"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="301.60000000000002" y="270.31484257871068"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>AGainv3</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSAppleMusicUsageDescription</key>
<string>Import an audio file for preview</string>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>SupportedNumChannels</key>
<string>kSupportedNumChannels</string>
</dict>
</plist>
@@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/iOS/Sources/AppDelegate.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.
//-----------------------------------------------------------------------------
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@@ -0,0 +1,44 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/iOS/Sources/AppDelegate.m
// 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 "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
@end
@@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/iOS/Sources/ViewController.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.
//-----------------------------------------------------------------------------
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController <MPMediaPickerControllerDelegate>
@end
@@ -0,0 +1,142 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/iOS/Sources/ViewController.m
// 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 "ViewController.h"
#import <CoreAudioKit/AUViewController.h>
#import "public.sdk/source/vst/auv3wrapper/Shared/AUv3AudioEngine.h"
#import "public.sdk/source/vst/auv3wrapper/Shared/AUv3Wrapper.h"
@class AUv3WrapperViewController;
@interface ViewController () {
// Button for playback
IBOutlet UIButton *playButton;
// Container for our custom view.
__weak IBOutlet UIView *auContainerView;
// Audio playback engine.
AUv3AudioEngine *audioEngine;
// Container for the custom view.
AUv3WrapperViewController *auV3ViewController;
}
-(IBAction)togglePlay:(id)sender;
-(IBAction)loadFile:(id)sender;
@end
@implementation ViewController
//------------------------------------------------------------------------
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self embedPlugInView];
AudioComponentDescription desc;
desc.componentType = kAUcomponentType;
desc.componentSubType = kAUcomponentSubType;
desc.componentManufacturer = kAUcomponentManufacturer;
desc.componentFlags = kAUcomponentFlags;
desc.componentFlagsMask = kAUcomponentFlagsMask;
[AUAudioUnit registerSubclass: AUv3Wrapper.class asComponentDescription:desc name:@"Local AUv3" version: UINT32_MAX];
audioEngine = [[AUv3AudioEngine alloc] initWithComponentType:desc.componentType];
[audioEngine loadAudioUnitWithComponentDescription:desc completion:^{
auV3ViewController.audioUnit = (AUv3Wrapper*)audioEngine.currentAudioUnit;
NSString* fileName = @kAudioFileName;
NSString* fileFormat = @kAudioFileFormat;
NSURL* fileURL = [[NSBundle mainBundle] URLForResource:fileName withExtension:fileFormat];
NSError* error = [audioEngine loadAudioFile:fileURL];
if (error)
{
NSLog (@"Error setting up audio or midi file: %@", [error description]);
}
}];
}
//------------------------------------------------------------------------
- (void)embedPlugInView {
NSURL *builtInPlugInURL = [[NSBundle mainBundle] builtInPlugInsURL];
NSURL *pluginURL = [builtInPlugInURL URLByAppendingPathComponent: @"AUv3WrapperiOSExtension.appex"];
NSBundle *appExtensionBundle = [NSBundle bundleWithURL: pluginURL];
auV3ViewController = [[AUv3WrapperViewController alloc] initWithNibName: @"AUv3WrapperViewController" bundle: appExtensionBundle];
// Present the view controller's view.
UIView *view = auV3ViewController.view;
view.frame = auContainerView.bounds;
[auContainerView addSubview: view];
view.translatesAutoresizingMaskIntoConstraints = NO;
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)];
[auContainerView addConstraints: constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)];
[auContainerView addConstraints: constraints];
}
//------------------------------------------------------------------------
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//------------------------------------------------------------------------
-(IBAction)loadFile:(id)sender {
MPMediaPickerController *soundPicker=[[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeAnyAudio];
soundPicker.delegate=self;
soundPicker.allowsPickingMultipleItems=NO; // You can set it to yes for multiple selection
[self presentViewController:soundPicker animated:YES completion:nil];
}
//------------------------------------------------------------------------
-(void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:
(MPMediaItemCollection *)mediaItemCollection
{
MPMediaItem *item = [[mediaItemCollection items] objectAtIndex:0]; // For multiple you can iterate iTems array
NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL];
[mediaPicker dismissViewControllerAnimated:YES completion:nil];
NSError* error = [audioEngine loadAudioFile:url];
if (error != nil)
{
NSLog(@"something went wrong");
}
}
- (void) mediaPickerDidCancel: (MPMediaPickerController *) mediaPicker
{
[mediaPicker dismissViewControllerAnimated:YES completion:nil];
}
//------------------------------------------------------------------------
-(IBAction)togglePlay:(id)sender {
BOOL isPlaying = [audioEngine startStop];
[playButton setTitle: isPlaying ? @"Stop" : @"Play" forState: UIControlStateNormal];
}
@end
@@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/iOS/Sources/main.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 <UIKit/UIKit.h>
#import "AppDelegate.h"
int main (int argc, char* argv[])
{
@autoreleasepool
{
return UIApplicationMain (argc, argv, nil, NSStringFromClass ([AppDelegate class]));
}
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>
@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="AUv3App" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="AUv3App" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About AUV3App" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide AUV3App" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit AUV3App" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" tag="123" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="AUv3LFO2 Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</application>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="0.0"/>
</scene>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="0.0" y="757" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="j2h-An-kEE"/>
</connections>
</window>
<connections>
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="250"/>
</scene>
<!--View Controller-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController">
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="480" height="364"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kkG-5b-ojC">
<rect key="frame" x="207" y="316" width="66" height="32"/>
<buttonCell key="cell" type="push" title="Play" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="gCD-Et-Q6x">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="togglePlay:" target="XfG-lQ-9wD" id="oSe-db-zgP"/>
</connections>
</button>
<customView wantsLayer="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6J0-ZM-W9c">
<rect key="frame" x="0.0" y="0.0" width="480" height="323"/>
</customView>
</subviews>
<constraints>
<constraint firstItem="kkG-5b-ojC" firstAttribute="centerX" secondItem="m2S-Jp-Qdl" secondAttribute="centerX" id="5h0-Ry-y2J"/>
<constraint firstItem="kkG-5b-ojC" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="20" id="J8K-Ne-pVq"/>
<constraint firstItem="6J0-ZM-W9c" firstAttribute="top" secondItem="kkG-5b-ojC" secondAttribute="bottom" id="RAO-aF-aJn"/>
<constraint firstItem="6J0-ZM-W9c" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="bHR-tH-jff"/>
<constraint firstAttribute="trailing" secondItem="6J0-ZM-W9c" secondAttribute="trailing" id="d6h-Oq-iH2"/>
<constraint firstAttribute="bottom" secondItem="6J0-ZM-W9c" secondAttribute="bottom" id="jg2-r2-1A9"/>
</constraints>
</view>
<connections>
<outlet property="containerView" destination="6J0-ZM-W9c" id="j60-iC-0OX"/>
<outlet property="playButton" destination="kkG-5b-ojC" id="lCN-dZ-Vtx"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="702"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string>again</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2024 Steinberg Media Technologies. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SupportedNumChannels</key>
<string>kSupportedNumChannels</string>
</dict>
</plist>
@@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/macOS/Sources/AppDelegate.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.
//-----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end
@@ -0,0 +1,32 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/macOS/Sources/AppDelegate.m
// 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 "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
@end
@@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/macOS/Sources/ViewController.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.
//-----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
@interface ViewController : NSViewController <NSWindowDelegate>
@end
@@ -0,0 +1,164 @@
//-----------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Helpers
// Filename : public.sdk/samples/vst/again_auv3/macOS/Sources/ViewController.m
// 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 "ViewController.h"
#import <CoreAudioKit/AUViewController.h>
#import "public.sdk/source/vst/auv3wrapper/Shared/AUv3AudioEngine.h"
#import "public.sdk/source/vst/auv3wrapper/Shared/AUv3Wrapper.h"
@class AUv3WrapperViewController;
@interface ViewController ()
{
// Button for playback
IBOutlet NSButton* playButton;
AUv3AudioEngine* audioEngine;
// Container for the custom view.
AUv3WrapperViewController* auV3ViewController;
}
@property IBOutlet NSView *containerView;
-(IBAction)togglePlay:(id)sender;
-(void)handleMenuSelection:(id)sender;
@end
@implementation ViewController
//------------------------------------------------------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self embedPlugInView];
AudioComponentDescription desc;
desc.componentType = kAUcomponentType;
desc.componentSubType = kAUcomponentSubType;
desc.componentManufacturer = kAUcomponentManufacturer;
desc.componentFlags = kAUcomponentFlags;
desc.componentFlagsMask = kAUcomponentFlagsMask;
if (desc.componentType == 'aufx' || desc.componentType == 'aumf')
[self addFileMenuEntry];
[AUAudioUnit registerSubclass: AUv3Wrapper.class asComponentDescription:desc name:@"Local AUv3" version: UINT32_MAX];
audioEngine = [[AUv3AudioEngine alloc] initWithComponentType:desc.componentType];
[audioEngine loadAudioUnitWithComponentDescription:desc completion:^{
auV3ViewController.audioUnit = (AUv3Wrapper*)audioEngine.currentAudioUnit;
NSString* fileName = @kAudioFileName;
NSString* fileFormat = @kAudioFileFormat;
NSURL* fileURL = [[NSBundle mainBundle] URLForResource:fileName withExtension:fileFormat];
NSError* error = [audioEngine loadAudioFile:fileURL];
if (error)
{
NSLog (@"Error setting up audio or midi file: %@", [error description]);
}
}];
}
//------------------------------------------------------------------------
- (void)embedPlugInView
{
NSURL *builtInPlugInURL = [[NSBundle mainBundle] builtInPlugInsURL];
NSURL *pluginURL = [builtInPlugInURL URLByAppendingPathComponent: @"vst3plugin.appex"];
NSBundle *appExtensionBundle = [NSBundle bundleWithURL: pluginURL];
auV3ViewController = [[AUv3WrapperViewController alloc] initWithNibName: @"AUv3WrapperViewController" bundle: appExtensionBundle];
// Present the view controller's view.
NSView *view = auV3ViewController.view;
view.frame = _containerView.bounds;
[_containerView addSubview: view];
view.translatesAutoresizingMaskIntoConstraints = NO;
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)];
[_containerView addConstraints: constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)];
[_containerView addConstraints: constraints];
}
//------------------------------------------------------------------------
-(void)addFileMenuEntry
{
NSApplication *app = [NSApplication sharedApplication];
NSMenu *fileMenu = [[app.mainMenu itemWithTag:123] submenu];
NSMenuItem *openFileItem = [[NSMenuItem alloc] initWithTitle:@"Load file..."
action:@selector(handleMenuSelection:)
keyEquivalent:@"O"];
[fileMenu insertItem:openFileItem atIndex:0];
}
//------------------------------------------------------------------------
-(void)handleMenuSelection:(NSMenuItem *)sender
{
// create the open dialog
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
openPanel.title = @"Choose an audio file";
openPanel.showsResizeIndicator = YES;
openPanel.canChooseFiles = YES;
openPanel.allowsMultipleSelection = NO;
openPanel.canChooseDirectories = NO;
openPanel.canCreateDirectories = YES;
openPanel.allowedFileTypes = @[@"aac", @"aif", @"aiff", @"caf", @"m4a", @"mp3", @"wav"];
if ( [openPanel runModal] == NSModalResponseOK )
{
NSArray* urls = [openPanel URLs];
// Loop through all the files and process them.
for(int i = 0; i < [urls count]; i++ )
{
NSError* error = [audioEngine loadAudioFile:[urls objectAtIndex:i]];
if (error != nil)
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Error loading file"];
[alert setInformativeText:@"Something went wrong loading the audio file. Please make sure to select the correct format and try again."];
[alert addButtonWithTitle:@"Ok"];
[alert runModal];
}
}
}
}
//------------------------------------------------------------------------
-(IBAction)togglePlay:(id)sender
{
BOOL isPlaying = [audioEngine startStop];
[playButton setTitle: isPlaying ? @"Stop" : @"Play"];
}
#pragma mark <NSWindowDelegate>
//------------------------------------------------------------------------
- (void)windowWillClose:(NSNotification *)notification
{
// Main applicaiton window closing, we're done
auV3ViewController = nil;
}
@end
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-again-sampleaccurate
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 AGain example"
)
smtg_add_vst3plugin(again-sample-accurate
source/agsa_controller.cpp
source/agsa_factory.cpp
source/agsa_processor.cpp
source/agsa.h
source/tutorial.cpp
source/tutorial.h
source/version.h
${SDK_ROOT}/public.sdk/source/vst/utility/test/sampleaccuratetest.cpp
${SDK_ROOT}/public.sdk/source/vst/utility/test/rttransfertest.cpp
)
target_link_libraries(again-sample-accurate
PRIVATE
sdk_hosting
)
smtg_target_setup_as_vst3_example(again-sample-accurate)
@@ -0,0 +1,18 @@
# AGain Sample Accurate
## Introduction
AGain Sample Accurate is the variant of the AGain FX plug-in showing how to achieve sample-accurate processing for the gain value.
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#again-sample-accurate).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,46 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa.h
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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
#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/vst/vsttypes.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
static const FUID ProcessorID (0xC18D3C1E, 0x719E4E29, 0x924D3ECA, 0xA5E4DA18);
static const FUID ControllerID (0xC244B7E6, 0x24084E20, 0xA24A8C43, 0xF84C8BE8);
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*);
FUnknown* createControllerInstance (void*);
//------------------------------------------------------------------------
enum ParameterID : ParamID
{
Bypass,
Gain,
};
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,92 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_controller.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "base/source/fstreamer.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
class Controller : public EditController
{
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
};
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::initialize (FUnknown* context)
{
tresult result = EditController::initialize (context);
if (result != kResultOk)
{
return result;
}
parameters.addParameter (STR ("Bypass"), nullptr, 1, 0.,
ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass,
ParameterID::Bypass);
parameters.addParameter (STR ("Gain"), STR ("%"), 0, 1., ParameterInfo::kCanAutomate,
ParameterID::Gain);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::terminate ()
{
return EditController::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::setComponentState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
uint32 numParams;
if (streamer.readInt32u (numParams) == false)
return kResultFalse;
ParamID pid;
ParamValue value;
for (uint32 i = 0u; i < numParams; ++i)
{
if (!streamer.readInt32u (pid))
break;
if (!streamer.readDouble (value))
break;
if (auto param = parameters.getParameter (pid))
param->setNormalized (value);
}
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createControllerInstance (void*)
{
return static_cast<IEditController*> (new Controller);
}
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,60 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_factory.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.h"
#include "tutorial.h"
#include "version.h"
#include "public.sdk/source/main/pluginfactory.h"
#include "public.sdk/source/vst/utility/testing.h"
#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"
#define stringPluginName "AGain Sample Accurate"
using namespace Steinberg;
using namespace Steinberg::Vst;
using namespace Steinberg::Vst::AgainSampleAccurate;
//------------------------------------------------------------------------
// VST Plug-in Factory
//------------------------------------------------------------------------
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail)
// AGain sample accurate
DEF_CLASS2 (INLINE_UID_FROM_FUID (ProcessorID), PClassInfo::kManyInstances, kVstAudioEffectClass,
stringPluginName, Vst::kDistributable, "Fx", FULL_VERSION_STR, kVstVersionString,
createProcessorInstance)
DEF_CLASS2 (INLINE_UID_FROM_FUID (ControllerID), PClassInfo::kManyInstances,
kVstComponentControllerClass, stringPluginName "Controller", 0, "", FULL_VERSION_STR,
kVstVersionString, createControllerInstance)
// Test
DEF_CLASS2 (INLINE_UID_FROM_FUID (getTestFactoryUID ()), PClassInfo::kManyInstances, kTestClass,
stringPluginName "Test Factory", 0, "", "", "", createTestFactoryInstance)
// Tutorial
DEF_CLASS2 (INLINE_UID_FROM_FUID (Tutorial::ProcessorID), PClassInfo::kManyInstances,
kVstAudioEffectClass, "Advanced Tutorial", Vst::kDistributable, "Fx", FULL_VERSION_STR,
kVstVersionString, Tutorial::createProcessorInstance)
DEF_CLASS2 (INLINE_UID_FROM_FUID (Tutorial::ControllerID), PClassInfo::kManyInstances,
kVstComponentControllerClass, "Advanced Tutorial Controller", 0, "", FULL_VERSION_STR,
kVstVersionString, Tutorial::createControllerInstance)
END_FACTORY
@@ -0,0 +1,264 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_processor.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.h"
#include "public.sdk/source/vst/utility/audiobuffers.h"
#include "public.sdk/source/vst/utility/processdataslicer.h"
#include "public.sdk/source/vst/utility/rttransfer.h"
#include "public.sdk/source/vst/utility/sampleaccurate.h"
#include "public.sdk/source/vst/vstaudioeffect.h"
#include "base/source/fstreamer.h"
#include <array>
#include <cassert>
#include <limits>
#include <vector>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
struct Processor : public AudioEffect
{
using ParameterVector = std::vector<std::pair<ParamID, ParamValue>>;
using RTTransfer = RTTransferT<ParameterVector>;
Processor ();
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) SMTG_OVERRIDE;
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
void handleParameterChanges (IParameterChanges* changes);
template <SymbolicSampleSizes SampleSize>
void process (ProcessData& data);
std::array<SampleAccurate::Parameter, 2> parameters;
RTTransfer stateTransfer;
};
//------------------------------------------------------------------------
Processor::Processor ()
{
setControllerClass (ControllerID);
parameters[0].setParamID (ParameterID::Bypass);
parameters[1].setParamID (ParameterID::Gain);
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::initialize (FUnknown* context)
{
auto result = AudioEffect::initialize (context);
if (result == kResultTrue)
{
addAudioInput (STR ("Input"), SpeakerArr::kStereo);
addAudioOutput (STR ("Output"), SpeakerArr::kStereo);
}
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::terminate ()
{
stateTransfer.clear_ui ();
return AudioEffect::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::setState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
uint32 numParams;
if (streamer.readInt32u (numParams) == false)
return kResultFalse;
auto paramChanges = std::make_unique<ParameterVector> ();
ParamID pid;
ParamValue value;
for (uint32 i = 0u; i < numParams; ++i)
{
if (!streamer.readInt32u (pid))
break;
if (!streamer.readDouble (value))
break;
for (auto& param : parameters)
{
if (param.getParamID () == pid)
{
paramChanges->emplace_back (std::make_pair (pid, value));
break;
}
}
}
stateTransfer.transferObject_ui (std::move (paramChanges));
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::getState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
streamer.writeInt32u (static_cast<uint32> (parameters.size ()));
for (auto& param : parameters)
{
streamer.writeInt32u (param.getParamID ());
streamer.writeDouble (param.getValue ());
}
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs, int32 numOuts)
{
if (numIns != 1 || numOuts != 1)
return kResultFalse;
if (SpeakerArr::getChannelCount (inputs[0]) == SpeakerArr::getChannelCount (outputs[0]))
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioOutput (0)->setArrangement (outputs[0]);
return kResultTrue;
}
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::canProcessSampleSize (int32 symbolicSampleSize)
{
return (symbolicSampleSize == SymbolicSampleSizes::kSample32 ||
symbolicSampleSize == SymbolicSampleSizes::kSample64) ?
kResultTrue :
kResultFalse;
}
//------------------------------------------------------------------------
template <SymbolicSampleSizes SampleSize>
void Processor::process (ProcessData& data)
{
using SampleT = typename std::conditional<SampleSize == SymbolicSampleSizes::kSample32, float,
double>::type;
static constexpr auto SliceSize = 16u;
ProcessDataSlicer slicer (SliceSize);
std::array<SampleT, SliceSize> againValueBuffer;
auto doProcessing = [this, &againValueBuffer] (ProcessData& data) {
parameters[ParameterID::Bypass].advance (data.numSamples);
auto inputs = data.inputs;
auto outputs = data.outputs;
if (parameters[ParameterID::Bypass].getValue () > 0.5)
{
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
{
auto inChannelBuffer = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
auto outChannelBuffer = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
{
outChannelBuffer[sampleIndex] = inChannelBuffer[sampleIndex];
}
}
return;
}
for (auto i = 0; i < data.numSamples; ++i)
againValueBuffer[i] = static_cast<SampleT> (parameters[ParameterID::Gain].advance (1));
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
{
auto inChannelBuffer = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
auto outChannelBuffer = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
{
auto sample = inChannelBuffer[sampleIndex] * againValueBuffer[sampleIndex];
outChannelBuffer[sampleIndex] = sample;
}
}
};
slicer.process<SampleSize> (data, doProcessing);
}
//------------------------------------------------------------------------
void Processor::handleParameterChanges (IParameterChanges* changes)
{
if (changes)
{
auto changeCount = changes->getParameterCount ();
for (auto i = 0; i < changeCount; ++i)
{
if (auto queue = changes->getParameterData (i))
{
auto paramID = queue->getParameterId ();
if (paramID >= ParameterID::Bypass && paramID <= ParameterID::Gain)
parameters[paramID].beginChanges (queue);
}
}
}
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::process (ProcessData& data)
{
stateTransfer.accessTransferObject_rt ([this] (const auto& stateChanges) {
for (const auto& change : stateChanges)
{
if (change.first >= ParameterID::Bypass && change.first <= ParameterID::Gain)
parameters[change.first].setValue (change.second);
}
});
handleParameterChanges (data.inputParameterChanges);
if (data.numSamples > 0)
{
if (processSetup.symbolicSampleSize == SymbolicSampleSizes::kSample32)
process<SymbolicSampleSizes::kSample32> (data);
else
process<SymbolicSampleSizes::kSample64> (data);
}
for (auto& param : parameters)
param.endChanges ();
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*)
{
return static_cast<IAudioProcessor*> (new Processor);
}
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,273 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/tutorial.cpp
// Created by : Steinberg, 04/2021
// Description : Tutorial
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "tutorial.h"
#include "public.sdk/source/vst/utility/audiobuffers.h"
#include "public.sdk/source/vst/utility/processdataslicer.h"
#include "public.sdk/source/vst/utility/rttransfer.h"
#include "public.sdk/source/vst/utility/sampleaccurate.h"
#include "public.sdk/source/vst/vstaudioeffect.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "base/source/fstreamer.h"
#include <array>
#include <cassert>
#include <limits>
#include <vector>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace Tutorial {
//------------------------------------------------------------------------
enum ParameterID
{
Gain = 1,
};
//------------------------------------------------------------------------
struct StateModel
{
double gain;
};
//------------------------------------------------------------------------
struct MyEffect : public AudioEffect
{
using RTTransfer = RTTransferT<StateModel>;
MyEffect ();
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs,
int32 numOuts) SMTG_OVERRIDE;
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) SMTG_OVERRIDE;
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
void handleParameterChanges (IParameterChanges* changes);
template <SymbolicSampleSizes SampleSize>
void process (ProcessData& data);
SampleAccurate::Parameter gainParameter {ParameterID::Gain, 1.};
RTTransfer stateTransfer;
};
//------------------------------------------------------------------------
MyEffect::MyEffect ()
{
setControllerClass (ControllerID);
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::initialize (FUnknown* context)
{
auto result = AudioEffect::initialize (context);
if (result == kResultTrue)
{
addAudioInput (STR ("Input"), SpeakerArr::kStereo);
addAudioOutput (STR ("Output"), SpeakerArr::kStereo);
}
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::terminate ()
{
stateTransfer.clear_ui ();
return AudioEffect::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::setState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
uint32 numParams;
if (streamer.readInt32u (numParams) == false)
return kResultFalse;
auto model = std::make_unique<StateModel> ();
ParamValue value;
if (!streamer.readDouble (value))
return kResultFalse;
model->gain = value;
stateTransfer.transferObject_ui (std::move (model));
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::getState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
streamer.writeDouble (gainParameter.getValue ());
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
SpeakerArrangement* outputs, int32 numOuts)
{
if (numIns != 1 || numOuts != 1)
return kResultFalse;
if (SpeakerArr::getChannelCount (inputs[0]) == SpeakerArr::getChannelCount (outputs[0]))
{
getAudioInput (0)->setArrangement (inputs[0]);
getAudioOutput (0)->setArrangement (outputs[0]);
return kResultTrue;
}
return kResultFalse;
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::canProcessSampleSize (int32 symbolicSampleSize)
{
return (symbolicSampleSize == SymbolicSampleSizes::kSample32 ||
symbolicSampleSize == SymbolicSampleSizes::kSample64) ?
kResultTrue :
kResultFalse;
}
//------------------------------------------------------------------------
template <SymbolicSampleSizes SampleSize>
void MyEffect::process (ProcessData& data)
{
ProcessDataSlicer slicer (8);
auto doProcessing = [this] (ProcessData& data) {
// get the gain value for this block
ParamValue gain = gainParameter.advance (data.numSamples);
// process audio
AudioBusBuffers* inputs = data.inputs;
AudioBusBuffers* outputs = data.outputs;
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
{
auto inputBuffers = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
auto outputBuffers = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
{
auto sample = inputBuffers[sampleIndex];
outputBuffers[sampleIndex] = sample * gain;
}
}
};
slicer.process<SampleSize> (data, doProcessing);
}
//------------------------------------------------------------------------
void MyEffect::handleParameterChanges (IParameterChanges* changes)
{
if (!changes)
return;
int32 changeCount = changes->getParameterCount ();
for (auto i = 0; i < changeCount; ++i)
{
if (auto queue = changes->getParameterData (i))
{
auto paramID = queue->getParameterId ();
if (paramID == ParameterID::Gain)
{
gainParameter.beginChanges (queue);
}
}
}
}
//------------------------------------------------------------------------
tresult PLUGIN_API MyEffect::process (ProcessData& data)
{
stateTransfer.accessTransferObject_rt (
[this] (const auto& stateModel) { gainParameter.setValue (stateModel.gain); });
handleParameterChanges (data.inputParameterChanges);
if (processSetup.symbolicSampleSize == SymbolicSampleSizes::kSample32)
process<SymbolicSampleSizes::kSample32> (data);
else
process<SymbolicSampleSizes::kSample64> (data);
gainParameter.endChanges ();
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*)
{
return static_cast<IAudioProcessor*> (new MyEffect);
}
//------------------------------------------------------------------------
class Controller : public EditController
{
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
};
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::initialize (FUnknown* context)
{
tresult result = EditController::initialize (context);
if (result != kResultOk)
{
return result;
}
parameters.addParameter (STR ("Gain"), STR ("%"), 0, 1., ParameterInfo::kCanAutomate,
ParameterID::Gain);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::setComponentState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
ParamValue value;
if (!streamer.readDouble (value))
return kResultFalse;
if (auto param = parameters.getParameter (ParameterID::Gain))
param->setNormalized (value);
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createControllerInstance (void*)
{
return static_cast<IEditController*> (new Controller);
}
//------------------------------------------------------------------------
} // Tutorial
} // Vst
} // Steinberg
@@ -0,0 +1,39 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/tutorial.h
// Created by : Steinberg, 04/2021
// Description : Tutorial
//
//-----------------------------------------------------------------------------
// 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
#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/vst/vsttypes.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace Tutorial {
//------------------------------------------------------------------------
static const FUID ProcessorID (0xCC48BF25, 0x529043DA, 0x80223510, 0xFFE8BD02);
static const FUID ControllerID (0x3A89B2B2, 0x4F474E02, 0x9C96EE27, 0x0AD2A15B);
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*);
FUnknown* createControllerInstance (void*);
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/version.h
// Created by : Steinberg, 04/2021
// Description : Example of handle the versioning and copyright info of again sampleaccurate plug-in
// used for the resources (RC file for example)
//
//-----------------------------------------------------------------------------
// 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
#include "pluginterfaces/base/fplatform.h"
// Plain project version file generated by cmake
#include "projectversion.h"
#define stringOriginalFilename "again_sampleaccurate.vst3"
#if SMTG_PLATFORM_64
#define stringFileDescription "AGain SampleAccurate VST3-SDK (64Bit)"
#else
#define stringFileDescription "AGain SampleAccurate VST3-SDK"
#endif
#define stringCompanyWeb "http://www.steinberg.net"
#define stringCompanyEmail "mailto:info@steinberg.de"
#define stringCompanyName "Steinberg Media Technologies"
#define stringLegalCopyright "© 2025 Steinberg Media Technologies"
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-channelcontext
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 Channel Context example"
)
smtg_add_vst3plugin(channel-context
source/plug.cpp
source/plug.h
source/plugcids.h
source/plugcontroller.cpp
source/plugcontroller.h
source/plugentry.cpp
source/plugparamids.h
source/version.h
)
smtg_target_setup_as_vst3_example(channel-context)
@@ -0,0 +1,18 @@
# Test Channel Context
## Introduction
**Test Channel Context** is simple FX plug-in showing how to use the [Steinberg::Vst::ChannelContext::IInfoListener](https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Change+History/3.6.5/IInfoListener.html) interface.
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#testchannelcontext).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,216 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/channelcontext/source/plug.cpp
// Created by : Steinberg, 02/2014
// Description : Plug Example for VST SDK 3.x
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "plug.h"
#include "plugparamids.h"
#include "plugcids.h" // for class ids
#include "public.sdk/source/vst/vstaudioprocessoralgo.h"
#include "pluginterfaces/base/futils.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include "base/source/fstreamer.h"
#include <cstdio>
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// Plug Implementation
//------------------------------------------------------------------------
Plug::Plug ()
: bBypass (false)
{
// register its editor class (the same than used in plugentry.cpp)
setControllerClass (PlugControllerUID);
}
//------------------------------------------------------------------------
tresult PLUGIN_API Plug::initialize (FUnknown* context)
{
//---always initialize the parent-------
tresult result = AudioEffect::initialize (context);
// if everything Ok, continue
if (result != kResultOk)
{
return result;
}
//---create Audio In/Out busses------
// we want a stereo Input and a Stereo Output
addAudioInput (STR16 ("Stereo In"), SpeakerArr::kStereo);
addAudioOutput (STR16 ("Stereo Out"), SpeakerArr::kStereo);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Plug::process (ProcessData& data)
{
//---1) Read inputs parameter changes-----------
if (IParameterChanges* paramChanges = data.inputParameterChanges)
{
int32 numParamsChanged = paramChanges->getParameterCount ();
// for each parameter which are some changes in this audio block:
for (int32 i = 0; i < numParamsChanged; i++)
{
if (IParamValueQueue* paramQueue = paramChanges->getParameterData (i))
{
int32 offsetSamples;
double value;
int32 numPoints = paramQueue->getPointCount ();
switch (paramQueue->getParameterId ())
{
case kBypassId:
if (paramQueue->getPoint (numPoints - 1, offsetSamples, value) == kResultTrue)
{
bBypass = (value > 0.5f);
}
break;
}
}
}
}
//-------------------------------------
//---3) Process Audio---------------------
//-------------------------------------
if (data.numInputs == 0 || data.numOutputs == 0)
{
// nothing to do
return kResultOk;
}
// (simplification) we suppose in this example that we have the same input channel count than
// the output
int32 numChannels = Min (data.inputs[0].numChannels, data.outputs[0].numChannels);
//---get audio buffers----------------
float** in = data.inputs[0].channelBuffers32;
float** out = data.outputs[0].channelBuffers32;
// check if all channel are silent then process silent
if (data.inputs[0].silenceFlags == getChannelMask (data.inputs[0].numChannels))
{
// mark output silence too
data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
int32 sampleFrames = data.numSamples;
// the plug-in has to be sure that if it sets the flags silence that the output buffer are
// clear
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be cleared if the buffers are the same (in this case input buffer are
// already cleared by the host)
if (in[i] != out[i])
{
memset (out[i], 0, sampleFrames * sizeof (float));
}
}
// nothing to do at this point
return kResultOk;
}
// mark our outputs has not silent
data.outputs[0].silenceFlags = 0;
//---in bypass mode outputs should be like inputs-----
if (bBypass)
{
int32 sampleFrames = data.numSamples;
for (int32 i = 0; i < numChannels; i++)
{
// do not need to be copied if the buffers are the same
if (in[i] != out[i])
{
memcpy (out[i], in[i], sampleFrames * sizeof (float));
}
}
for (int32 i = numChannels; i < data.outputs[0].numChannels; i++)
{
memset (out[i], 0, sizeof (float)* data.numSamples);
}
}
else
{
float gain = 0.5;
// in real plug-in it would be better to do dezippering to avoid jump (click) in gain value
for (int32 i = 0; i < numChannels; i++)
{
int32 sampleFrames = data.numSamples;
float* ptrIn = in[i];
float* ptrOut = out[i];
float tmp;
while (--sampleFrames >= 0)
{
// apply gain
tmp = (*ptrIn++) * gain;
(*ptrOut++) = tmp;
}
}
for (int32 i = numChannels; i < data.outputs[0].numChannels; i++)
{
memset (out[i], 0, sizeof (float)* data.numSamples);
}
}
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Plug::setState (IBStream* state)
{
// called when we load a preset, the model has to be reloaded
if (!state)
return kResultFalse;
IBStreamer streamer (state, kLittleEndian);
// read the bypass
int32 savedBypass = 0;
if (streamer.readInt32 (savedBypass) == false)
return kResultFalse;
bBypass = savedBypass > 0;
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Plug::getState (IBStream* state)
{
// here we need to save the model
if (!state)
return kResultFalse;
IBStreamer streamer (state, kLittleEndian);
streamer.writeInt32 (bBypass ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,58 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/channelcontext/source/plug.h
// Created by : Steinberg, 02/2014
// Description : Plug-in Example for VST SDK 3.x using ChannelContext::IInfoListener
//
//-----------------------------------------------------------------------------
// 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
#include "public.sdk/source/vst/vstaudioeffect.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// Plug: directly derived from the helper class AudioEffect
//------------------------------------------------------------------------
class Plug : public AudioEffect
{
public:
Plug ();
//--- ---------------------------------------------------------------------
// create function required for plug-in factory,
// it will be called to create new instances of this plug-in
//--- ---------------------------------------------------------------------
static FUnknown* createInstance (void* /*context*/) { return (IAudioProcessor*)new Plug; }
//--- ---------------------------------------------------------------------
// AudioEffect overrides:
//--- ---------------------------------------------------------------------
/** Called at first after constructor */
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
/** Here we go...the process call */
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
/** For persistence */
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
//------------------------------------------------------------------------
protected:
bool bBypass;
};
//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg
@@ -0,0 +1,25 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/channelcontext/source/plugcids.h
// Created by : Steinberg, 02/2014
// Description : define the class IDs for channelcontext
//
//-----------------------------------------------------------------------------
// 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
namespace Steinberg {
namespace Vst {
// Plug A
static const FUID PlugProcessorUID (0x01EDEBE8, 0x8CD14564, 0xAF34B1A2, 0xDDC13384);
static const FUID PlugControllerUID(0xB4D97900, 0xAAC84AAE, 0xB9D1C427, 0xB77A698B);
}} // namespaces
@@ -0,0 +1,293 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/channelcontext/source/PlugController.cpp
// Created by : Steinberg, 02/2014
// Description : Plug Controller Example for VST SDK 3.x
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "plugcontroller.h"
#include "plugparamids.h"
#include "pluginterfaces/base/ibstream.h"
#include "pluginterfaces/base/ustring.h"
#include "base/source/fstreamer.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// PlugController Implementation
//------------------------------------------------------------------------
tresult PLUGIN_API PlugController::initialize (FUnknown* context)
{
tresult result = EditControllerEx1::initialize (context);
if (result != kResultOk)
{
return result;
}
//---Create Parameters------------
//---Bypass parameter---
int32 stepCount = 1;
ParamValue defaultVal = 0;
int32 flags = ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass;
int32 tag = kBypassId;
parameters.addParameter (STR16 ("Bypass"), nullptr, stepCount, defaultVal, flags, tag);
//---Read only parameters
String128 undefinedStr;
Steinberg::UString (undefinedStr, 128).fromAscii ("undefined");
flags = ParameterInfo::kIsReadOnly;
auto* strParam = NEW StringListParameter (STR16 ("Ch Uid"), kChannelUIDId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Uid Len"), kChannelUIDLengthId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Name"), kChannelNameId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Name Len"), kChannelNameLengthId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Index"), kChannelIndexId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam =
NEW StringListParameter (STR16 ("Ch Index Namespace Order"), kChannelIndexNamespaceOrderId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam =
NEW StringListParameter (STR16 ("Ch Index Namespace"), kChannelIndexNamespaceId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Index Namespace Len"),
kChannelIndexNamespaceLengthId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Color"), kChannelColorId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
strParam = NEW StringListParameter (STR16 ("Ch Plug Loc."), kChannelPluginLocationId, nullptr, flags);
strParam->appendString (undefinedStr);
parameters.addParameter (strParam);
return result;
}
//------------------------------------------------------------------------
tresult PLUGIN_API PlugController::setComponentState (IBStream* state)
{
// we receive the current state of the component (processor part)
// we read only the gain and bypass value...
if (!state)
return kResultFalse;
IBStreamer streamer (state, kLittleEndian);
// read the bypass
int32 bypassState = 0;
if (streamer.readInt32 (bypassState) == false)
return kResultFalse;
setParamNormalized (kBypassId, bypassState ? 1 : 0);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API PlugController::setChannelContextInfos (IAttributeList* list)
{
if (!list)
return kResultFalse;
String128 undefinedStr;
Steinberg::UString (undefinedStr, 128).fromAscii ("undefined");
// get the channel name length (optional) where we, as plugin, are instantiated
auto* param =
static_cast<StringListParameter*> (parameters.getParameter (kChannelNameLengthId));
if (param)
{
int64 length;
if (list->getInt (ChannelContext::kChannelNameLengthKey, length) == kResultTrue)
{
String128 string128;
Steinberg::UString (string128, 128).printInt (length);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get the channel name where we, as plugin, are instantiated
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelNameId));
if (param)
{
String128 name;
if (list->getString (ChannelContext::kChannelNameKey, name, sizeof (name)) == kResultTrue)
param->replaceString (0, name);
else
param->replaceString (0, undefinedStr);
}
// get the channel UID Length
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelUIDLengthId));
if (param)
{
int64 length;
if (list->getInt (ChannelContext::kChannelUIDLengthKey, length) == kResultTrue)
{
String128 string128;
Steinberg::UString (string128, 128).printInt (length);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get the channel UID
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelUIDId));
if (param)
{
String128 name;
if (list->getString (ChannelContext::kChannelUIDKey, name, sizeof (name)) == kResultTrue)
param->replaceString (0, name);
else
param->replaceString (0, undefinedStr);
}
// get Channel Index
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelIndexId));
if (param)
{
int64 index;
if (list->getInt (ChannelContext::kChannelIndexKey, index) == kResultTrue)
{
String128 string128;
Steinberg::UString (string128, 128).printInt (index);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get Channel Index Namespace Order
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelIndexNamespaceOrderId));
if (param)
{
int64 index;
if (list->getInt (ChannelContext::kChannelIndexNamespaceOrderKey, index) == kResultTrue)
{
String128 string128;
Steinberg::UString (string128, 128).printInt (index);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get the channel Index Namespace Length
param = static_cast<StringListParameter*> (
parameters.getParameter (kChannelIndexNamespaceLengthId));
if (param)
{
int64 length;
if (list->getInt (ChannelContext::kChannelIndexNamespaceLengthKey, length) == kResultTrue)
{
String128 string128;
Steinberg::UString (string128, 128).printInt (length);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get the channel Index Namespace
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelIndexNamespaceId));
if (param)
{
String128 name;
if (list->getString (ChannelContext::kChannelIndexNamespaceKey, name, sizeof (name)) ==
kResultTrue)
param->replaceString (0, name);
else
param->replaceString (0, undefinedStr);
}
// get plug-in Channel Location
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelPluginLocationId));
if (param)
{
int64 location;
if (list->getInt (ChannelContext::kChannelPluginLocationKey, location) == kResultTrue)
{
String128 string128;
switch (location)
{
case ChannelContext::kPreVolumeFader:
Steinberg::UString (string128, 128).fromAscii ("PreVolFader");
break;
case ChannelContext::kPostVolumeFader:
Steinberg::UString (string128, 128).fromAscii ("PostVolFader");
break;
case ChannelContext::kUsedAsPanner:
Steinberg::UString (string128, 128).fromAscii ("UsedAsPanner");
break;
default: Steinberg::UString (string128, 128).fromAscii ("unknown!"); break;
}
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// get Channel Color
param = static_cast<StringListParameter*> (parameters.getParameter (kChannelColorId));
if (param)
{
int64 color;
if (list->getInt (ChannelContext::kChannelColorKey, color) == kResultTrue)
{
uint32 channelColor = (uint32)color;
char str[10];
snprintf (str, 10, "%x%x%x%x", ChannelContext::GetAlpha (channelColor),
ChannelContext::GetRed (channelColor),
ChannelContext::GetGreen (channelColor),
ChannelContext::GetBlue (channelColor));
String128 string128;
Steinberg::UString (string128, 128).fromAscii (str);
param->replaceString (0, string128);
}
else
param->replaceString (0, undefinedStr);
}
// we have to inform the host that our strings have changed (values not)
if (componentHandler)
componentHandler->restartComponent (kParamValuesChanged);
return kResultTrue;
}
}
} // namespaces
@@ -0,0 +1,58 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/channelcontext/source/plugcontroller.h
// Created by : Steinberg, 02/2014
// Description : channelcontext Controller Example for VST SDK 3.x
//
//-----------------------------------------------------------------------------
// 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
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "pluginterfaces/vst/ivstchannelcontextinfo.h"
namespace Steinberg {
namespace Vst {
//------------------------------------------------------------------------
// PlugController
//------------------------------------------------------------------------
class PlugController : public EditControllerEx1, public ChannelContext::IInfoListener
{
public:
//------------------------------------------------------------------------
// create function required for plug-in factory,
// it will be called to create new instances of this controller
//------------------------------------------------------------------------
static FUnknown* createInstance (void* /*context*/) { return (IEditController*)new PlugController; }
//---from IPluginBase--------
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
//---from EditController-----
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
//---from ChannelContext::IInfoListener-----
tresult PLUGIN_API setChannelContextInfos (IAttributeList* list) SMTG_OVERRIDE;
//---Interface---------
OBJ_METHODS (PlugController, EditControllerEx1)
DEFINE_INTERFACES
DEF_INTERFACE (ChannelContext::IInfoListener)
END_DEFINE_INTERFACES (EditController)
DELEGATE_REFCOUNT (EditControllerEx1)
//------------------------------------------------------------------------
private:
};
}
} // namespaces

Some files were not shown because too many files have changed in this diff Show More