1 //-----------------------------------------------------------------------------
2 // LICENSE
3 // (c) 2005-2018, Steinberg Media Technologies GmbH, All Rights Reserved
4 // (c) 2018, Guillaume Piolat (contact@auburnsounds.com)
5 //-----------------------------------------------------------------------------
6 //
7 // This Software Development Kit is licensed under the terms of the General
8 // Public License (GPL) Version 3.
9 //
10 // This source is part of the "Auburn Sounds (Guillaume Piolat) extension to the 
11 // Steinberg VST 3 Plug-in SDK".
12 //
13 // Details of that license can be found at: www.gnu.org/licenses/gpl-3.0.html
14 //
15 // Dual-licence:
16 // 
17 // The "Auburn Sounds (Guillaume Piolat) extension to the Steinberg VST 3 Plug-in
18 // SDK", hereby referred to as DPLUG:VST3, is a language translation of the VST3 
19 // SDK suitable for usage in Dplug. Any Licensee of a currently valid Steinberg 
20 // VST 3 Plug-In SDK Licensing Agreement (version 2.2.4 or ulterior, hereby referred
21 // to as the AGREEMENT), is granted by Auburn Sounds (Guillaume Piolat) a non-exclusive, 
22 // worldwide, nontransferable license during the term the AGREEMENT to use parts
23 // of DPLUG:VST3 not covered by the AGREEMENT, as if they were originally 
24 // inside the Licensed Software Developer Kit mentionned in the AGREEMENT. 
25 // Under this licence all conditions that apply to the Licensed Software Developer 
26 // Kit also apply to DPLUG:VST3.
27 //
28 //-----------------------------------------------------------------------------
29 module dplug.vst3.ivstaudioprocessor;
30 
31 version(VST3):
32 
33 import dplug.vst3.ftypes;
34 
35 // 64-bit seemingly need a slightly different ABI.
36 // The problem being that there is no direct pragma(pack) equivalent in D, would be simpler to have tool that displays the layout
37 version(Windows)
38 {
39     static if (size_t.sizeof == 8)
40     {
41         enum bool eventABIFix = true;
42     }
43     else
44         enum bool eventABIFix = false;
45 }
46 else version(OSX)
47 {
48     static if (size_t.sizeof == 8)
49     {
50         enum bool eventABIFix = true;
51     }
52     else
53         enum bool eventABIFix = false;
54 }
55 else
56     enum bool eventABIFix = true;
57 
58 immutable string kVstAudioEffectClass = "Audio Module Class";
59 
60 struct PlugType
61 {
62     static immutable:
63 
64     string kFxAnalyzer           = "Fx|Analyzer";    ///< Scope, FFT-Display, Loudness Processing...
65     string kFxDelay              = "Fx|Delay";       ///< Delay, Multi-tap Delay, Ping-Pong Delay...
66     string kFxDistortion         = "Fx|Distortion";  ///< Amp Simulator, Sub-Harmonic, SoftClipper...
67     string kFxDynamics           = "Fx|Dynamics";    ///< Compressor, Expander, Gate, Limiter, Maximizer, Tape Simulator, EnvelopeShaper...
68     string kFxEQ                 = "Fx|EQ";          ///< Equalization, Graphical EQ...
69     string kFxFilter             = "Fx|Filter";      ///< WahWah, ToneBooster, Specific Filter,...
70     string kFx                   = "Fx";             ///< others type (not categorized)
71     string kFxInstrument         = "Fx|Instrument";  ///< Fx which could be loaded as Instrument too
72     string kFxInstrumentExternal = "Fx|Instrument|External"; ///< Fx which could be loaded as Instrument too and is external (wrapped Hardware)
73     string kFxSpatial            = "Fx|Spatial";     ///< MonoToStereo, StereoEnhancer,...
74     string kFxGenerator          = "Fx|Generator";   ///< Tone Generator, Noise Generator...
75     string kFxMastering          = "Fx|Mastering";   ///< Dither, Noise Shaping,...
76     string kFxModulation         = "Fx|Modulation";  ///< Phaser, Flanger, Chorus, Tremolo, Vibrato, AutoPan, Rotary, Cloner...
77     string kFxPitchShift         = "Fx|Pitch Shift"; ///< Pitch Processing, Pitch Correction, Vocal Tuning...
78     string kFxRestoration        = "Fx|Restoration"; ///< Denoiser, Declicker,...
79     string kFxReverb             = "Fx|Reverb";      ///< Reverberation, Room Simulation, Convolution Reverb...
80     string kFxSurround           = "Fx|Surround";    ///< dedicated to surround processing: LFE Splitter, Bass Manager...
81     string kFxTools              = "Fx|Tools";       ///< Volume, Mixer, Tuner...
82     string kFxNetwork            = "Fx|Network";     ///< using Network
83 
84     string kInstrument           = "Instrument";         ///< Effect used as instrument (sound generator), not as insert
85     string kInstrumentDrum       = "Instrument|Drum";    ///< Instrument for Drum sounds
86     string kInstrumentSampler    = "Instrument|Sampler"; ///< Instrument based on Samples
87     string kInstrumentSynth      = "Instrument|Synth";   ///< Instrument based on Synthesis
88     string kInstrumentSynthSampler = "Instrument|Synth|Sampler"; ///< Instrument based on Synthesis and Samples
89     string kInstrumentExternal   = "Instrument|External";///< External Instrument (wrapped Hardware)
90 
91     string kSpatial              = "Spatial";        ///< used for SurroundPanner
92     string kSpatialFx            = "Spatial|Fx";     ///< used for SurroundPanner and as insert effect
93     string kOnlyRealTime         = "OnlyRT";         ///< indicates that it supports only realtime process call, no processing faster than realtime
94     string kOnlyOfflineProcess   = "OnlyOfflineProcess"; ///< used for Plug-in offline processing  (will not work as normal insert Plug-in)
95     string kNoOfflineProcess     = "NoOfflineProcess";   ///< will be NOT used for Plug-in offline processing (will work as normal insert Plug-in)
96     string kUpDownMix            = "Up-Downmix";     ///< used for Mixconverter/Up-Mixer/Down-Mixer
97     string kAnalyzer             = "Analyzer";       ///< Meter, Scope, FFT-Display, not selectable as insert plugin
98     string kAmbisonics           = "Ambisonics";     ///< used for Ambisonics channel (FX or Panner/Mixconverter/Up-Mixer/Down-Mixer when combined with other category)
99 
100     string kMono                 = "Mono";           ///< used for Mono only Plug-in [optional]
101     string kStereo               = "Stereo";         ///< used for Stereo only Plug-in [optional]
102     string kSurround             = "Surround";       ///< used for Surround only Plug-in [optional]
103 }
104 
105 
106 alias ComponentFlags = int;
107 enum : ComponentFlags
108 {
109     kDistributable          = 1 << 0,   ///< Component can be run on remote computer
110     kSimpleModeSupported    = 1 << 1    ///< Component supports simple IO mode (or works in simple mode anyway) see \ref vst3IoMode
111 }
112 
113 
114 // Symbolic sample size.
115 alias SymbolicSampleSizes = int;
116 enum : SymbolicSampleSizes
117 {
118     kSample32,      ///< 32-bit precision
119     kSample64       ///< 64-bit precision
120 }
121 
122 /** Processing mode informs the Plug-in about the context and at which frequency the process call is called.
123 VST3 defines 3 modes:
124 - kRealtime: each process call is called at a realtime frequency (defined by [numSamples of ProcessData] / samplerate).
125              The Plug-in should always try to process as fast as possible in order to let enough time slice to other Plug-ins.
126 - kPrefetch: each process call could be called at a variable frequency (jitter, slower / faster than realtime),
127              the Plug-in should process at the same quality level than realtime, Plug-in must not slow down to realtime
128              (e.g. disk streaming)!
129              The host should avoid to process in kPrefetch mode such sampler based Plug-in.
130 - kOffline:  each process call could be faster than realtime or slower, higher quality than realtime could be used.
131              Plug-ins using disk streaming should be sure that they have enough time in the process call for streaming,
132              if needed by slowing down to realtime or slower.
133 .
134 Note about Process Modes switching:
135     -Switching between kRealtime and kPrefetch process modes are done in realtime thread without need of calling
136      IAudioProcessor::setupProcessing, the Plug-in should check in process call the member processMode of ProcessData
137      in order to know in which mode it is processed.
138     -Switching between kRealtime (or kPrefetch) and kOffline requires that the host calls IAudioProcessor::setupProcessing
139      in order to inform the Plug-in about this mode change. */
140 alias ProcessModes = int;
141 enum : ProcessModes
142 {
143     kRealtime,      ///< realtime processing
144     kPrefetch,      ///< prefetch processing
145     kOffline        ///< offline processing
146 }
147 
148 /** kNoTail
149  *
150  * to be returned by getTailSamples when no tail is wanted
151  \see IAudioProcessor::getTailSamples */
152 enum uint kNoTail = 0;
153 
154 /** kInfiniteTail
155  *
156  * to be returned by getTailSamples when infinite tail is wanted
157  \see IAudioProcessor::getTailSamples */
158 enum uint kInfiniteTail = uint.max;
159 
160 /** Audio processing setup.
161 \see IAudioProcessor::setupProcessing */
162 struct ProcessSetup
163 {
164     int32 processMode;          ///< \ref ProcessModes
165     int32 symbolicSampleSize;   ///< \ref SymbolicSampleSizes
166     int32 maxSamplesPerBlock;   ///< maximum number of samples per audio block
167     SampleRate sampleRate;      ///< sample rate
168 }
169 
170 mixin SMTG_TYPE_SIZE_CHECK!(ProcessSetup, 24, 20, 24);
171 
172 /** Processing buffers of an audio bus.
173 This structure contains the processing buffer for each channel of an audio bus.
174 - The number of channels (numChannels) must always match the current bus arrangement.
175   It could be set to value '0' when the host wants to flush the parameters (when the Plug-in is not processed).
176 - The size of the channel buffer array must always match the number of channels. So the host
177   must always supply an array for the channel buffers, regardless if the
178   bus is active or not. However, if an audio bus is currently inactive, the actual sample
179   buffer addresses are safe to be null.
180 - The silence flag is set when every sample of the according buffer has the value '0'. It is
181   intended to be used as help for optimizations allowing a Plug-in to reduce processing activities.
182   But even if this flag is set for a channel, the channel buffers must still point to valid memory!
183   This flag is optional. A host is free to support it or not.
184 .
185 \see ProcessData */
186 struct AudioBusBuffers
187 {
188     int32 numChannels = 0;      ///< number of audio channels in bus
189     uint64 silenceFlags = 0;    ///< Bitset of silence state per channel
190     union
191     {
192         Sample32** channelBuffers32 = null;    ///< sample buffers to process with 32-bit precision
193         Sample64** channelBuffers64;    ///< sample buffers to process with 64-bit precision
194     }
195 }
196 
197 mixin SMTG_TYPE_SIZE_CHECK!(AudioBusBuffers, 24, 16, 24);
198 
199 /** Any data needed in audio processing.
200     The host prepares AudioBusBuffers for each input/output bus,
201     regardless of the bus activation state. Bus buffer indices always match
202     with bus indices used in IComponent::getBusInfo of media type kAudio.
203 \see AudioBusBuffers, IParameterChanges, IEventList, ProcessContext */
204 struct ProcessData
205 {
206     int32 processMode = 0;          ///< processing mode - value of \ref ProcessModes
207     int32 symbolicSampleSize = kSample32;   ///< sample size - value of \ref SymbolicSampleSizes
208     int32 numSamples = 0;           ///< number of samples to process
209     int32 numInputs = 0;            ///< number of audio input buses
210     int32 numOutputs = 0;           ///< number of audio output buses
211     AudioBusBuffers* inputs = null;  ///< buffers of input buses
212     AudioBusBuffers* outputs = null; ///< buffers of output buses
213 
214     IParameterChanges inputParameterChanges = null;   ///< incoming parameter changes for this block
215     IParameterChanges outputParameterChanges = null;  ///< outgoing parameter changes for this block (optional)
216     IEventList inputEvents = null;                ///< incoming events for this block (optional)
217     IEventList outputEvents = null;               ///< outgoing events for this block (optional)
218     ProcessContext* processContext = null;         ///< processing context (optional, but most welcome)
219 }
220 
221 mixin SMTG_TYPE_SIZE_CHECK!(ProcessData, 80, 48, 48);
222 
223 /** Audio Processing Interface.
224 This interface must always be supported by audio processing Plug-ins. */
225 interface IAudioProcessor: FUnknown
226 {
227 public:
228 nothrow:
229 @nogc:
230 
231     /** Try to set (from host) a predefined arrangement for inputs and outputs.
232         The host should always deliver the same number of input and output buses than the Plug-in needs
233         (see \ref IComponent::getBusCount).
234         The Plug-in returns kResultFalse if wanted arrangements are not supported.
235         If the Plug-in accepts these arrangements, it should modify its buses to match the new arrangements
236         (asked by the host with IComponent::getInfo () or IAudioProcessor::getBusArrangement ()) and then return kResultTrue.
237         If the Plug-in does not accept these arrangements, but can adapt its current arrangements (according to the wanted ones),
238         it should modify its buses arrangements and return kResultFalse. */
239     tresult setBusArrangements (SpeakerArrangement* inputs, int32 numIns,  SpeakerArrangement* outputs, int32 numOuts);
240 
241     /** Gets the bus arrangement for a given direction (input/output) and index.
242         Note: IComponent::getInfo () and IAudioProcessor::getBusArrangement () should be always return the same
243         information about the buses arrangements. */
244     tresult getBusArrangement (BusDirection dir, int32 index, ref SpeakerArrangement arr);
245 
246     /** Asks if a given sample size is supported see \ref SymbolicSampleSizes. */
247     tresult canProcessSampleSize (int32 symbolicSampleSize);
248 
249     /** Gets the current Latency in samples.
250         The returned value defines the group delay or the latency of the Plug-in. For example, if the Plug-in internally needs
251         to look in advance (like compressors) 512 samples then this Plug-in should report 512 as latency.
252         If during the use of the Plug-in this latency change, the Plug-in has to inform the host by
253         using IComponentHandler::restartComponent (kLatencyChanged), this could lead to audio playback interruption
254         because the host has to recompute its internal mixer delay compensation.
255         Note that for player live recording this latency should be zero or small. */
256     uint32 getLatencySamples ();
257 
258     /** Called in disable state (not active) before processing will begin. */
259     tresult setupProcessing (ref ProcessSetup setup);
260 
261     /** Informs the Plug-in about the processing state. This will be called before any process calls start with true and after with false.
262         Note that setProcessing (false) may be called after setProcessing (true) without any process calls.
263         In this call the Plug-in should do only light operation (no memory allocation or big setup reconfiguration),
264         this could be used to reset some buffers (like Delay line or Reverb). */
265     tresult setProcessing (TBool state);
266 
267     /** The Process call, where all information (parameter changes, event, audio buffer) are passed. */
268     tresult process (ref ProcessData data);
269 
270     /** Gets tail size in samples. For example, if the Plug-in is a Reverb Plug-in and it knows that
271         the maximum length of the Reverb is 2sec, then it has to return in getTailSamples()
272         (in VST2 it was getGetTailSize ()): 2*sampleRate.
273         This information could be used by host for offline processing, process optimization and
274         downmix (avoiding signal cut (clicks)).
275         It should return:
276          - kNoTail when no tail
277          - x * sampleRate when x Sec tail.
278          - kInfiniteTail when infinite tail. */
279     uint32 getTailSamples ();
280 
281     __gshared immutable TUID iid = INLINE_UID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D);
282 }
283 
284 
285 // ivstparameterchanges.h
286 
287 //----------------------------------------------------------------------
288 /** Queue of changes for a specific parameter.
289 \ingroup vstIHost vst300
290 - [host imp]
291 - [released: 3.0.0]
292 
293 The change queue can be interpreted as segment of an automation curve. For each
294 processing block a segment with the size of the block is transmitted to the processor.
295 The curve is expressed as sampling points of a linear approximation of
296 the original automation curve. If the original already is a linear curve it can
297 be transmitted precisely. A non-linear curve has to be converted to a linear
298 approximation by the host. Every point of the value queue defines a linear
299 section of the curve as a straight line from the previous point of a block to
300 the new one. So the Plug-in can calculate the value of the curve for any sample
301 position in the block.
302 
303 <b>Implicit Points:</b> \n
304 In each processing block the section of the curve for each parameter is transmitted.
305 In order to reduce the amount of points, the point at block position 0 can be omitted.
306 - If the curve has a slope of 0 over a period of multiple blocks, only one point is
307 transmitted for the block where the constant curve section starts. The queue for the following
308 blocks will be empty as long as the curve slope is 0.
309 - If the curve has a constant slope other than 0 over the period of several blocks, only
310 the value for the last sample of the block is transmitted. In this case the last valid point
311 is at block position -1. The processor can calculate the value for each sample in the block
312 by using a linear interpolation:
313 \code
314 double x1 = -1; // position of last point related to current buffer
315 double y1 = currentParameterValue; // last transmitted value
316 
317 int32 pointTime = 0;
318 ParamValue pointValue = 0;
319 IParamValueQueue::getPoint (0, pointTime, pointValue);
320 
321 double x2 = pointTime;
322 double y2 = pointValue;
323 
324 double slope = (y2 - y1) / (x2 - x1);
325 double offset = y1 - (slope * x1);
326 
327 double curveValue = (slope * bufferTime) + offset; // bufferTime is any position in buffer
328 \endcode
329 
330 <b>Jumps:</b> \n
331 A jump in the automation curve has to be transmitted as two points: one with the
332 old value and one with the new value at the next sample position.
333 
334 \image html "automation.jpg"
335 \see IParameterChanges, ProcessData
336 */
337 interface IParamValueQueue: FUnknown
338 {
339 public:
340 nothrow:
341 @nogc:
342     /** Returns its associated ID. */
343     ParamID getParameterId ();
344 
345     /** Returns count of points in the queue. */
346     int32 getPointCount ();
347 
348     /** Gets the value and offset at a given index. */
349     tresult getPoint (int32 index, ref int32 sampleOffset /*out*/, ref ParamValue value /*out*/);
350 
351     /** Adds a new value at the end of the queue, its index is returned. */
352     tresult addPoint (int32 sampleOffset, ParamValue value, ref int32 index /*out*/);
353 
354     __gshared immutable TUID iid = INLINE_UID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA);
355 }
356 
357 //----------------------------------------------------------------------
358 /** All parameter changes of a processing block.
359 \ingroup vstIHost vst300
360 - [host imp]
361 - [released: 3.0.0]
362 
363 This interface is used to transmit any changes that shall be applied to parameters
364 in the current processing block. A change can be caused by GUI interaction as
365 well as automation. They are transmitted as a list of queues (IParamValueQueue)
366 containing only queues for parameters that actually did change.
367 \see IParamValueQueue, ProcessData */
368 //----------------------------------------------------------------------
369 interface IParameterChanges: FUnknown
370 {
371 public:
372 nothrow:
373 @nogc:
374     /** Returns count of Parameter changes in the list. */
375     int32 getParameterCount () ;
376 
377     /** Returns the queue at a given index. */
378     IParamValueQueue getParameterData (int32 index);
379 
380     /** Adds a new parameter queue with a given ID at the end of the list,
381     returns it and its index in the parameter changes list. */
382     IParamValueQueue addParameterData (ref const(ParamID) id, ref int32 index /*out*/);
383 
384     __gshared immutable TUID iid = INLINE_UID(0xA4779663, 0x0BB64A56, 0xB44384A8, 0x466FEB9D);
385 }
386 
387 // ivstprocesscontext.h
388 
389 /** Audio processing context.
390 For each processing block the host provides timing information and
391 musical parameters that can change over time. For a host that supports jumps
392 (like cycle) it is possible to split up a processing block into multiple parts in
393 order to provide a correct project time inside of every block, but this behaviour
394 is not mandatory. Since the timing will be correct at the beginning of the next block
395 again, a host that is dependent on a fixed processing block size can choose to neglect
396 this problem.
397 \see IAudioProcessor, ProcessData*/
398 struct ProcessContext
399 {
400     /** Transport state & other flags */
401     alias StatesAndFlags = int;
402     enum : StatesAndFlags
403     {
404         kPlaying          = 1 << 1,     ///< currently playing
405         kCycleActive      = 1 << 2,     ///< cycle is active
406         kRecording        = 1 << 3,     ///< currently recording
407 
408         kSystemTimeValid  = 1 << 8,     ///< systemTime contains valid information
409         kContTimeValid    = 1 << 17,    ///< continousTimeSamples contains valid information
410 
411         kProjectTimeMusicValid = 1 << 9,///< projectTimeMusic contains valid information
412         kBarPositionValid = 1 << 11,    ///< barPositionMusic contains valid information
413         kCycleValid       = 1 << 12,    ///< cycleStartMusic and barPositionMusic contain valid information
414 
415         kTempoValid       = 1 << 10,    ///< tempo contains valid information
416         kTimeSigValid     = 1 << 13,    ///< timeSigNumerator and timeSigDenominator contain valid information
417         kChordValid       = 1 << 18,    ///< chord contains valid information
418 
419         kSmpteValid       = 1 << 14,    ///< smpteOffset and frameRate contain valid information
420         kClockValid       = 1 << 15     ///< samplesToNextClock valid
421     }
422 
423     uint32 state;                   ///< a combination of the values from \ref StatesAndFlags
424 
425     double sampleRate;              ///< current sample rate (always valid)
426     TSamples projectTimeSamples;    ///< project time in samples (always valid)
427 
428     int64 systemTime;               ///< system time in nanoseconds (optional)
429     TSamples continousTimeSamples;  ///< project time, without loop (optional)
430 
431     TQuarterNotes projectTimeMusic; ///< musical position in quarter notes (1.0 equals 1 quarter note)
432     TQuarterNotes barPositionMusic; ///< last bar start position, in quarter notes
433     TQuarterNotes cycleStartMusic;  ///< cycle start in quarter notes
434     TQuarterNotes cycleEndMusic;    ///< cycle end in quarter notes
435 
436     double tempo;                   ///< tempo in BPM (Beats Per Minute)
437     int32 timeSigNumerator;         ///< time signature numerator (e.g. 3 for 3/4)
438     int32 timeSigDenominator;       ///< time signature denominator (e.g. 4 for 3/4)
439 
440     Chord chord;                    ///< musical info
441 
442     int32 smpteOffsetSubframes;     ///< SMPTE (sync) offset in subframes (1/80 of frame)
443     FrameRate frameRate;            ///< frame rate
444 
445     int32 samplesToNextClock;       ///< MIDI Clock Resolution (24 Per Quarter Note), can be negative (nearest)
446 }
447 
448 mixin SMTG_TYPE_SIZE_CHECK!(ProcessContext, 112, 104, 112);
449 
450 struct FrameRate
451 {
452     enum FrameRateFlags
453     {
454         kPullDownRate = 1 << 0, ///< for ex. HDTV: 23.976 fps with 24 as frame rate
455         kDropRate     = 1 << 1  ///< for ex. 29.97 fps drop with 30 as frame rate
456     };
457     uint32 framesPerSecond;     ///< frame rate
458     uint32 flags;               ///< flags #FrameRateFlags
459 }
460 
461 mixin SMTG_TYPE_SIZE_CHECK!(FrameRate, 8, 8, 8);
462 
463 /** Description of a chord.
464 A chord is described with a key note, a root note and the
465 \copydoc chordMask
466 \see ProcessContext*/
467 
468 struct Chord
469 {
470     uint8 keyNote;      ///< key note in chord
471     uint8 rootNote;     ///< lowest note in chord
472 
473     /** Bitmask of a chord.
474         1st bit set: minor second; 2nd bit set: major second, and so on. \n
475         There is \b no bit for the keynote (root of the chord) because it is inherently always present. \n
476         Examples:
477         - XXXX 0000 0100 1000 (= 0x0048) -> major chord\n
478         - XXXX 0000 0100 0100 (= 0x0044) -> minor chord\n
479         - XXXX 0010 0100 0100 (= 0x0244) -> minor chord with minor seventh  */
480     int16 chordMask;
481 
482     enum Masks {
483         kChordMask = 0x0FFF,    ///< mask for chordMask
484         kReservedMask = 0xF000  ///< reserved for future use
485     }
486 }
487 
488 mixin SMTG_TYPE_SIZE_CHECK!(Chord, 4, 4, 4);
489 
490 /** Note-on event specific data. Used in \ref Event (union)*/
491 struct NoteOnEvent
492 {
493     short channel;          ///< channel index in event bus
494     short pitch;            ///< range [0, 127] = [C-2, G8] with A3=440Hz
495     float tuning;           ///< 1.f = +1 cent, -1.f = -1 cent
496     float velocity;         ///< range [0.0, 1.0]
497     int length;           ///< in sample frames (optional, Note Off has to follow in any case!)
498     int noteId;           ///< note identifier (if not available then -1)
499 }
500 
501 mixin SMTG_TYPE_SIZE_CHECK!(NoteOnEvent, 20, 20, 20);
502 
503 /** Note-off event specific data. Used in \ref Event (union)*/
504 struct NoteOffEvent
505 {
506     int16 channel;          ///< channel index in event bus
507     int16 pitch;            ///< range [0, 127] = [C-2, G8] with A3=440Hz
508     float velocity;         ///< range [0.0, 1.0]
509     int32 noteId;           ///< associated noteOn identifier (if not available then -1)
510     float tuning;           ///< 1.f = +1 cent, -1.f = -1 cent
511 }
512 
513 mixin SMTG_TYPE_SIZE_CHECK!(NoteOffEvent, 16, 16, 16);
514 
515 /** Data event specific data. Used in \ref Event (union)*/
516 struct DataEvent
517 {
518     uint32 size;            ///< size in bytes of the data block bytes
519     uint32 type;            ///< type of this data block (see \ref DataTypes)
520     const uint8* bytes;     ///< pointer to the data block
521 
522     /** Value for DataEvent::type */
523     enum DataTypes
524     {
525         kMidiSysEx = 0      ///< for MIDI system exclusive message
526     }
527 }
528 
529 mixin SMTG_TYPE_SIZE_CHECK!(DataEvent, 16, 12, 12);
530 
531 /** PolyPressure event specific data. Used in \ref Event (union)*/
532 struct PolyPressureEvent
533 {
534     int16 channel;          ///< channel index in event bus
535     int16 pitch;            ///< range [0, 127] = [C-2, G8] with A3=440Hz
536     float pressure;         ///< range [0.0, 1.0]
537     int32 noteId;           ///< event should be applied to the noteId (if not -1)
538 }
539 
540 mixin SMTG_TYPE_SIZE_CHECK!(PolyPressureEvent, 12, 12, 12);
541 
542 /** Chord event specific data. Used in \ref Event (union)*/
543 struct ChordEvent
544 {
545     int16 root;             ///< range [0, 127] = [C-2, G8] with A3=440Hz
546     int16 bassNote;         ///< range [0, 127] = [C-2, G8] with A3=440Hz
547     int16 mask;             ///< root is bit 0
548     uint16 textLen;         ///< the number of characters (TChar) between the beginning of text and the terminating
549     ///< null character (without including the terminating null character itself)
550     const TChar* text;      ///< UTF-16, null terminated Hosts Chord Name
551 }
552 
553 mixin SMTG_TYPE_SIZE_CHECK!(ChordEvent, 16, 12, 12);
554 
555 /** Legacy MIDI CC Out event specific data. Used in \ref Event (union)*/
556 struct LegacyMIDICCOutEvent
557 {
558     uint8 controlNumber; ///< see enum ControllerNumbers [0, 255]
559     int8 channel;        ///< channel index in event bus [0, 15]
560     int8 value;          ///< value of Controller [0, 127]
561     int8 value2;         ///< [0, 127] used for pitch bend (kPitchBend) and polyPressure (kCtrlPolyPressure)
562 };
563 
564 mixin SMTG_TYPE_SIZE_CHECK!(LegacyMIDICCOutEvent, 4, 4, 4);
565 
566 
567 
568 static if (eventABIFix)
569 {
570     /** Event */
571     struct Event
572     {
573         int32 busIndex;             ///< event bus index
574         int32 sampleOffset;         ///< sample frames related to the current block start sample position
575         TQuarterNotes ppqPosition;  ///< position in project
576         uint16 flags;               ///< combination of \ref EventFlags
577 
578         /** Event Flags - used for Event::flags */
579         enum EventFlags
580         {
581             kIsLive = 1 << 0,           ///< indicates that the event is played live (directly from keyboard)
582 
583             kUserReserved1 = 1 << 14,   ///< reserved for user (for internal use)
584             kUserReserved2 = 1 << 15    ///< reserved for user (for internal use)
585         }
586 
587         /**  Event Types - used for Event::type */
588         enum EventTypes
589         {
590             kNoteOnEvent = 0,              ///< is \ref NoteOnEvent
591             kNoteOffEvent,                 ///< is \ref NoteOffEvent
592             kDataEvent,                    ///< is \ref DataEvent
593             kPolyPressureEvent,            ///< is \ref PolyPressureEvent
594             kNoteExpressionValueEvent,     ///< is \ref NoteExpressionValueEvent
595             kNoteExpressionTextEvent,      ///< is \ref NoteExpressionTextEvent
596             kChordEvent,                   ///< is \ref ChordEvent
597             kScaleEvent,                   ///< is \ref ScaleEvent
598             kLegacyMIDICCOutEvent = 65535, ///< is \ref LegacyMIDICCOutEvent
599         }
600 
601         uint16 type;                ///< a value from \ref EventTypes
602         union
603         {
604             NoteOnEvent noteOn;                             ///< type == kNoteOnEvent
605             NoteOffEvent noteOff;                           ///< type == kNoteOffEvent
606             DataEvent data;                                 ///< type == kDataEvent
607             PolyPressureEvent polyPressure;                 ///< type == kPolyPressureEvent
608             NoteExpressionValueEvent noteExpressionValue;   ///< type == kNoteExpressionValueEvent
609             NoteExpressionTextEvent noteExpressionText;     ///< type == kNoteExpressionTextEvent
610             ChordEvent chord;                               ///< type == kChordEvent
611             //ScaleEvent scale;                               ///< type == kScaleEvent
612             LegacyMIDICCOutEvent midiCCOut;                 ///< type == kLegacyMIDICCOutEvent
613         }
614     }
615 }
616 else
617 {
618     /** Event */
619     struct Event
620     {
621     align(1):
622         int32 busIndex;             ///< event bus index
623         int32 sampleOffset;         ///< sample frames related to the current block start sample position
624         TQuarterNotes ppqPosition;  ///< position in project
625         uint16 flags;               ///< combination of \ref EventFlags
626 
627         /** Event Flags - used for Event::flags */
628         enum EventFlags
629         {
630             kIsLive = 1 << 0,           ///< indicates that the event is played live (directly from keyboard)
631 
632             kUserReserved1 = 1 << 14,   ///< reserved for user (for internal use)
633             kUserReserved2 = 1 << 15    ///< reserved for user (for internal use)
634         }
635 
636         /**  Event Types - used for Event::type */
637         enum EventTypes
638         {
639             kNoteOnEvent = 0,              ///< is \ref NoteOnEvent
640             kNoteOffEvent,                 ///< is \ref NoteOffEvent
641             kDataEvent,                    ///< is \ref DataEvent
642             kPolyPressureEvent,            ///< is \ref PolyPressureEvent
643             kNoteExpressionValueEvent,     ///< is \ref NoteExpressionValueEvent
644             kNoteExpressionTextEvent,      ///< is \ref NoteExpressionTextEvent
645             kChordEvent,                   ///< is \ref ChordEvent
646             kScaleEvent,                   ///< is \ref ScaleEvent
647             kLegacyMIDICCOutEvent = 65535, ///< is \ref LegacyMIDICCOutEvent
648         }
649 
650         static if (size_t.sizeof == 8)
651             ubyte[2] padding0;
652 
653         uint16 type;                ///< a value from \ref EventTypes
654         union
655         {
656             NoteOnEvent noteOn;                             ///< type == kNoteOnEvent
657             NoteOffEvent noteOff;                           ///< type == kNoteOffEvent
658             DataEvent data;                                 ///< type == kDataEvent
659             PolyPressureEvent polyPressure;                 ///< type == kPolyPressureEvent
660             NoteExpressionValueEvent noteExpressionValue;   ///< type == kNoteExpressionValueEvent
661             NoteExpressionTextEvent noteExpressionText;     ///< type == kNoteExpressionTextEvent
662             ChordEvent chord;                               ///< type == kChordEvent
663             //ScaleEvent scale;                               ///< type == kScaleEvent
664             LegacyMIDICCOutEvent midiCCOut;                 ///< type == kLegacyMIDICCOutEvent
665         }
666 
667         static if (size_t.sizeof == 8)
668             ubyte[2] padding1;
669     }
670 }
671 
672 mixin SMTG_TYPE_SIZE_CHECK!(Event, 48, 40, 40);
673 
674 
675         /** List of events to process.
676 \ingroup vstIHost vst300
677 - [host imp]
678 - [released: 3.0.0]
679 
680 \see ProcessData, Event */
681 interface IEventList : FUnknown
682 {
683 public:
684 nothrow:
685 @nogc:
686     /** Returns the count of events. */
687     int32 getEventCount ();
688 
689     /** Gets parameter by index. */
690     tresult getEvent (int32 index, ref Event e /*out*/);
691 
692     /** Adds a new event. */
693     tresult addEvent (ref Event e /*in*/);
694 
695     __gshared immutable TUID iid = INLINE_UID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44);
696 }
697 
698 
699 alias NoteExpressionTypeID = uint;
700 alias NoteExpressionValue = double;
701 
702 struct NoteExpressionValueEvent
703 {
704     NoteExpressionTypeID typeId;    ///< see \ref NoteExpressionTypeID
705     int32 noteId;                   ///< associated note identifier to apply the change
706 
707     NoteExpressionValue value;      ///< normalized value [0.0, 1.0].
708 }
709 
710 mixin SMTG_TYPE_SIZE_CHECK!(NoteExpressionValueEvent, 16, 16, 16);
711 
712 struct NoteExpressionTextEvent
713 {
714     NoteExpressionTypeID typeId;    ///< see \ref NoteExpressionTypeID (kTextTypeID or kPhoneticTypeID)
715     int32 noteId;                   ///< associated note identifier to apply the change
716 
717     uint32 textLen;                 ///< the number of characters (TChar) between the beginning of text and the terminating
718     ///< null character (without including the terminating null character itself)
719 
720     const TChar* text;              ///< UTF-16, null terminated
721 }
722 
723 mixin SMTG_TYPE_SIZE_CHECK!(NoteExpressionTextEvent, 24, 16, 16);
724 
725 
726 /** Basic Host Callback Interface.
727 \ingroup vstIHost vst300
728 - [host imp]
729 - [passed as 'context' in to IPluginBase::initialize () ]
730 - [released: 3.0.0]
731 
732 Basic VST host application interface. */
733 interface IHostApplication: FUnknown
734 {
735 public:
736 nothrow:
737 @nogc:
738     /** Gets host application name. */
739     tresult getName (String128* name);
740 
741     /** Creates host object (e.g. Vst::IMessage). */
742     tresult createInstance (TUID cid, TUID _iid, void** obj);
743 
744     __gshared immutable TUID iid = INLINE_UID(0x58E595CC, 0xDB2D4969, 0x8B6AAF8C, 0x36A664E5);
745 }