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