gain/
gain.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::cell::Cell;
6use std::ffi::{c_char, c_void, CString};
7use std::str::FromStr;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::{ptr, slice};
10
11use vst3::{uid, Class, ComRef, ComWrapper, Steinberg::Vst::*, Steinberg::*};
12
13fn copy_cstring(src: &str, dst: &mut [c_char]) {
14    let c_string = CString::new(src).unwrap_or_else(|_| CString::default());
15    let bytes = c_string.as_bytes_with_nul();
16
17    for (src, dst) in bytes.iter().zip(dst.iter_mut()) {
18        *dst = *src as c_char;
19    }
20
21    if bytes.len() > dst.len() {
22        if let Some(last) = dst.last_mut() {
23            *last = 0;
24        }
25    }
26}
27
28fn copy_wstring(src: &str, dst: &mut [TChar]) {
29    let mut len = 0;
30    for (src, dst) in src.encode_utf16().zip(dst.iter_mut()) {
31        *dst = src as TChar;
32        len += 1;
33    }
34
35    if len < dst.len() {
36        dst[len] = 0;
37    } else if let Some(last) = dst.last_mut() {
38        *last = 0;
39    }
40}
41
42unsafe fn len_wstring(string: *const TChar) -> usize {
43    let mut len = 0;
44
45    while *string.offset(len) != 0 {
46        len += 1;
47    }
48
49    len as usize
50}
51
52const PLUGIN_NAME: &'static str = "Gain (vst3-rs example plugin)";
53
54struct GainProcessor {
55    gain: AtomicU64,
56}
57
58impl Class for GainProcessor {
59    type Interfaces = (IComponent, IAudioProcessor, IProcessContextRequirements);
60}
61
62impl GainProcessor {
63    const CID: TUID = uid(0x6E332252, 0x54224A00, 0xAA69301A, 0xF318797D);
64
65    fn new() -> GainProcessor {
66        GainProcessor {
67            gain: AtomicU64::new(1.0f64.to_bits()),
68        }
69    }
70}
71
72impl IPluginBaseTrait for GainProcessor {
73    unsafe fn initialize(&self, _context: *mut FUnknown) -> tresult {
74        kResultOk
75    }
76
77    unsafe fn terminate(&self) -> tresult {
78        kResultOk
79    }
80}
81
82impl IComponentTrait for GainProcessor {
83    unsafe fn getControllerClassId(&self, class_id: *mut TUID) -> tresult {
84        *class_id = GainController::CID;
85        kResultOk
86    }
87
88    unsafe fn setIoMode(&self, _mode: IoMode) -> tresult {
89        kResultOk
90    }
91
92    unsafe fn getBusCount(&self, mediaType: MediaType, dir: BusDirection) -> i32 {
93        match mediaType as BusDirections {
94            MediaTypes_::kAudio => match dir as BusDirections {
95                BusDirections_::kInput => 1,
96                BusDirections_::kOutput => 1,
97                _ => 0,
98            },
99            MediaTypes_::kEvent => 0,
100            _ => 0,
101        }
102    }
103
104    unsafe fn getBusInfo(
105        &self,
106        mediaType: MediaType,
107        dir: BusDirection,
108        index: i32,
109        bus: *mut BusInfo,
110    ) -> tresult {
111        match mediaType as MediaTypes {
112            MediaTypes_::kAudio => match dir as BusDirections {
113                BusDirections_::kInput => match index {
114                    0 => {
115                        let bus = &mut *bus;
116
117                        bus.mediaType = MediaTypes_::kAudio as MediaType;
118                        bus.direction = BusDirections_::kInput as BusDirection;
119                        bus.channelCount = 2;
120                        copy_wstring("Input", &mut bus.name);
121                        bus.busType = BusTypes_::kMain as BusType;
122                        bus.flags = BusInfo_::BusFlags_::kDefaultActive as u32;
123
124                        kResultOk
125                    }
126                    _ => kInvalidArgument,
127                },
128                BusDirections_::kOutput => match index {
129                    0 => {
130                        let bus = &mut *bus;
131
132                        bus.mediaType = MediaTypes_::kAudio as MediaType;
133                        bus.direction = BusDirections_::kOutput as BusDirection;
134                        bus.channelCount = 2;
135                        copy_wstring("Output", &mut bus.name);
136                        bus.busType = BusTypes_::kMain as BusType;
137                        bus.flags = BusInfo_::BusFlags_::kDefaultActive as u32 as uint32;
138
139                        kResultOk
140                    }
141                    _ => kInvalidArgument,
142                },
143                _ => kInvalidArgument,
144            },
145            MediaTypes_::kEvent => kInvalidArgument,
146            _ => kInvalidArgument,
147        }
148    }
149
150    unsafe fn getRoutingInfo(
151        &self,
152        _in_info: *mut RoutingInfo,
153        _out_info: *mut RoutingInfo,
154    ) -> tresult {
155        kNotImplemented
156    }
157
158    unsafe fn activateBus(
159        &self,
160        _media_type: MediaType,
161        _dir: BusDirection,
162        _index: i32,
163        _state: TBool,
164    ) -> tresult {
165        kResultOk
166    }
167
168    unsafe fn setActive(&self, _state: TBool) -> tresult {
169        kResultOk
170    }
171
172    unsafe fn setState(&self, _state: *mut IBStream) -> tresult {
173        kResultOk
174    }
175
176    unsafe fn getState(&self, _state: *mut IBStream) -> tresult {
177        kResultOk
178    }
179}
180
181impl IAudioProcessorTrait for GainProcessor {
182    unsafe fn setBusArrangements(
183        &self,
184        inputs: *mut SpeakerArrangement,
185        num_ins: i32,
186        outputs: *mut SpeakerArrangement,
187        num_outs: i32,
188    ) -> tresult {
189        if num_ins != 1 || num_outs != 1 {
190            return kResultFalse;
191        }
192
193        if *inputs != SpeakerArr::kStereo || *outputs != SpeakerArr::kStereo {
194            return kResultFalse;
195        }
196
197        kResultTrue
198    }
199
200    unsafe fn getBusArrangement(
201        &self,
202        dir: BusDirection,
203        index: i32,
204        arr: *mut SpeakerArrangement,
205    ) -> tresult {
206        match dir as BusDirections {
207            BusDirections_::kInput => {
208                if index == 0 {
209                    *arr = SpeakerArr::kStereo;
210                    kResultOk
211                } else {
212                    kInvalidArgument
213                }
214            }
215            BusDirections_::kOutput => {
216                if index == 0 {
217                    *arr = SpeakerArr::kStereo;
218                    kResultOk
219                } else {
220                    kInvalidArgument
221                }
222            }
223            _ => kInvalidArgument,
224        }
225    }
226
227    unsafe fn canProcessSampleSize(&self, symbolic_sample_size: i32) -> tresult {
228        match symbolic_sample_size as SymbolicSampleSizes {
229            SymbolicSampleSizes_::kSample32 => kResultOk as i32,
230            SymbolicSampleSizes_::kSample64 => kNotImplemented as i32,
231            _ => kInvalidArgument,
232        }
233    }
234
235    unsafe fn getLatencySamples(&self) -> u32 {
236        0
237    }
238
239    unsafe fn setupProcessing(&self, _setup: *mut ProcessSetup) -> tresult {
240        kResultOk
241    }
242
243    unsafe fn setProcessing(&self, _state: TBool) -> tresult {
244        kResultOk
245    }
246
247    unsafe fn process(&self, data: *mut ProcessData) -> tresult {
248        let process_data = &*data;
249
250        if let Some(param_changes) = ComRef::from_raw(process_data.inputParameterChanges) {
251            let param_count = param_changes.getParameterCount();
252            for param_index in 0..param_count {
253                if let Some(param_queue) =
254                    ComRef::from_raw(param_changes.getParameterData(param_index))
255                {
256                    let param_id = param_queue.getParameterId();
257                    let point_count = param_queue.getPointCount();
258
259                    match param_id {
260                        0 => {
261                            let mut sample_offset = 0;
262                            let mut value = 0.0;
263                            let result = param_queue.getPoint(
264                                point_count - 1,
265                                &mut sample_offset,
266                                &mut value,
267                            );
268
269                            if result == kResultTrue {
270                                self.gain.store(value.to_bits(), Ordering::Relaxed);
271                            }
272                        }
273                        _ => {}
274                    }
275                }
276            }
277        }
278
279        let gain = f64::from_bits(self.gain.load(Ordering::Relaxed)) as f32;
280
281        let num_samples = process_data.numSamples as usize;
282
283        if process_data.numInputs != 1 || process_data.numOutputs != 1 {
284            return kResultOk;
285        }
286
287        let input_buses =
288            slice::from_raw_parts(process_data.inputs, process_data.numInputs as usize);
289        let output_buses =
290            slice::from_raw_parts(process_data.outputs, process_data.numOutputs as usize);
291
292        if input_buses[0].numChannels != 2 || output_buses[0].numChannels != 2 {
293            return kResultOk;
294        }
295
296        let input_channels = slice::from_raw_parts(
297            input_buses[0].__field0.channelBuffers32,
298            input_buses[0].numChannels as usize,
299        );
300        let output_channels = slice::from_raw_parts(
301            output_buses[0].__field0.channelBuffers32,
302            output_buses[0].numChannels as usize,
303        );
304
305        let input_l = slice::from_raw_parts(input_channels[0], num_samples);
306        let input_r = slice::from_raw_parts(input_channels[1], num_samples);
307        let output_l = slice::from_raw_parts_mut(output_channels[0], num_samples);
308        let output_r = slice::from_raw_parts_mut(output_channels[1], num_samples);
309
310        for i in 0..num_samples {
311            output_l[i] = gain * input_l[i];
312            output_r[i] = gain * input_r[i];
313        }
314
315        kResultOk
316    }
317
318    unsafe fn getTailSamples(&self) -> u32 {
319        0
320    }
321}
322
323impl IProcessContextRequirementsTrait for GainProcessor {
324    unsafe fn getProcessContextRequirements(&self) -> u32 {
325        0
326    }
327}
328
329struct GainController {
330    gain: Cell<f64>,
331}
332
333impl Class for GainController {
334    type Interfaces = (IEditController,);
335}
336
337impl GainController {
338    const CID: TUID = uid(0x1BA8A477, 0xEE0A4A2D, 0x80F50D14, 0x13D2EAA0);
339
340    fn new() -> GainController {
341        GainController {
342            gain: Cell::new(1.0),
343        }
344    }
345}
346
347impl IPluginBaseTrait for GainController {
348    unsafe fn initialize(&self, _context: *mut FUnknown) -> tresult {
349        kResultOk
350    }
351
352    unsafe fn terminate(&self) -> tresult {
353        kResultOk
354    }
355}
356
357impl IEditControllerTrait for GainController {
358    unsafe fn setComponentState(&self, _state: *mut IBStream) -> tresult {
359        kNotImplemented
360    }
361
362    unsafe fn setState(&self, _state: *mut IBStream) -> tresult {
363        kResultOk
364    }
365
366    unsafe fn getState(&self, _state: *mut IBStream) -> tresult {
367        kResultOk
368    }
369
370    unsafe fn getParameterCount(&self) -> i32 {
371        1
372    }
373
374    unsafe fn getParameterInfo(&self, param_index: i32, info: *mut ParameterInfo) -> tresult {
375        match param_index {
376            0 => {
377                let info = &mut *info;
378
379                info.id = 0;
380                copy_wstring("Gain", &mut info.title);
381                copy_wstring("Gain", &mut info.shortTitle);
382                copy_wstring("", &mut info.units);
383                info.stepCount = 0;
384                info.defaultNormalizedValue = 1.0;
385                info.unitId = 0;
386                info.flags = ParameterInfo_::ParameterFlags_::kCanAutomate as i32;
387
388                kResultOk
389            }
390            _ => kInvalidArgument,
391        }
392    }
393
394    unsafe fn getParamStringByValue(
395        &self,
396        id: u32,
397        value_normalized: f64,
398        string: *mut String128,
399    ) -> tresult {
400        let slice = unsafe { &mut *string };
401
402        match id {
403            0 => {
404                let display = value_normalized.to_string();
405                copy_wstring(&display, slice);
406                kResultOk
407            }
408            _ => kInvalidArgument,
409        }
410    }
411
412    unsafe fn getParamValueByString(
413        &self,
414        id: u32,
415        string: *mut TChar,
416        value_normalized: *mut f64,
417    ) -> tresult {
418        match id {
419            0 => {
420                let len = len_wstring(string as *const TChar);
421                if let Ok(string) =
422                    String::from_utf16(slice::from_raw_parts(string as *const u16, len))
423                {
424                    if let Ok(value) = f64::from_str(&string) {
425                        *value_normalized = value;
426                        return kResultOk;
427                    }
428                }
429                kInvalidArgument
430            }
431            _ => kInvalidArgument,
432        }
433    }
434
435    unsafe fn normalizedParamToPlain(&self, id: u32, value_normalized: f64) -> f64 {
436        match id {
437            0 => value_normalized,
438            _ => 0.0,
439        }
440    }
441
442    unsafe fn plainParamToNormalized(&self, id: u32, plain_value: f64) -> f64 {
443        match id {
444            0 => plain_value,
445            _ => 0.0,
446        }
447    }
448
449    unsafe fn getParamNormalized(&self, id: u32) -> f64 {
450        match id {
451            0 => self.gain.get(),
452            _ => 0.0,
453        }
454    }
455
456    unsafe fn setParamNormalized(&self, id: u32, value: f64) -> tresult {
457        match id {
458            0 => {
459                self.gain.set(value);
460                kResultOk
461            }
462            _ => kInvalidArgument,
463        }
464    }
465
466    unsafe fn setComponentHandler(&self, _handler: *mut IComponentHandler) -> tresult {
467        kResultOk
468    }
469
470    unsafe fn createView(&self, _name: *const c_char) -> *mut IPlugView {
471        ptr::null_mut()
472    }
473}
474
475struct Factory {}
476
477impl Class for Factory {
478    type Interfaces = (IPluginFactory,);
479}
480
481impl IPluginFactoryTrait for Factory {
482    unsafe fn getFactoryInfo(&self, info: *mut PFactoryInfo) -> tresult {
483        let info = &mut *info;
484
485        copy_cstring("Vendor", &mut info.vendor);
486        copy_cstring("https://example.com", &mut info.url);
487        copy_cstring("someone@example.com", &mut info.email);
488        info.flags = PFactoryInfo_::FactoryFlags_::kUnicode as int32;
489
490        kResultOk
491    }
492
493    unsafe fn countClasses(&self) -> i32 {
494        2
495    }
496
497    unsafe fn getClassInfo(&self, index: i32, info: *mut PClassInfo) -> tresult {
498        match index {
499            0 => {
500                let info = &mut *info;
501                info.cid = GainProcessor::CID;
502                info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
503                copy_cstring("Audio Module Class", &mut info.category);
504                copy_cstring(PLUGIN_NAME, &mut info.name);
505
506                kResultOk
507            }
508            1 => {
509                let info = &mut *info;
510                info.cid = GainController::CID;
511                info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
512                copy_cstring("Component Controller Class", &mut info.category);
513                copy_cstring(PLUGIN_NAME, &mut info.name);
514
515                kResultOk
516            }
517            _ => kInvalidArgument,
518        }
519    }
520
521    unsafe fn createInstance(
522        &self,
523        cid: FIDString,
524        iid: FIDString,
525        obj: *mut *mut c_void,
526    ) -> tresult {
527        let instance = match *(cid as *const TUID) {
528            GainProcessor::CID => Some(
529                ComWrapper::new(GainProcessor::new())
530                    .to_com_ptr::<FUnknown>()
531                    .unwrap(),
532            ),
533            GainController::CID => Some(
534                ComWrapper::new(GainController::new())
535                    .to_com_ptr::<FUnknown>()
536                    .unwrap(),
537            ),
538            _ => None,
539        };
540
541        if let Some(instance) = instance {
542            let ptr = instance.as_ptr();
543            ((*(*ptr).vtbl).queryInterface)(ptr, iid as *mut TUID, obj)
544        } else {
545            kInvalidArgument
546        }
547    }
548}
549
550#[cfg(target_os = "windows")]
551#[no_mangle]
552extern "system" fn InitDll() -> bool {
553    true
554}
555
556#[cfg(target_os = "windows")]
557#[no_mangle]
558extern "system" fn ExitDll() -> bool {
559    true
560}
561
562#[cfg(target_os = "macos")]
563#[no_mangle]
564extern "system" fn BundleEntry(_bundle_ref: *mut c_void) -> bool {
565    true
566}
567
568#[cfg(target_os = "macos")]
569#[no_mangle]
570extern "system" fn BundleExit() -> bool {
571    true
572}
573
574#[cfg(target_os = "linux")]
575#[no_mangle]
576extern "system" fn ModuleEntry(_library_handle: *mut c_void) -> bool {
577    true
578}
579
580#[cfg(target_os = "linux")]
581#[no_mangle]
582extern "system" fn ModuleExit() -> bool {
583    true
584}
585
586#[no_mangle]
587extern "system" fn GetPluginFactory() -> *mut IPluginFactory {
588    ComWrapper::new(Factory {})
589        .to_com_ptr::<IPluginFactory>()
590        .unwrap()
591        .into_raw()
592}