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,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"