1use nice_plug_core::audio_setup::{AuxiliaryBuffers, BufferConfig, ProcessMode};
2use nice_plug_core::context::process::Transport;
3use nice_plug_core::midi::sysex::SysExMessage;
4use nice_plug_core::midi::{MidiConfig, NoteEvent};
5use nice_plug_core::params::ParamFlags;
6use nice_plug_core::plugin::ProcessStatus;
7use std::borrow::Borrow;
8use std::ffi::c_void;
9use std::mem::{self, MaybeUninit};
10use std::num::NonZeroU32;
11use std::ptr::NonNull;
12use std::sync::Arc;
13use std::sync::atomic::Ordering;
14use vst3::Steinberg::Vst::ProcessContext_::StatesAndFlags_::{
15 kBarPositionValid, kCycleActive, kCycleValid, kPlaying, kProjectTimeMusicValid, kRecording,
16 kTempoValid, kTimeSigValid,
17};
18use vst3::Steinberg::Vst::{
19 BusDirection, CString, CtrlNumber, DataEvent, Event, Event_::EventTypes_, IAudioProcessor,
20 IAudioProcessorTrait, IComponent, IComponentHandler, IComponentTrait, IEditController,
21 IEditControllerTrait, IEventListTrait, IMidiMapping, IMidiMappingTrait,
22 INoteExpressionController, INoteExpressionControllerTrait, IParamValueQueueTrait,
23 IParameterChangesTrait, IProcessContextRequirements, IProcessContextRequirements_,
24 IProcessContextRequirementsTrait, IUnitInfo, IUnitInfoTrait, IoMode, LegacyMIDICCOutEvent,
25 MediaType, NoteExpressionTypeID, NoteExpressionTypeInfo, NoteExpressionValue,
26 NoteExpressionValueDescription, NoteOffEvent, NoteOnEvent, ParamID, ParamValue, ParameterInfo,
27 ParameterInfo_::ParameterFlags_, PolyPressureEvent, ProcessData, ProcessModes_, ProcessSetup,
28 ProgramListID, ProgramListInfo, SpeakerArrangement, String128, TChar, UnitID, UnitInfo,
29 kNoParamId, kNoParentUnitId, kNoProgramListId, kRootUnitId,
30};
31use vst3::Steinberg::{
32 FIDString, FUnknown, IBStream, IBStreamTrait, IPlugView, IPluginBaseTrait, TBool, TUID, int16,
33 int32, kInvalidArgument, kNoInterface, kResultFalse, kResultOk, tresult, uint32,
34};
35use vst3::{Class, ComRef, ComWrapper};
36use widestring::U16CStr;
37
38use super::inner::{ProcessEvent, WrapperInner};
39use super::note_expressions::{self, NoteExpressionController};
40use super::util::{VST3_MIDI_CCS, VST3_MIDI_NUM_PARAMS, VST3_MIDI_PARAMS_START, u16strlcpy};
41use super::util::{VST3_MIDI_CHANNELS, VST3_MIDI_PARAMS_END};
42use super::view::WrapperView;
43use crate::util::permit_alloc;
44use crate::wrapper::state;
45use crate::wrapper::util::buffer_management::{BufferManager, ChannelPointers};
46use crate::wrapper::util::{clamp_input_event_timing, clamp_output_event_timing, process_wrapper};
47use crate::wrapper::vst3::Vst3Plugin;
48
49#[allow(clippy::unnecessary_cast)]
50const K_SYMBOLIC_SAMPLE_SIZE_32: i32 = vst3::Steinberg::Vst::SymbolicSampleSizes_::kSample32 as i32;
51#[allow(clippy::unnecessary_cast)]
52const K_MEDIA_TYPE_AUDIO: i32 = vst3::Steinberg::Vst::MediaTypes_::kAudio as i32;
53#[allow(clippy::unnecessary_cast)]
54const K_MEDIA_TYPE_EVENT: i32 = vst3::Steinberg::Vst::MediaTypes_::kEvent as i32;
55#[allow(clippy::unnecessary_cast)]
56const K_BUS_DIRECTION_INPUT: i32 = vst3::Steinberg::Vst::BusDirections_::kInput as i32;
57#[allow(clippy::unnecessary_cast)]
58const K_BUS_DIRECTION_OUTPUT: i32 = vst3::Steinberg::Vst::BusDirections_::kOutput as i32;
59#[allow(clippy::unnecessary_cast)]
60const K_BUS_TYPE_MAIN: i32 = vst3::Steinberg::Vst::BusTypes_::kMain as i32;
61#[allow(clippy::unnecessary_cast)]
62const K_BUS_TYPE_AUX: i32 = vst3::Steinberg::Vst::BusTypes_::kAux as i32;
63
64pub struct Wrapper<P: Vst3Plugin> {
65 inner: Arc<WrapperInner<P>>,
66}
67
68impl<P: Vst3Plugin> Class for Wrapper<P> {
69 type Interfaces = (
70 IComponent,
71 IEditController,
72 IAudioProcessor,
73 IMidiMapping,
74 INoteExpressionController,
75 IProcessContextRequirements,
76 IUnitInfo,
77 );
78}
79
80impl<P: Vst3Plugin> Wrapper<P> {
81 pub fn new() -> Self {
82 Self {
83 inner: WrapperInner::new(),
84 }
85 }
86}
87
88impl<P: Vst3Plugin> Default for Wrapper<P> {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl<P: Vst3Plugin> Drop for Wrapper<P> {
95 fn drop(&mut self) {
96 crate::nice_debug_assert_eq!(Arc::strong_count(&self.inner), 1);
97 }
98}
99
100impl<P: Vst3Plugin> IPluginBaseTrait for Wrapper<P> {
101 unsafe fn initialize(&self, _context: *mut FUnknown) -> tresult {
102 kResultOk
104 }
105
106 unsafe fn terminate(&self) -> tresult {
107 kResultOk
108 }
109}
110
111impl<P: Vst3Plugin> IComponentTrait for Wrapper<P> {
112 unsafe fn getControllerClassId(&self, _class_id: *mut TUID) -> tresult {
113 kNoInterface
115 }
116
117 unsafe fn setIoMode(&self, _mode: IoMode) -> tresult {
118 kResultOk
121 }
122
123 unsafe fn getBusCount(
124 &self,
125 type_: vst3::Steinberg::Vst::MediaType,
126 dir: vst3::Steinberg::Vst::BusDirection,
127 ) -> int32 {
128 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
129
130 match type_ {
133 x if x == K_MEDIA_TYPE_AUDIO && dir == K_BUS_DIRECTION_INPUT => {
134 let main_busses = if current_audio_io_layout.main_input_channels.is_some() {
135 1
136 } else {
137 0
138 };
139 let aux_busses = current_audio_io_layout.aux_input_ports.len() as i32;
140
141 main_busses + aux_busses
142 }
143 x if x == K_MEDIA_TYPE_AUDIO && dir == K_BUS_DIRECTION_OUTPUT => {
144 let main_busses = if current_audio_io_layout.main_output_channels.is_some() {
145 1
146 } else {
147 0
148 };
149 let aux_busses = current_audio_io_layout.aux_output_ports.len() as i32;
150
151 main_busses + aux_busses
152 }
153 x if x == K_MEDIA_TYPE_EVENT
154 && dir == K_BUS_DIRECTION_INPUT
155 && P::MIDI_INPUT >= MidiConfig::Basic =>
156 {
157 1
158 }
159 x if x == K_MEDIA_TYPE_EVENT
160 && dir == K_BUS_DIRECTION_OUTPUT
161 && P::MIDI_OUTPUT >= MidiConfig::Basic =>
162 {
163 1
164 }
165 _ => 0,
166 }
167 }
168
169 unsafe fn getBusInfo(
170 &self,
171 type_: vst3::Steinberg::Vst::MediaType,
172 dir: vst3::Steinberg::Vst::BusDirection,
173 index: int32,
174 info: *mut vst3::Steinberg::Vst::BusInfo,
175 ) -> tresult {
176 check_null_ptr!(info);
177
178 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
179
180 match (type_, dir, index) {
181 (t, d, _) if t == K_MEDIA_TYPE_AUDIO && d == K_BUS_DIRECTION_INPUT => {
182 unsafe { *info = mem::zeroed() };
183
184 let info = unsafe { &mut *info };
185 info.mediaType = K_MEDIA_TYPE_AUDIO;
186 info.direction = dir;
187 #[allow(clippy::unnecessary_cast)]
188 {
189 info.flags = vst3::Steinberg::Vst::BusInfo_::BusFlags_::kDefaultActive as u32;
190 }
191
192 let has_main_input = current_audio_io_layout.main_input_channels.is_some();
193 let aux_input_start_idx = if has_main_input { 1 } else { 0 };
194 let aux_input_idx = (index - aux_input_start_idx).max(0) as usize;
195 if index == 0 && has_main_input {
196 info.busType = K_BUS_TYPE_MAIN;
197 info.channelCount =
198 current_audio_io_layout.main_input_channels.unwrap().get() as i32;
199 u16strlcpy(&mut info.name, ¤t_audio_io_layout.main_input_name());
200
201 kResultOk
202 } else if aux_input_idx < current_audio_io_layout.aux_input_ports.len() {
203 info.busType = K_BUS_TYPE_AUX;
204 info.channelCount =
205 current_audio_io_layout.aux_input_ports[aux_input_idx].get() as i32;
206 u16strlcpy(
207 &mut info.name,
208 ¤t_audio_io_layout
209 .aux_input_name(aux_input_idx)
210 .expect("Out of bounds auxiliary input port"),
211 );
212
213 kResultOk
214 } else {
215 kInvalidArgument
216 }
217 }
218 (t, d, _) if t == K_MEDIA_TYPE_AUDIO && d == K_BUS_DIRECTION_OUTPUT => {
219 unsafe { *info = mem::zeroed() };
220
221 let info = unsafe { &mut *info };
222 info.mediaType = K_MEDIA_TYPE_AUDIO;
223 info.direction = dir;
224 #[allow(clippy::unnecessary_cast)]
225 {
226 info.flags = vst3::Steinberg::Vst::BusInfo_::BusFlags_::kDefaultActive as u32;
227 }
228
229 let has_main_output = current_audio_io_layout.main_output_channels.is_some();
230 let aux_output_start_idx = if has_main_output { 1 } else { 0 };
231 let aux_output_idx = (index - aux_output_start_idx).max(0) as usize;
232 if index == 0 && has_main_output {
233 info.busType = K_BUS_TYPE_MAIN;
234 info.channelCount = current_audio_io_layout
237 .main_output_channels
238 .map(NonZeroU32::get)
239 .unwrap_or_default() as i32;
240 u16strlcpy(&mut info.name, ¤t_audio_io_layout.main_output_name());
241
242 kResultOk
243 } else if aux_output_idx < current_audio_io_layout.aux_output_ports.len() {
244 info.busType = K_BUS_TYPE_AUX;
245 info.channelCount =
246 current_audio_io_layout.aux_output_ports[aux_output_idx].get() as i32;
247 u16strlcpy(
248 &mut info.name,
249 ¤t_audio_io_layout
250 .aux_output_name(aux_output_idx)
251 .expect("Out of bounds auxiliary output port"),
252 );
253
254 kResultOk
255 } else {
256 kInvalidArgument
257 }
258 }
259 (t, d, 0)
260 if t == K_MEDIA_TYPE_EVENT
261 && d == K_BUS_DIRECTION_INPUT
262 && P::MIDI_INPUT >= MidiConfig::Basic =>
263 {
264 unsafe { *info = mem::zeroed() };
265
266 let info = unsafe { &mut *info };
267 info.mediaType = K_MEDIA_TYPE_EVENT;
268 info.direction = K_BUS_DIRECTION_INPUT;
269 info.channelCount = 16;
270 u16strlcpy(&mut info.name, "Note Input");
271 info.busType = K_BUS_TYPE_MAIN;
272 #[allow(clippy::unnecessary_cast)]
273 {
274 info.flags = vst3::Steinberg::Vst::BusInfo_::BusFlags_::kDefaultActive as u32;
275 }
276 kResultOk
277 }
278 (t, d, 0)
279 if t == K_MEDIA_TYPE_EVENT
280 && d == K_BUS_DIRECTION_OUTPUT
281 && P::MIDI_OUTPUT >= MidiConfig::Basic =>
282 {
283 unsafe { *info = mem::zeroed() };
284
285 let info = unsafe { &mut *info };
286 info.mediaType = K_MEDIA_TYPE_EVENT;
287 info.direction = K_BUS_DIRECTION_OUTPUT;
288 info.channelCount = 16;
289 u16strlcpy(&mut info.name, "Note Output");
290 info.busType = K_BUS_TYPE_MAIN;
291 #[allow(clippy::unnecessary_cast)]
292 {
293 info.flags = vst3::Steinberg::Vst::BusInfo_::BusFlags_::kDefaultActive as u32;
294 }
295 kResultOk
296 }
297 _ => kInvalidArgument,
298 }
299 }
300
301 unsafe fn getRoutingInfo(
302 &self,
303 in_info: *mut vst3::Steinberg::Vst::RoutingInfo,
304 out_info: *mut vst3::Steinberg::Vst::RoutingInfo,
305 ) -> tresult {
306 check_null_ptr!(in_info, out_info);
307
308 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
309
310 unsafe { *out_info = mem::zeroed() };
311
312 let in_info = unsafe { &*in_info };
313 let out_info = unsafe { &mut *out_info };
314 match (in_info.mediaType, in_info.busIndex) {
315 (t, 0)
316 if t == K_MEDIA_TYPE_AUDIO
317 && current_audio_io_layout.main_input_channels.is_some()
319 && current_audio_io_layout.main_output_channels.is_some() =>
320 {
321 out_info.mediaType = K_MEDIA_TYPE_AUDIO;
322 out_info.busIndex = in_info.busIndex;
323 out_info.channel = in_info.channel;
324
325 kResultOk
326 }
327 (t, 0)
328 if t == K_MEDIA_TYPE_EVENT
329 && P::MIDI_INPUT >= MidiConfig::Basic
330 && P::MIDI_OUTPUT >= MidiConfig::Basic =>
331 {
332 out_info.mediaType = K_MEDIA_TYPE_EVENT;
333 out_info.busIndex = in_info.busIndex;
334 out_info.channel = in_info.channel;
335
336 kResultOk
337 }
338 _ => kResultFalse,
339 }
340 }
341
342 unsafe fn activateBus(
343 &self,
344 type_: vst3::Steinberg::Vst::MediaType,
345 dir: vst3::Steinberg::Vst::BusDirection,
346 index: int32,
347 _state: TBool,
348 ) -> tresult {
349 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
350
351 match (type_, dir, index) {
354 (t, d, _) if t == K_MEDIA_TYPE_AUDIO && d == K_BUS_DIRECTION_INPUT => {
355 let main_busses = if current_audio_io_layout.main_input_channels.is_some() {
356 1
357 } else {
358 0
359 };
360 let aux_busses = current_audio_io_layout.aux_input_ports.len() as i32;
361
362 if (0..main_busses + aux_busses).contains(&index) {
363 kResultOk
364 } else {
365 kInvalidArgument
366 }
367 }
368 (t, d, _) if t == K_MEDIA_TYPE_AUDIO && d == K_BUS_DIRECTION_OUTPUT => {
369 let main_busses = if current_audio_io_layout.main_output_channels.is_some() {
370 1
371 } else {
372 0
373 };
374 let aux_busses = current_audio_io_layout.aux_output_ports.len() as i32;
375
376 if (0..main_busses + aux_busses).contains(&index) {
377 kResultOk
378 } else {
379 kInvalidArgument
380 }
381 }
382 (t, d, 0)
383 if t == K_MEDIA_TYPE_EVENT
384 && d == K_BUS_DIRECTION_INPUT
385 && P::MIDI_INPUT >= MidiConfig::Basic =>
386 {
387 kResultOk
388 }
389 (t, d, 0)
390 if t == K_MEDIA_TYPE_EVENT
391 && d == K_BUS_DIRECTION_OUTPUT
392 && P::MIDI_OUTPUT >= MidiConfig::Basic =>
393 {
394 kResultOk
395 }
396 _ => kInvalidArgument,
397 }
398 }
399
400 unsafe fn setActive(&self, state: TBool) -> tresult {
401 match (state != 0, self.inner.current_buffer_config.load()) {
405 (true, Some(buffer_config)) => {
406 for param in self.inner.param_by_hash.values() {
408 unsafe { param._internal_update_smoother(buffer_config.sample_rate, true) };
409 }
410
411 let mut init_context = self.inner.make_init_context();
413 let audio_io_layout = self.inner.current_audio_io_layout.load();
414 let mut plugin = self.inner.plugin.lock();
415 if plugin.initialize(&audio_io_layout, &buffer_config, &mut init_context) {
416 *self.inner.buffer_manager.borrow_mut() = BufferManager::for_audio_io_layout(
424 buffer_config.max_buffer_size as usize,
425 audio_io_layout,
426 );
427
428 kResultOk
429 } else {
430 kResultFalse
431 }
432 }
433 (true, None) => kResultFalse,
434 (false, _) => {
435 self.inner.plugin.lock().deactivate();
436
437 kResultOk
438 }
439 }
440 }
441
442 unsafe fn setState(&self, state: *mut IBStream) -> tresult {
443 use vst3::Steinberg::IBStream_::IStreamSeekMode_::*;
444
445 check_null_ptr!(state);
446
447 let state = unsafe { ComRef::from_raw(state).unwrap() };
448
449 let mut current_pos = 0;
453 let mut eof_pos = 0;
454 if unsafe {
455 state.tell(&mut current_pos) != kResultOk
456 || state.seek(0, kIBSeekEnd as int32, &mut eof_pos) != kResultOk
457 || state.seek(current_pos, kIBSeekSet as int32, std::ptr::null_mut()) != kResultOk
458 } {
459 crate::nice_debug_assert_failure!("Could not get the stream length");
460 return kResultFalse;
461 }
462
463 let stream_byte_size = (eof_pos - current_pos) as i32;
464 let mut num_bytes_read = 0;
465 let mut read_buffer: Vec<u8> = Vec::with_capacity(stream_byte_size as usize);
466 unsafe {
467 state.read(
468 read_buffer.as_mut_ptr() as *mut c_void,
469 read_buffer.capacity() as i32,
470 &mut num_bytes_read,
471 );
472 }
473 unsafe { read_buffer.set_len(num_bytes_read as usize) };
474
475 if read_buffer.len() != stream_byte_size as usize {
479 crate::nice_debug_assert_failure!("Unexpected stream length");
480 return kResultFalse;
481 }
482
483 match unsafe { state::deserialize_json(&read_buffer) } {
484 Some(mut state) => {
485 if self.inner.set_state_inner(&mut state) {
486 crate::nice_trace!("Loaded state ({} bytes)", read_buffer.len());
487 kResultOk
488 } else {
489 kResultFalse
490 }
491 }
492 None => kResultFalse,
493 }
494 }
495
496 unsafe fn getState(&self, state: *mut IBStream) -> tresult {
497 check_null_ptr!(state);
498
499 let state = unsafe { ComRef::from_raw(state).unwrap() };
500
501 let serialized = unsafe {
502 state::serialize_json::<P>(
503 self.inner.params.clone(),
504 state::make_params_iter(&self.inner.param_by_hash, &self.inner.param_id_to_hash),
505 )
506 };
507 match serialized {
508 Ok(serialized) => {
509 let mut num_bytes_written = 0;
510 let result = unsafe {
511 state.write(
512 serialized.as_ptr() as *mut c_void,
513 serialized.len() as i32,
514 &mut num_bytes_written,
515 )
516 };
517
518 crate::nice_debug_assert_eq!(result, kResultOk);
519 crate::nice_debug_assert_eq!(num_bytes_written as usize, serialized.len());
520
521 crate::nice_trace!("Saved state ({} bytes)", serialized.len());
522
523 kResultOk
524 }
525 Err(err) => {
526 crate::nice_debug_assert_failure!("Could not save state: {:#}", err);
527 kResultFalse
528 }
529 }
530 }
531}
532
533impl<P: Vst3Plugin> IEditControllerTrait for Wrapper<P> {
534 unsafe fn setComponentState(&self, _state: *mut IBStream) -> tresult {
535 kResultOk
537 }
538
539 unsafe fn setState(&self, _state: *mut IBStream) -> tresult {
540 kResultOk
544 }
545
546 unsafe fn getState(&self, _state: *mut IBStream) -> tresult {
547 kResultOk
549 }
550
551 unsafe fn getParameterCount(&self) -> int32 {
552 if P::MIDI_INPUT >= MidiConfig::MidiCCs {
554 self.inner.param_hashes.len() as i32 + VST3_MIDI_NUM_PARAMS as i32
555 } else {
556 self.inner.param_hashes.len() as i32
557 }
558 }
559
560 unsafe fn getParameterInfo(&self, param_index: int32, info: *mut ParameterInfo) -> tresult {
561 check_null_ptr!(info);
562
563 if param_index < 0 || param_index > unsafe { self.getParameterCount() } {
564 return kInvalidArgument;
565 }
566
567 unsafe { *info = std::mem::zeroed() };
568 let info = unsafe { &mut *info };
569
570 let num_actual_params = self.inner.param_hashes.len() as i32;
573 if P::MIDI_INPUT >= MidiConfig::MidiCCs && param_index >= num_actual_params {
574 let midi_param_relative_idx = (param_index - num_actual_params) as u32;
575 let midi_cc = midi_param_relative_idx % VST3_MIDI_CCS;
577 let midi_channel = midi_param_relative_idx / VST3_MIDI_CCS;
578 let name = match midi_cc {
579 128 => format!("MIDI Ch. {} Channel Pressure", midi_channel + 1),
581 129 => format!("MIDI Ch. {} Pitch Bend", midi_channel + 1),
583 n => format!("MIDI Ch. {} CC {}", midi_channel + 1, n),
584 };
585
586 info.id = VST3_MIDI_PARAMS_START + midi_param_relative_idx;
587 u16strlcpy(&mut info.title, &name);
588 u16strlcpy(&mut info.shortTitle, &name);
589 info.flags = ParameterFlags_::kIsReadOnly | (1 << 4); } else {
591 let param_hash = &self.inner.param_hashes[param_index as usize];
592 let param_unit = &self
593 .inner
594 .param_units
595 .get_vst3_unit_id(*param_hash)
596 .expect("Inconsistent parameter data");
597 let param_ptr = &self.inner.param_by_hash[param_hash];
598 let default_value = unsafe { param_ptr.default_normalized_value() };
599 let flags = unsafe { param_ptr.flags() };
600 let automatable = !flags.contains(ParamFlags::NON_AUTOMATABLE);
601 let hidden = flags.contains(ParamFlags::HIDDEN);
602 let is_bypass = flags.contains(ParamFlags::BYPASS);
603
604 info.id = *param_hash;
605 u16strlcpy(&mut info.title, unsafe { param_ptr.name() });
606 u16strlcpy(&mut info.shortTitle, unsafe { param_ptr.name() });
607 u16strlcpy(&mut info.units, unsafe { param_ptr.unit() });
608 info.stepCount = unsafe { param_ptr.step_count().unwrap_or(0) } as i32;
609 info.defaultNormalizedValue = default_value as f64;
610 info.unitId = *param_unit;
611 info.flags = 0;
612 if automatable && !hidden {
613 info.flags |= ParameterFlags_::kCanAutomate;
614 }
615 if hidden {
616 info.flags |= ParameterFlags_::kIsReadOnly | (1 << 4); }
618 if is_bypass {
619 info.flags |= ParameterFlags_::kIsBypass;
620 }
621 }
622
623 kResultOk
624 }
625
626 unsafe fn getParamStringByValue(
627 &self,
628 id: ParamID,
629 value_normalized: ParamValue,
630 string: *mut String128,
631 ) -> tresult {
632 check_null_ptr!(string);
633
634 let dest = unsafe { &mut *(string) };
635
636 match self.inner.param_by_hash.get(&id) {
639 Some(param_ptr) => {
640 unsafe {
641 u16strlcpy(
642 dest,
643 ¶m_ptr.normalized_value_to_string(value_normalized as f32, false),
644 );
645 }
646
647 kResultOk
648 }
649 _ => kInvalidArgument,
650 }
651 }
652
653 unsafe fn getParamValueByString(
654 &self,
655 id: ParamID,
656 string: *mut TChar,
657 value_normalized: *mut ParamValue,
658 ) -> tresult {
659 check_null_ptr!(string, value_normalized);
660
661 let string = match unsafe { U16CStr::from_ptr_str(string as *const u16).to_string() } {
662 Ok(s) => s,
663 Err(_) => return kInvalidArgument,
664 };
665
666 match self.inner.param_by_hash.get(&id) {
667 Some(param_ptr) => {
668 let value = match unsafe { param_ptr.string_to_normalized_value(&string) } {
669 Some(v) => v as f64,
670 None => return kResultFalse,
671 };
672 unsafe { *value_normalized = value };
673
674 kResultOk
675 }
676 _ => kInvalidArgument,
677 }
678 }
679
680 unsafe fn normalizedParamToPlain(
681 &self,
682 id: ParamID,
683 value_normalized: ParamValue,
684 ) -> ParamValue {
685 match self.inner.param_by_hash.get(&id) {
686 Some(param_ptr) => unsafe { param_ptr.preview_plain(value_normalized as f32) as f64 },
687 _ => value_normalized,
688 }
689 }
690
691 unsafe fn plainParamToNormalized(&self, id: ParamID, plain_value: ParamValue) -> ParamValue {
692 match self.inner.param_by_hash.get(&id) {
693 Some(param_ptr) => unsafe { param_ptr.preview_normalized(plain_value as f32) as f64 },
694 _ => plain_value,
695 }
696 }
697
698 unsafe fn getParamNormalized(&self, id: ParamID) -> ParamValue {
699 match self.inner.param_by_hash.get(&id) {
700 Some(param_ptr) => unsafe { param_ptr.modulated_normalized_value() as f64 },
701 _ => 0.5,
702 }
703 }
704
705 unsafe fn setParamNormalized(&self, id: ParamID, value: ParamValue) -> tresult {
706 if self.inner.is_processing.load(Ordering::SeqCst) {
709 return kResultOk;
710 }
711
712 let sample_rate = self
713 .inner
714 .current_buffer_config
715 .load()
716 .map(|c| c.sample_rate);
717 self.inner
718 .set_normalized_value_by_hash(id, value as f32, sample_rate)
719 }
720
721 unsafe fn setComponentHandler(&self, handler: *mut IComponentHandler) -> tresult {
722 *self.inner.component_handler.borrow_mut() =
723 unsafe { ComRef::from_raw(handler) }.map(|r| r.to_com_ptr());
724
725 kResultOk
726 }
727
728 unsafe fn createView(&self, _name: FIDString) -> *mut IPlugView {
729 match self.inner.editor.borrow().as_ref() {
732 Some(editor) => {
733 let view = ComWrapper::new(WrapperView::new(self.inner.clone(), editor.clone()));
734 let plug_view_ptr = view.to_com_ptr::<IPlugView>().unwrap().into_raw();
735 *self.inner.plug_view.write() = Some(view);
736 plug_view_ptr
737 }
738 None => std::ptr::null_mut(),
739 }
740 }
741}
742
743impl<P: Vst3Plugin> IAudioProcessorTrait for Wrapper<P> {
744 unsafe fn setBusArrangements(
745 &self,
746 inputs: *mut SpeakerArrangement,
747 num_ins: int32,
748 outputs: *mut SpeakerArrangement,
749 num_outs: int32,
750 ) -> tresult {
751 check_null_ptr!(inputs, outputs);
752
753 if num_ins < 0 || num_outs < 0 {
755 return kInvalidArgument;
756 }
757
758 let matching_layout = P::AUDIO_IO_LAYOUTS
761 .iter()
762 .find(|layout| {
763 let num_layout_ins = if layout.main_input_channels.is_some() {
767 1
768 } else {
769 0
770 } + layout.aux_input_ports.len();
771 let num_layout_outs = if layout.main_output_channels.is_some() {
772 1
773 } else {
774 0
775 } + layout.aux_output_ports.len();
776 if num_ins as usize != num_layout_ins || num_outs as usize != num_layout_outs {
777 return false;
778 }
779
780 let has_main_input = layout.main_input_channels.is_some();
783 let aux_input_start_idx = if has_main_input { 0 } else { 1 };
784 if has_main_input
785 && unsafe {
786 (*inputs).count_ones() != layout.main_input_channels.unwrap().get()
787 }
788 {
789 return false;
790 }
791 for (aux_input_idx, channel_count) in layout.aux_input_ports.iter().enumerate() {
792 if unsafe {
793 (*inputs.add(aux_input_idx + aux_input_start_idx)).count_ones()
794 != channel_count.get()
795 } {
796 return false;
797 }
798 }
799
800 let has_main_output = layout.main_output_channels.is_some();
801 let aux_output_start_idx = if has_main_output { 0 } else { 1 };
802 if unsafe {
803 (*outputs).count_ones()
804 != layout
805 .main_output_channels
806 .map(NonZeroU32::get)
807 .unwrap_or_default()
808 } {
809 return false;
810 }
811 for (aux_output_idx, channel_count) in layout.aux_output_ports.iter().enumerate() {
812 if unsafe {
813 (*outputs.add(aux_output_idx + aux_output_start_idx)).count_ones()
814 != channel_count.get()
815 } {
816 return false;
817 }
818 }
819
820 true
821 })
822 .copied();
823
824 match matching_layout {
825 Some(layout) => {
826 self.inner.current_audio_io_layout.store(layout);
829
830 kResultOk
831 }
832 None => kResultFalse,
833 }
834 }
835
836 unsafe fn getBusArrangement(
837 &self,
838 dir: BusDirection,
839 index: i32,
840 arr: *mut SpeakerArrangement,
841 ) -> tresult {
842 check_null_ptr!(arr);
843
844 let channel_count_to_map = |count| match count {
845 0 => vst3::Steinberg::Vst::SpeakerArr::kEmpty,
846 1 => vst3::Steinberg::Vst::SpeakerArr::kMono,
847 2 => vst3::Steinberg::Vst::SpeakerArr::kStereo,
848 5 => vst3::Steinberg::Vst::SpeakerArr::k50,
849 6 => vst3::Steinberg::Vst::SpeakerArr::k51,
850 7 => vst3::Steinberg::Vst::SpeakerArr::k70Cine,
851 8 => vst3::Steinberg::Vst::SpeakerArr::k71Cine,
852 n => {
853 crate::nice_debug_assert_failure!(
854 "No defined layout for {} channels, making something up on the spot...",
855 n
856 );
857 (1 << n) - 1
858 }
859 };
860
861 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
862 let num_channels = if dir == K_BUS_DIRECTION_INPUT {
863 let has_main_input = current_audio_io_layout.main_input_channels.is_some();
864 let aux_input_start_idx = if has_main_input { 1 } else { 0 };
865 let aux_input_idx = (index - aux_input_start_idx).max(0) as usize;
866 if index == 0 && has_main_input {
867 current_audio_io_layout.main_input_channels.unwrap().get()
868 } else if aux_input_idx < current_audio_io_layout.aux_input_ports.len() {
869 current_audio_io_layout.aux_input_ports[aux_input_idx].get()
870 } else {
871 return kInvalidArgument;
872 }
873 } else if dir == K_BUS_DIRECTION_OUTPUT {
874 let has_main_output = current_audio_io_layout.main_output_channels.is_some();
875 let aux_output_start_idx = if has_main_output { 1 } else { 0 };
876 let aux_output_idx = (index - aux_output_start_idx).max(0) as usize;
877 if index == 0 && has_main_output {
878 current_audio_io_layout.main_output_channels.unwrap().get()
879 } else if aux_output_idx < current_audio_io_layout.aux_output_ports.len() {
880 current_audio_io_layout.aux_output_ports[aux_output_idx].get()
881 } else {
882 return kInvalidArgument;
883 }
884 } else {
885 return kInvalidArgument;
886 };
887 let channel_map = channel_count_to_map(num_channels);
888
889 crate::nice_debug_assert_eq!(num_channels, channel_map.count_ones());
890 unsafe { *arr = channel_map };
891
892 kResultOk
893 }
894
895 unsafe fn canProcessSampleSize(&self, symbolic_sample_size: int32) -> tresult {
896 if symbolic_sample_size == K_SYMBOLIC_SAMPLE_SIZE_32 {
897 kResultOk
898 } else {
899 kResultFalse
900 }
901 }
902
903 unsafe fn getLatencySamples(&self) -> uint32 {
904 self.inner.current_latency.load(Ordering::SeqCst)
905 }
906
907 unsafe fn setupProcessing(&self, setup: *mut ProcessSetup) -> tresult {
908 check_null_ptr!(setup);
909
910 let setup = unsafe { &*setup };
912 crate::nice_debug_assert_eq!(setup.symbolicSampleSize, K_SYMBOLIC_SAMPLE_SIZE_32);
913
914 self.inner.current_buffer_config.store(Some(BufferConfig {
916 sample_rate: setup.sampleRate as f32,
917 min_buffer_size: None,
918 max_buffer_size: setup.maxSamplesPerBlock as u32,
919 process_mode: self.inner.current_process_mode.load(),
920 }));
921
922 #[allow(clippy::unnecessary_cast)]
923 const K_REALTIME: i32 = ProcessModes_::kRealtime as i32;
924 #[allow(clippy::unnecessary_cast)]
925 const K_PREFETCH: i32 = ProcessModes_::kPrefetch as i32;
926 #[allow(clippy::unnecessary_cast)]
927 const K_OFFLINE: i32 = ProcessModes_::kOffline as i32;
928
929 let mode = match setup.processMode {
930 n if n == K_REALTIME => ProcessMode::Realtime,
931 n if n == K_PREFETCH => ProcessMode::Buffered,
932 n if n == K_OFFLINE => ProcessMode::Offline,
933 n => {
934 crate::nice_debug_assert_failure!(
935 "Unknown rendering mode '{}', defaulting to realtime",
936 n
937 );
938 ProcessMode::Realtime
939 }
940 };
941 self.inner.current_process_mode.store(mode);
942
943 kResultOk
947 }
948
949 unsafe fn setProcessing(&self, state: TBool) -> tresult {
950 let state = state != 0;
951
952 self.inner.last_process_status.store(ProcessStatus::Normal);
954 self.inner.is_processing.store(state, Ordering::SeqCst);
955
956 if state {
959 let mut plugin = match self.inner.plugin.try_lock() {
962 Some(plugin) => plugin,
963 None => {
964 crate::nice_debug_assert_failure!(
965 "The host tried to call IAudioProcessor::setProcessing(true) during a \
966 reentrent call to IComponent::setActive(true), returning kResultOk. If \
967 this is Ardour then it will still call \
968 IAudioProcessor::setProcessing(true) later and everything will be fine. \
969 Hopefully."
970 );
971 return kResultOk;
972 }
973 };
974
975 process_wrapper(|| plugin.reset());
976 }
977
978 kResultOk
980 }
981
982 #[allow(clippy::mut_range_bound)]
984 unsafe fn process(&self, data: *mut ProcessData) -> tresult {
985 check_null_ptr!(data);
986
987 process_wrapper(|| {
990 let data = unsafe { &*data };
992 let sample_rate = self
993 .inner
994 .current_buffer_config
995 .load()
996 .expect("Process call without prior setup call")
997 .sample_rate;
998
999 crate::nice_debug_assert!(data.numInputs >= 0 && data.numOutputs >= 0);
1000 crate::nice_debug_assert_eq!(data.symbolicSampleSize, K_SYMBOLIC_SAMPLE_SIZE_32);
1001 crate::nice_debug_assert!(data.numSamples >= 0);
1002
1003 let total_buffer_len = data.numSamples as usize;
1004
1005 let current_audio_io_layout = self.inner.current_audio_io_layout.load();
1006 let has_main_input = current_audio_io_layout.main_input_channels.is_some();
1007 let has_main_output = current_audio_io_layout.main_output_channels.is_some();
1008 let aux_input_start_idx = if has_main_input { 1 } else { 0 };
1009 let aux_output_start_idx = if has_main_output { 1 } else { 0 };
1010
1011 let mut is_param_flush = total_buffer_len == 0;
1017 if (data.numOutputs == 0 || data.outputs.is_null())
1018 && (has_main_output || !current_audio_io_layout.aux_output_ports.is_empty())
1019 {
1020 is_param_flush = true;
1021 }
1022
1023 let mut process_events = self.inner.process_events.borrow_mut();
1030 process_events.clear();
1031
1032 if let Some(param_changes) = unsafe { ComRef::from_raw(data.inputParameterChanges) } {
1035 let num_param_queues = unsafe { param_changes.getParameterCount() };
1036 for change_queue_idx in 0..num_param_queues {
1037 if let Some(param_change_queue) = unsafe {
1038 ComRef::from_raw(param_changes.getParameterData(change_queue_idx))
1039 } {
1040 let param_hash = unsafe { param_change_queue.getParameterId() };
1041 let num_changes = unsafe { param_change_queue.getPointCount() };
1042 if num_changes <= 0 {
1043 continue;
1044 }
1045
1046 let mut sample_offset = 0i32;
1047 let mut value = 0.0f64;
1048 for change_idx in 0..num_changes {
1049 if unsafe {
1050 param_change_queue.getPoint(
1051 change_idx,
1052 &mut sample_offset,
1053 &mut value,
1054 ) == kResultOk
1055 } {
1056 let timing = clamp_input_event_timing(
1060 sample_offset as u32,
1061 total_buffer_len as u32,
1062 );
1063 let value = value as f32;
1064
1065 if P::MIDI_INPUT >= MidiConfig::MidiCCs
1068 && (VST3_MIDI_PARAMS_START..VST3_MIDI_PARAMS_END)
1069 .contains(¶m_hash)
1070 {
1071 let midi_param_relative_idx =
1072 param_hash - VST3_MIDI_PARAMS_START;
1073 let midi_cc = (midi_param_relative_idx % VST3_MIDI_CCS) as u8;
1075 let midi_channel =
1076 (midi_param_relative_idx / VST3_MIDI_CCS) as u8;
1077 process_events.push(ProcessEvent::NoteEvent(match midi_cc {
1078 128 => NoteEvent::MidiChannelPressure {
1080 timing,
1081 channel: midi_channel,
1082 pressure: value,
1083 },
1084 129 => NoteEvent::MidiPitchBend {
1086 timing,
1087 channel: midi_channel,
1088 value,
1089 },
1090 n => NoteEvent::MidiCC {
1091 timing,
1092 channel: midi_channel,
1093 cc: n,
1094 value,
1095 },
1096 }));
1097 } else if P::SAMPLE_ACCURATE_AUTOMATION {
1098 process_events.push(ProcessEvent::ParameterChange {
1099 timing,
1100 hash: param_hash,
1101 normalized_value: value,
1102 });
1103 } else {
1104 self.inner.set_normalized_value_by_hash(
1105 param_hash,
1106 value,
1107 Some(sample_rate),
1108 );
1109 }
1110 }
1111 }
1112 }
1113 }
1114 }
1115
1116 if P::MIDI_INPUT >= MidiConfig::Basic {
1118 let mut note_expression_controller =
1119 self.inner.note_expression_controller.borrow_mut();
1120 if let Some(events) = unsafe { ComRef::from_raw(data.inputEvents) } {
1121 let num_events = unsafe { events.getEventCount() };
1122
1123 let mut event: MaybeUninit<_> = MaybeUninit::uninit();
1124 for i in 0..num_events {
1125 let result = unsafe { events.getEvent(i, event.as_mut_ptr()) };
1126 crate::nice_debug_assert_eq!(result, kResultOk);
1127
1128 let event = unsafe { event.assume_init() };
1129 let timing = clamp_input_event_timing(
1130 event.sampleOffset as u32,
1131 total_buffer_len as u32,
1132 );
1133
1134 if event.r#type == EventTypes_::kNoteOnEvent as u16 {
1135 let event = unsafe { event.__field0.noteOn };
1136
1137 note_expression_controller.register_note(&event);
1140
1141 process_events.push(ProcessEvent::NoteEvent(NoteEvent::NoteOn {
1142 timing,
1143 voice_id: if event.noteId != -1 {
1144 Some(event.noteId)
1145 } else {
1146 None
1147 },
1148 channel: event.channel as u8,
1149 note: event.pitch as u8,
1150 velocity: event.velocity,
1151 }));
1152 } else if event.r#type == EventTypes_::kNoteOffEvent as u16 {
1153 let event = unsafe { event.__field0.noteOff };
1154 process_events.push(ProcessEvent::NoteEvent(NoteEvent::NoteOff {
1155 timing,
1156 voice_id: if event.noteId != -1 {
1157 Some(event.noteId)
1158 } else {
1159 None
1160 },
1161 channel: event.channel as u8,
1162 note: event.pitch as u8,
1163 velocity: event.velocity,
1164 }));
1165 } else if event.r#type == EventTypes_::kPolyPressureEvent as u16 {
1166 let event = unsafe { event.__field0.polyPressure };
1167 process_events.push(ProcessEvent::NoteEvent(NoteEvent::PolyPressure {
1168 timing,
1169 voice_id: if event.noteId != -1 {
1170 Some(event.noteId)
1171 } else {
1172 None
1173 },
1174 channel: event.channel as u8,
1175 note: event.pitch as u8,
1176 pressure: event.pressure,
1177 }));
1178 } else if event.r#type == EventTypes_::kNoteExpressionValueEvent as u16 {
1179 let event = unsafe { event.__field0.noteExpressionValue };
1180 match note_expression_controller.translate_event(timing, &event) {
1181 Some(translated_event) => {
1182 process_events.push(ProcessEvent::NoteEvent(translated_event))
1183 }
1184 None => crate::nice_debug_assert_failure!(
1185 "Unhandled note expression type: {}",
1186 event.typeId
1187 ),
1188 }
1189 } else if event.r#type == EventTypes_::kDataEvent as u16
1190 && unsafe { event.__field0.data.r#type } == 0
1191 {
1192 let event = unsafe { event.__field0.data };
1194
1195 assert!(!event.bytes.is_null());
1198 let sysex_buffer = unsafe {
1199 std::slice::from_raw_parts(event.bytes, event.size as usize)
1200 };
1201 if let Ok(note_event) = NoteEvent::from_midi(timing, sysex_buffer) {
1202 process_events.push(ProcessEvent::NoteEvent(note_event));
1203 };
1204 }
1205 }
1206 }
1207 }
1208
1209 permit_alloc(|| {
1217 process_events.sort_by_key(|event| match event {
1218 ProcessEvent::ParameterChange { timing, .. } => *timing,
1219 ProcessEvent::NoteEvent(event) => event.timing(),
1220 })
1221 });
1222
1223 let mut block_start = 0usize;
1224 let mut block_end;
1225 let mut event_start_idx = 0;
1226 let result = loop {
1227 {
1235 let mut input_events = self.inner.input_events.borrow_mut();
1236 input_events.clear();
1237
1238 block_end = total_buffer_len;
1239 for event_idx in event_start_idx..process_events.len() {
1240 match &process_events[event_idx] {
1241 ProcessEvent::ParameterChange {
1242 timing,
1243 hash,
1244 normalized_value,
1245 } => {
1246 if *timing != block_start as u32 {
1250 event_start_idx = event_idx;
1251 block_end = *timing as usize;
1252 break;
1253 }
1254
1255 self.inner.set_normalized_value_by_hash(
1256 *hash,
1257 *normalized_value,
1258 Some(sample_rate),
1259 );
1260 }
1261 ProcessEvent::NoteEvent(event) => {
1262 let mut event = event.clone();
1265 event.subtract_timing(block_start as u32);
1266 input_events.push_back(event);
1267 }
1268 }
1269 }
1270 }
1271
1272 let result = if is_param_flush {
1273 kResultOk
1274 } else {
1275 let block_len = block_end - block_start;
1278
1279 let mut buffer_manager = self.inner.buffer_manager.borrow_mut();
1282 let buffers = unsafe {
1283 buffer_manager.create_buffers(block_start, block_len, |buffer_source| {
1284 if data.numOutputs > 0
1285 && !data.outputs.is_null()
1286 && !(*data.outputs).__field0.channelBuffers32.is_null()
1287 && has_main_output
1288 {
1289 let audio_output = &*data.outputs;
1290 let ptrs =
1291 NonNull::new(audio_output.__field0.channelBuffers32).unwrap();
1292 let num_channels = audio_output.numChannels as usize;
1293
1294 *buffer_source.main_output_channel_pointers =
1295 Some(ChannelPointers { ptrs, num_channels });
1296 }
1297
1298 if data.numInputs > 0
1299 && !data.inputs.is_null()
1300 && !(*data.inputs).__field0.channelBuffers32.is_null()
1301 && has_main_input
1302 {
1303 let audio_input = &*data.inputs;
1304 let ptrs =
1305 NonNull::new(audio_input.__field0.channelBuffers32).unwrap();
1306 let num_channels = audio_input.numChannels as usize;
1307
1308 *buffer_source.main_input_channel_pointers =
1309 Some(ChannelPointers { ptrs, num_channels });
1310 }
1311
1312 if !data.inputs.is_null() {
1313 for (aux_input_no, aux_input_channel_pointers) in buffer_source
1314 .aux_input_channel_pointers
1315 .iter_mut()
1316 .enumerate()
1317 {
1318 let aux_input_idx = aux_input_no + aux_input_start_idx;
1319 if aux_input_idx > data.numOutputs as usize {
1320 break;
1321 }
1322
1323 let audio_input = &*data.inputs.add(aux_input_idx);
1324 match NonNull::new(audio_input.__field0.channelBuffers32) {
1325 Some(ptrs) => {
1326 let num_channels = audio_input.numChannels as usize;
1327
1328 *aux_input_channel_pointers =
1329 Some(ChannelPointers { ptrs, num_channels });
1330 }
1331 None => continue,
1332 }
1333 }
1334 }
1335
1336 if !data.outputs.is_null() {
1337 for (aux_output_no, aux_output_channel_pointers) in buffer_source
1338 .aux_output_channel_pointers
1339 .iter_mut()
1340 .enumerate()
1341 {
1342 let aux_output_idx = aux_output_no + aux_output_start_idx;
1343 if aux_output_idx > data.numOutputs as usize {
1344 break;
1345 }
1346
1347 let audio_output = &*data.outputs.add(aux_output_idx);
1348 match NonNull::new(audio_output.__field0.channelBuffers32) {
1349 Some(ptrs) => {
1350 let num_channels = audio_output.numChannels as usize;
1351
1352 *aux_output_channel_pointers =
1353 Some(ChannelPointers { ptrs, num_channels });
1354 }
1355 None => continue,
1356 }
1357 }
1358 }
1359 })
1360 };
1361
1362 let mut buffer_is_valid = true;
1367 for output_buffer_slice in
1368 buffers.main_buffer.as_slice_immutable().iter().chain(
1369 buffers
1370 .aux_outputs
1371 .iter()
1372 .flat_map(|buffer| buffer.as_slice_immutable().iter()),
1373 )
1374 {
1375 if output_buffer_slice.is_empty() {
1376 buffer_is_valid = false;
1377 break;
1378 }
1379 }
1380 crate::nice_debug_assert!(buffer_is_valid);
1381
1382 let mut transport = Transport::new(sample_rate);
1386 if !data.processContext.is_null() {
1387 let context = unsafe { &*data.processContext };
1388
1389 #[allow(clippy::unnecessary_cast)]
1390 {
1391 transport.playing = context.state & kPlaying as u32 != 0;
1392 transport.recording = context.state & kRecording as u32 != 0;
1393
1394 if context.state & kTempoValid as u32 != 0 {
1395 transport.tempo = Some(context.tempo);
1396 }
1397
1398 if context.state & kTimeSigValid as u32 != 0 {
1399 transport.time_sig_numerator = Some(context.timeSigNumerator);
1400 transport.time_sig_denominator = Some(context.timeSigDenominator);
1401 }
1402 }
1403
1404 transport.pos_samples =
1406 Some(context.projectTimeSamples + block_start as i64);
1407 #[allow(clippy::unnecessary_cast)]
1408 if context.state & kProjectTimeMusicValid as u32 != 0 {
1409 if P::SAMPLE_ACCURATE_AUTOMATION
1410 && block_start > 0
1411 && (context.state & kTempoValid as u32 != 0)
1412 {
1413 transport.pos_beats = Some(
1414 context.projectTimeMusic
1415 + (block_start as f64 / sample_rate as f64 / 60.0
1416 * context.tempo),
1417 );
1418 } else {
1419 transport.pos_beats = Some(context.projectTimeMusic);
1420 }
1421 }
1422
1423 #[allow(clippy::unnecessary_cast)]
1424 if context.state & kBarPositionValid as u32 != 0 {
1425 if P::SAMPLE_ACCURATE_AUTOMATION && block_start > 0 {
1426 transport.bar_start_pos_beats =
1428 match transport.bar_start_pos_beats() {
1429 Some(updated) => Some(updated),
1430 None => Some(context.barPositionMusic),
1431 };
1432 } else {
1433 transport.bar_start_pos_beats = Some(context.barPositionMusic);
1434 }
1435 }
1436 #[allow(clippy::unnecessary_cast)]
1437 if context.state & kCycleActive as u32 != 0
1438 && context.state & kCycleValid as u32 != 0
1439 {
1440 transport.loop_range_beats =
1441 Some((context.cycleStartMusic, context.cycleEndMusic));
1442 }
1443 }
1444
1445 let result = if buffer_is_valid {
1446 let mut plugin = permit_alloc(|| self.inner.plugin.lock());
1449 let mut aux = AuxiliaryBuffers {
1450 inputs: buffers.aux_inputs,
1451 outputs: buffers.aux_outputs,
1452 };
1453 let mut context = self.inner.make_process_context(transport);
1454 let result = plugin.process(buffers.main_buffer, &mut aux, &mut context);
1455 self.inner.last_process_status.store(result);
1456 result
1457 } else {
1458 ProcessStatus::Normal
1459 };
1460
1461 match result {
1462 ProcessStatus::Error(err) => {
1463 crate::nice_debug_assert_failure!("Process error: {}", err);
1464
1465 return kResultFalse;
1466 }
1467 _ => kResultOk,
1468 }
1469 };
1470
1471 if let Some(events) = unsafe { ComRef::from_raw(data.outputEvents) } {
1473 let mut output_events = self.inner.output_events.borrow_mut();
1474 while let Some(event) = output_events.pop_front() {
1475 let mut vst3_event: Event = unsafe { mem::zeroed() };
1478 vst3_event.busIndex = 0;
1479 vst3_event.sampleOffset = clamp_output_event_timing(
1481 event.timing() + block_start as u32,
1482 total_buffer_len as u32,
1483 ) as i32;
1484
1485 #[allow(clippy::unnecessary_lazy_evaluations)]
1488 match event {
1489 NoteEvent::NoteOn {
1490 timing: _,
1491 voice_id,
1492 channel,
1493 note,
1494 velocity,
1495 } if P::MIDI_OUTPUT >= MidiConfig::Basic => {
1496 vst3_event.r#type = EventTypes_::kNoteOnEvent as u16;
1497 vst3_event.__field0.noteOn = NoteOnEvent {
1498 channel: channel as i16,
1499 pitch: note as i16,
1500 tuning: 0.0,
1501 velocity,
1502 length: 0, noteId: voice_id
1506 .unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
1507 };
1508 }
1509 NoteEvent::NoteOff {
1510 timing: _,
1511 voice_id,
1512 channel,
1513 note,
1514 velocity,
1515 } if P::MIDI_OUTPUT >= MidiConfig::Basic => {
1516 vst3_event.r#type = EventTypes_::kNoteOffEvent as u16;
1517 vst3_event.__field0.noteOff = NoteOffEvent {
1518 channel: channel as i16,
1519 pitch: note as i16,
1520 velocity,
1521 noteId: voice_id
1522 .unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
1523 tuning: 0.0,
1524 };
1525 }
1526 NoteEvent::VoiceTerminated { .. }
1530 if P::MIDI_INPUT >= MidiConfig::Basic =>
1531 {
1532 continue;
1533 }
1534 NoteEvent::PolyPressure {
1535 timing: _,
1536 voice_id,
1537 channel,
1538 note,
1539 pressure,
1540 } if P::MIDI_OUTPUT >= MidiConfig::Basic => {
1541 vst3_event.r#type = EventTypes_::kPolyPressureEvent as u16;
1542 vst3_event.__field0.polyPressure = PolyPressureEvent {
1543 channel: channel as i16,
1544 pitch: note as i16,
1545 noteId: voice_id
1546 .unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
1547 pressure,
1548 };
1549 }
1550 ref event @ (NoteEvent::PolyVolume {
1551 voice_id,
1552 channel,
1553 note,
1554 ..
1555 }
1556 | NoteEvent::PolyPan {
1557 voice_id,
1558 channel,
1559 note,
1560 ..
1561 }
1562 | NoteEvent::PolyTuning {
1563 voice_id,
1564 channel,
1565 note,
1566 ..
1567 }
1568 | NoteEvent::PolyVibrato {
1569 voice_id,
1570 channel,
1571 note,
1572 ..
1573 }
1574 | NoteEvent::PolyExpression {
1575 voice_id,
1576 channel,
1577 note,
1578 ..
1579 }
1580 | NoteEvent::PolyBrightness {
1581 voice_id,
1582 channel,
1583 note,
1584 ..
1585 }) if P::MIDI_OUTPUT >= MidiConfig::Basic => {
1586 match NoteExpressionController::translate_event_reverse(
1587 voice_id
1588 .unwrap_or_else(|| ((channel as i32) << 8) | note as i32),
1589 event,
1590 ) {
1591 Some(translated_event) => {
1592 vst3_event.r#type =
1593 EventTypes_::kNoteExpressionValueEvent as u16;
1594 vst3_event.__field0.noteExpressionValue = translated_event;
1595 }
1596 None => {
1597 crate::nice_debug_assert_failure!(
1598 "Mishandled note expression value event"
1599 );
1600 }
1601 }
1602 }
1603 NoteEvent::MidiChannelPressure {
1604 timing: _,
1605 channel,
1606 pressure,
1607 } if P::MIDI_OUTPUT >= MidiConfig::MidiCCs => {
1608 vst3_event.r#type = EventTypes_::kLegacyMIDICCOutEvent as u16;
1609 vst3_event.__field0.midiCCOut = LegacyMIDICCOutEvent {
1610 controlNumber: 128, channel: channel as std::ffi::c_char,
1612 value: (pressure * 127.0).round() as std::ffi::c_char,
1613 value2: 0,
1614 };
1615 }
1616 NoteEvent::MidiPitchBend {
1617 timing: _,
1618 channel,
1619 value,
1620 } if P::MIDI_OUTPUT >= MidiConfig::MidiCCs => {
1621 let scaled = (value * ((1 << 14) - 1) as f32).round() as i32;
1622
1623 vst3_event.r#type = EventTypes_::kLegacyMIDICCOutEvent as u16;
1624 vst3_event.__field0.midiCCOut = LegacyMIDICCOutEvent {
1625 controlNumber: 129, channel: channel as std::ffi::c_char,
1627 value: (scaled & 0b01111111) as std::ffi::c_char,
1628 value2: ((scaled >> 7) & 0b01111111) as std::ffi::c_char,
1629 };
1630 }
1631 NoteEvent::MidiCC {
1632 timing: _,
1633 channel,
1634 cc,
1635 value,
1636 } if P::MIDI_OUTPUT >= MidiConfig::MidiCCs => {
1637 vst3_event.r#type = EventTypes_::kLegacyMIDICCOutEvent as u16;
1638 vst3_event.__field0.midiCCOut = LegacyMIDICCOutEvent {
1639 controlNumber: cc,
1640 channel: channel as std::ffi::c_char,
1641 value: (value * 127.0).round() as std::ffi::c_char,
1642 value2: 0,
1643 };
1644 }
1645 NoteEvent::MidiProgramChange {
1646 timing: _,
1647 channel,
1648 program,
1649 } if P::MIDI_OUTPUT >= MidiConfig::MidiCCs => {
1650 vst3_event.r#type = EventTypes_::kLegacyMIDICCOutEvent as u16;
1651 vst3_event.__field0.midiCCOut = LegacyMIDICCOutEvent {
1652 controlNumber: 130, channel: channel as std::ffi::c_char,
1654 value: program as std::ffi::c_char,
1655 value2: 0,
1656 };
1657 }
1658 NoteEvent::MidiSysEx { timing: _, message }
1659 if P::MIDI_OUTPUT >= MidiConfig::Basic =>
1660 {
1661 let (padded_sysex_buffer, length) = message.to_buffer();
1662 let padded_sysex_buffer = padded_sysex_buffer.borrow();
1663 crate::nice_debug_assert!(padded_sysex_buffer.len() >= length);
1664 let sysex_buffer = &padded_sysex_buffer[..length];
1665
1666 vst3_event.r#type = EventTypes_::kDataEvent as u16;
1667 vst3_event.__field0.data = DataEvent {
1668 size: sysex_buffer.len() as u32,
1669 r#type: 0, bytes: sysex_buffer.as_ptr(),
1671 };
1672
1673 let result = unsafe { events.addEvent(&mut vst3_event) };
1676 crate::nice_debug_assert_eq!(result, kResultOk);
1677 continue;
1678 }
1679 _ => {
1680 crate::nice_debug_assert_failure!(
1681 "Invalid output event for the current MIDI_OUTPUT setting"
1682 );
1683 continue;
1684 }
1685 };
1686
1687 let result = unsafe { events.addEvent(&mut vst3_event) };
1688 crate::nice_debug_assert_eq!(result, kResultOk);
1689 }
1690 }
1691
1692 if block_end == total_buffer_len {
1696 break result;
1697 } else {
1698 block_start = block_end;
1699 }
1700 };
1701
1702 let updated_state = permit_alloc(|| self.inner.updated_state_receiver.try_recv());
1709 if let Ok(mut state) = updated_state {
1710 self.inner.set_state_inner(&mut state);
1711
1712 if let Err(err) = self.inner.updated_state_sender.send(state) {
1715 crate::nice_debug_assert_failure!(
1716 "Failed to send state object back to GUI thread: {}",
1717 err
1718 );
1719 };
1720 }
1721
1722 result
1723 })
1724 }
1725
1726 unsafe fn getTailSamples(&self) -> uint32 {
1727 match self.inner.last_process_status.load() {
1729 ProcessStatus::Tail(samples) => samples,
1730 ProcessStatus::KeepAlive => u32::MAX, _ => 0, }
1733 }
1734}
1735
1736impl<P: Vst3Plugin> IMidiMappingTrait for Wrapper<P> {
1737 unsafe fn getMidiControllerAssignment(
1738 &self,
1739 bus_index: int32,
1740 channel: int16,
1741 midi_cc_number: CtrlNumber,
1742 param_id: *mut ParamID,
1743 ) -> tresult {
1744 if P::MIDI_INPUT < MidiConfig::MidiCCs
1745 || bus_index != 0
1746 || !(0..VST3_MIDI_CHANNELS as i16).contains(&channel)
1747 || !(0..VST3_MIDI_CCS as i16).contains(&midi_cc_number)
1748 {
1749 return kResultFalse;
1750 }
1751
1752 check_null_ptr!(param_id);
1753
1754 unsafe {
1757 *param_id =
1758 VST3_MIDI_PARAMS_START + midi_cc_number as u32 + (channel as u32 * VST3_MIDI_CCS)
1759 };
1760
1761 kResultOk
1762 }
1763}
1764
1765impl<P: Vst3Plugin> INoteExpressionControllerTrait for Wrapper<P> {
1766 unsafe fn getNoteExpressionCount(&self, bus_idx: int32, _channel: int16) -> int32 {
1767 if P::MIDI_INPUT >= MidiConfig::Basic && bus_idx == 0 {
1769 note_expressions::KNOWN_NOTE_EXPRESSIONS.len() as i32
1770 } else {
1771 0
1772 }
1773 }
1774
1775 unsafe fn getNoteExpressionInfo(
1776 &self,
1777 bus_idx: int32,
1778 _channel: int16,
1779 note_expression_idx: int32,
1780 info: *mut NoteExpressionTypeInfo,
1781 ) -> tresult {
1782 if P::MIDI_INPUT < MidiConfig::Basic
1783 || bus_idx != 0
1784 || !(0..note_expressions::KNOWN_NOTE_EXPRESSIONS.len() as i32)
1785 .contains(¬e_expression_idx)
1786 {
1787 return kInvalidArgument;
1788 }
1789
1790 check_null_ptr!(info);
1791
1792 unsafe { *info = mem::zeroed() };
1793
1794 let info = unsafe { &mut *info };
1795 let note_expression_info =
1796 ¬e_expressions::KNOWN_NOTE_EXPRESSIONS[note_expression_idx as usize];
1797 info.typeId = note_expression_info.type_id;
1798 u16strlcpy(&mut info.title, note_expression_info.title);
1799 u16strlcpy(&mut info.shortTitle, note_expression_info.title);
1800 u16strlcpy(&mut info.units, note_expression_info.unit);
1801 info.unitId = kNoParentUnitId;
1802 info.valueDesc = NoteExpressionValueDescription {
1805 defaultValue: 0.5,
1806 minimum: 0.0,
1807 maximum: 1.0,
1808 stepCount: 0,
1809 };
1810 info.associatedParameterId = kNoParamId;
1811 info.flags = 1 << 2; kResultOk
1814 }
1815
1816 unsafe fn getNoteExpressionStringByValue(
1817 &self,
1818 _bus_idx: int32,
1819 _channel: int16,
1820 _id: NoteExpressionTypeID,
1821 _value: NoteExpressionValue,
1822 _string: *mut String128,
1823 ) -> tresult {
1824 kResultFalse
1825 }
1826
1827 unsafe fn getNoteExpressionValueByString(
1828 &self,
1829 _bus_idx: int32,
1830 _channel: int16,
1831 _id: NoteExpressionTypeID,
1832 _string: *const TChar,
1833 _value: *mut NoteExpressionValue,
1834 ) -> tresult {
1835 kResultFalse
1836 }
1837}
1838
1839impl<P: Vst3Plugin> IProcessContextRequirementsTrait for Wrapper<P> {
1840 #[allow(clippy::unnecessary_cast)]
1841 unsafe fn getProcessContextRequirements(&self) -> uint32 {
1842 (IProcessContextRequirements_::Flags_::kNeedProjectTimeMusic
1843 | IProcessContextRequirements_::Flags_::kNeedBarPositionMusic
1844 | IProcessContextRequirements_::Flags_::kNeedCycleMusic
1845 | IProcessContextRequirements_::Flags_::kNeedTimeSignature
1846 | IProcessContextRequirements_::Flags_::kNeedTempo
1847 | IProcessContextRequirements_::Flags_::kNeedTransportState) as u32
1848 }
1849}
1850
1851impl<P: Vst3Plugin> IUnitInfoTrait for Wrapper<P> {
1852 unsafe fn getUnitCount(&self) -> int32 {
1853 self.inner.param_units.len() as i32
1854 }
1855
1856 unsafe fn getUnitInfo(&self, unit_index: int32, info: *mut UnitInfo) -> tresult {
1857 check_null_ptr!(info);
1858
1859 match self.inner.param_units.info(unit_index as usize) {
1860 Some((unit_id, unit_info)) => {
1861 unsafe { *info = mem::zeroed() };
1862
1863 let info = unsafe { &mut *info };
1864 info.id = unit_id;
1865 info.parentUnitId = unit_info.parent_id;
1866 u16strlcpy(&mut info.name, &unit_info.name);
1867 info.programListId = kNoProgramListId;
1868
1869 kResultOk
1870 }
1871 None => kInvalidArgument,
1872 }
1873 }
1874
1875 unsafe fn getProgramListCount(&self) -> int32 {
1876 0
1878 }
1879
1880 unsafe fn getProgramListInfo(
1881 &self,
1882 _list_index: int32,
1883 _info: *mut ProgramListInfo,
1884 ) -> tresult {
1885 kInvalidArgument
1886 }
1887
1888 unsafe fn getProgramName(
1889 &self,
1890 _list_id: ProgramListID,
1891 _program_index: int32,
1892 _name: *mut String128,
1893 ) -> tresult {
1894 kInvalidArgument
1895 }
1896
1897 unsafe fn getProgramInfo(
1898 &self,
1899 _list_id: ProgramListID,
1900 _program_index: int32,
1901 _attribute_id: CString,
1902 _attribute_value: *mut String128,
1903 ) -> tresult {
1904 kInvalidArgument
1905 }
1906
1907 unsafe fn hasProgramPitchNames(&self, _id: ProgramListID, _index: int32) -> tresult {
1908 kInvalidArgument
1910 }
1911
1912 unsafe fn getProgramPitchName(
1913 &self,
1914 _id: ProgramListID,
1915 _index: int32,
1916 _pitch: int16,
1917 _name: *mut String128,
1918 ) -> tresult {
1919 kInvalidArgument
1920 }
1921
1922 unsafe fn getSelectedUnit(&self) -> UnitID {
1923 kRootUnitId
1925 }
1926
1927 unsafe fn selectUnit(&self, _id: UnitID) -> tresult {
1928 kResultFalse
1929 }
1930
1931 unsafe fn getUnitByBus(
1932 &self,
1933 _type_: MediaType,
1934 _dir: BusDirection,
1935 _bus_index: int32,
1936 _channel: int32,
1937 _unit_id: *mut UnitID,
1938 ) -> tresult {
1939 kResultFalse
1941 }
1942
1943 unsafe fn setUnitProgramData(
1944 &self,
1945 _list_or_unit: int32,
1946 _program_idx: int32,
1947 _data: *mut IBStream,
1948 ) -> tresult {
1949 kInvalidArgument
1950 }
1951}