1use crate::clap::{ClapParameterInfo, ClapPluginInfo};
2#[cfg(all(unix, not(target_os = "macos")))]
3use crate::lv2::Lv2PluginInfo;
4use crate::midi::io::MidiEvent;
5use crate::vst3::Vst3PluginInfo;
6use crate::{kind::Kind, mutex::UnsafeMutex, track::Track};
7use std::sync::{Arc, atomic::AtomicBool};
8use tokio::sync::mpsc::Sender;
9
10#[derive(Clone, Debug)]
11pub struct MidiNoteData {
12 pub start_sample: usize,
13 pub length_samples: usize,
14 pub pitch: u8,
15 pub velocity: u8,
16 pub channel: u8,
17}
18
19#[derive(Clone, Debug)]
20pub struct MidiControllerData {
21 pub sample: usize,
22 pub controller: u8,
23 pub value: u8,
24 pub channel: u8,
25}
26
27#[derive(Debug, Clone)]
28pub struct MidiRawEventData {
29 pub sample: usize,
30 pub data: Vec<u8>,
31}
32
33#[derive(Clone, Debug)]
34pub struct HwMidiEvent {
35 pub device: String,
36 pub event: MidiEvent,
37}
38
39#[derive(Clone, Debug)]
40pub struct OfflineAutomationPoint {
41 pub sample: usize,
42 pub value: f32,
43}
44
45#[derive(Clone, Debug)]
46pub enum OfflineAutomationTarget {
47 Volume,
48 Balance,
49 Mute,
50 #[cfg(all(unix, not(target_os = "macos")))]
51 Lv2Parameter {
52 instance_id: usize,
53 index: u32,
54 min: f32,
55 max: f32,
56 },
57 Vst3Parameter {
58 instance_id: usize,
59 param_id: u32,
60 },
61 ClapParameter {
62 instance_id: usize,
63 param_id: u32,
64 min: f64,
65 max: f64,
66 },
67}
68
69#[derive(Clone, Debug)]
70pub struct OfflineAutomationLane {
71 pub target: OfflineAutomationTarget,
72 pub points: Vec<OfflineAutomationPoint>,
73}
74
75#[derive(Clone, Debug)]
76pub struct OfflineBounceWork {
77 pub state: Arc<UnsafeMutex<crate::state::State>>,
78 pub track_name: String,
79 pub output_path: String,
80 pub start_sample: usize,
81 pub length_samples: usize,
82 pub tempo_bpm: f64,
83 pub tsig_num: u16,
84 pub tsig_denom: u16,
85 pub automation_lanes: Vec<OfflineAutomationLane>,
86 pub cancel: Arc<AtomicBool>,
87 pub apply_fader: bool,
88}
89
90#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
91pub struct PitchCorrectionPointData {
92 pub start_sample: usize,
93 pub length_samples: usize,
94 pub detected_midi_pitch: f32,
95 pub target_midi_pitch: f32,
96 pub clarity: f32,
97}
98
99#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
100pub struct AudioClipData {
101 pub name: String,
102 pub start: usize,
103 pub length: usize,
104 pub offset: usize,
105 pub input_channel: usize,
106 pub muted: bool,
107 pub peaks_file: Option<String>,
108 pub fade_enabled: bool,
109 pub fade_in_samples: usize,
110 pub fade_out_samples: usize,
111 pub preview_name: Option<String>,
112 pub source_name: Option<String>,
113 pub source_offset: Option<usize>,
114 pub source_length: Option<usize>,
115 pub pitch_correction_points: Vec<PitchCorrectionPointData>,
116 pub pitch_correction_frame_likeness: Option<f32>,
117 pub pitch_correction_inertia_ms: Option<u16>,
118 pub pitch_correction_formant_compensation: Option<bool>,
119 pub plugin_graph_json: Option<serde_json::Value>,
120 pub grouped_clips: Vec<AudioClipData>,
121}
122
123#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
124pub struct MidiClipData {
125 pub name: String,
126 pub start: usize,
127 pub length: usize,
128 pub offset: usize,
129 pub input_channel: usize,
130 pub muted: bool,
131 pub grouped_clips: Vec<MidiClipData>,
132}
133
134#[derive(Clone, Debug)]
135pub struct ClipMoveFrom {
136 pub track_name: String,
137 pub clip_index: usize,
138}
139
140#[derive(Clone, Debug)]
141pub struct ClipMoveTo {
142 pub track_name: String,
143 pub sample_offset: usize,
144 pub input_channel: usize,
145}
146
147#[derive(Clone, Debug, PartialEq, Eq, Hash)]
148pub enum PluginGraphNode {
149 TrackInput,
150 TrackOutput,
151 Lv2PluginInstance(usize),
152 Vst3PluginInstance(usize),
153 ClapPluginInstance(usize),
154}
155
156#[derive(Clone, Debug, PartialEq)]
157pub struct PluginGraphPlugin {
158 pub node: PluginGraphNode,
159 pub instance_id: usize,
160 pub format: String,
161 pub uri: String,
162 pub plugin_id: String,
163 pub name: String,
164 pub main_audio_inputs: usize,
165 pub main_audio_outputs: usize,
166 pub audio_inputs: usize,
167 pub audio_outputs: usize,
168 pub midi_inputs: usize,
169 pub midi_outputs: usize,
170 pub state: Option<serde_json::Value>,
171 pub bypassed: bool,
172}
173
174#[cfg(unix)]
175#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
176pub struct Lv2StatePortValue {
177 pub index: u32,
178 pub value: f32,
179}
180
181#[cfg(unix)]
182#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
183pub struct Lv2StateProperty {
184 pub key_uri: String,
185 pub type_uri: String,
186 pub flags: u32,
187 pub value: Vec<u8>,
188}
189
190#[cfg(unix)]
191#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
192pub struct Lv2PluginState {
193 pub port_values: Vec<Lv2StatePortValue>,
194 pub properties: Vec<Lv2StateProperty>,
195}
196
197#[cfg(all(unix, not(target_os = "macos")))]
198#[derive(Clone, Debug, PartialEq)]
199pub struct Lv2ControlPortInfo {
200 pub index: u32,
201 pub name: String,
202 pub min: f32,
203 pub max: f32,
204 pub value: f32,
205}
206
207#[derive(Clone, Debug, PartialEq, Eq)]
208pub struct PluginGraphConnection {
209 pub from_node: PluginGraphNode,
210 pub from_port: usize,
211 pub to_node: PluginGraphNode,
212 pub to_port: usize,
213 pub kind: Kind,
214}
215
216pub type PluginGraphSnapshot = (Vec<PluginGraphPlugin>, Vec<PluginGraphConnection>);
217
218#[derive(Clone, Debug, PartialEq, Eq, Hash)]
220pub enum Vst3GraphNode {
221 TrackInput,
222 TrackOutput,
223 PluginInstance(usize),
224}
225
226#[derive(Clone, Debug)]
227pub struct Vst3GraphPlugin {
228 pub instance_id: usize,
229 pub name: String,
230 pub path: String,
231 pub audio_inputs: usize,
232 pub audio_outputs: usize,
233 pub parameters: Vec<crate::vst3::port::ParameterInfo>,
234}
235
236#[derive(Clone, Debug, PartialEq, Eq)]
237pub struct Vst3GraphConnection {
238 pub from_node: Vst3GraphNode,
239 pub from_port: usize,
240 pub to_node: Vst3GraphNode,
241 pub to_port: usize,
242 pub kind: Kind,
243}
244
245#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
246pub struct MidiLearnBinding {
247 pub device: Option<String>,
248 pub channel: u8,
249 pub cc: u8,
250}
251
252#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
253pub enum TrackMidiLearnTarget {
254 Volume,
255 Balance,
256 Mute,
257 Solo,
258 Arm,
259 InputMonitor,
260 DiskMonitor,
261}
262
263#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
264pub enum GlobalMidiLearnTarget {
265 PlayPause,
266 Stop,
267 RecordToggle,
268}
269
270#[derive(Clone, Debug)]
271pub enum Action {
272 Quit,
273 Play,
274 Pause,
275 Stop,
276 TransportPosition(usize),
277 JumpToEnd,
278 SetLoopEnabled(bool),
279 SetLoopRange(Option<(usize, usize)>),
280 SetPunchEnabled(bool),
281 SetPunchRange(Option<(usize, usize)>),
282 SetMetronomeEnabled(bool),
283 SetTempo(f64),
284 SetTimeSignature {
285 numerator: u16,
286 denominator: u16,
287 },
288 SetOscEnabled(bool),
289 SetClipPlaybackEnabled(bool),
290 SetRecordEnabled(bool),
291 SetSessionPath(String),
292 BeginHistoryGroup,
293 EndHistoryGroup,
294 ApplyGroupedActions(Vec<Action>),
295 ClearHistory,
296 BeginSessionRestore,
297 EndSessionRestore,
298 AddTrack {
299 name: String,
300 audio_ins: usize,
301 midi_ins: usize,
302 audio_outs: usize,
303 midi_outs: usize,
304 },
305 TrackAddAudioInput(String),
306 TrackAddAudioOutput(String),
307 TrackRemoveAudioInput(String),
308 TrackRemoveAudioOutput(String),
309 AddClip {
310 name: String,
311 track_name: String,
312 start: usize,
313 length: usize,
314 offset: usize,
315 input_channel: usize,
316 muted: bool,
317 peaks_file: Option<String>,
318 kind: Kind,
319 fade_enabled: bool,
320 fade_in_samples: usize,
321 fade_out_samples: usize,
322 source_name: Option<String>,
323 source_offset: Option<usize>,
324 source_length: Option<usize>,
325 preview_name: Option<String>,
326 pitch_correction_points: Vec<PitchCorrectionPointData>,
327 pitch_correction_frame_likeness: Option<f32>,
328 pitch_correction_inertia_ms: Option<u16>,
329 pitch_correction_formant_compensation: Option<bool>,
330 plugin_graph_json: Option<serde_json::Value>,
331 },
332 AddGroupedClip {
333 track_name: String,
334 kind: Kind,
335 audio_clip: Option<AudioClipData>,
336 midi_clip: Option<MidiClipData>,
337 },
338 RemoveClip {
339 track_name: String,
340 kind: Kind,
341 clip_indices: Vec<usize>,
342 },
343 SetClipFade {
344 track_name: String,
345 clip_index: usize,
346 kind: Kind,
347 fade_enabled: bool,
348 fade_in_samples: usize,
349 fade_out_samples: usize,
350 },
351 SetClipBounds {
352 track_name: String,
353 clip_index: usize,
354 kind: Kind,
355 start: usize,
356 length: usize,
357 offset: usize,
358 },
359 SyncClipBounds {
360 track_name: String,
361 clip_index: usize,
362 kind: Kind,
363 start: usize,
364 length: usize,
365 offset: usize,
366 },
367 SetClipMuted {
368 track_name: String,
369 clip_index: usize,
370 kind: Kind,
371 muted: bool,
372 },
373 SetClipPluginGraphJson {
374 track_name: String,
375 clip_index: usize,
376 plugin_graph_json: Option<serde_json::Value>,
377 },
378 SetClipPitchCorrection {
379 track_name: String,
380 clip_index: usize,
381 preview_name: Option<String>,
382 source_name: Option<String>,
383 source_offset: Option<usize>,
384 source_length: Option<usize>,
385 pitch_correction_points: Vec<PitchCorrectionPointData>,
386 pitch_correction_frame_likeness: Option<f32>,
387 pitch_correction_inertia_ms: Option<u16>,
388 pitch_correction_formant_compensation: Option<bool>,
389 },
390 RenameClip {
391 track_name: String,
392 kind: Kind,
393 clip_index: usize,
394 new_name: String,
395 },
396 SetClipSourceName {
397 track_name: String,
398 kind: Kind,
399 clip_index: usize,
400 name: String,
401 },
402 RenameTrack {
403 old_name: String,
404 new_name: String,
405 },
406 RemoveTrack(String),
407 TrackLevel(String, f32),
408 TrackBalance(String, f32),
409 TrackAutomationLevel(String, f32),
410 TrackAutomationBalance(String, f32),
411 TrackAutomationMute(String, bool),
412 TrackMeters {
413 track_name: String,
414 output_db: Vec<f32>,
415 },
416 RequestMeterSnapshot,
417 MeterSnapshot {
418 hw_out_db: Arc<Vec<f32>>,
419 track_meters: Arc<Vec<(String, Vec<f32>)>>,
420 },
421 TrackToggleArm(String),
422 TrackToggleMute(String),
423 TrackTogglePhase(String),
424 TrackToggleSolo(String),
425 TrackToggleInputMonitor(String),
426 TrackToggleDiskMonitor(String),
427 TrackArmMidiLearn {
428 track_name: String,
429 target: TrackMidiLearnTarget,
430 },
431 GlobalArmMidiLearn {
432 target: GlobalMidiLearnTarget,
433 },
434 TrackSetMidiLearnBinding {
435 track_name: String,
436 target: TrackMidiLearnTarget,
437 binding: Option<MidiLearnBinding>,
438 },
439 SetGlobalMidiLearnBinding {
440 target: GlobalMidiLearnTarget,
441 binding: Option<MidiLearnBinding>,
442 },
443 TrackSetVcaMaster {
444 track_name: String,
445 master_track: Option<String>,
446 },
447 TrackSetMidiLaneChannel {
448 track_name: String,
449 lane: usize,
450 channel: Option<u8>,
451 },
452 TrackSetFrozen {
453 track_name: String,
454 frozen: bool,
455 },
456 TrackOfflineBounce {
457 track_name: String,
458 output_path: String,
459 start_sample: usize,
460 length_samples: usize,
461 automation_lanes: Vec<OfflineAutomationLane>,
462 apply_fader: bool,
463 },
464 TrackOfflineBounceCancel {
465 track_name: String,
466 },
467 TrackOfflineBounceCancelAll,
468 TrackOfflineBounceCanceled {
469 track_name: String,
470 },
471 TrackOfflineBounceProgress {
472 track_name: String,
473 progress: f32,
474 operation: Option<String>,
475 },
476 PianoKey {
477 track_name: String,
478 note: u8,
479 velocity: u8,
480 on: bool,
481 },
482 ModifyMidiNotes {
483 track_name: String,
484 clip_index: usize,
485 note_indices: Vec<usize>,
486 new_notes: Vec<MidiNoteData>,
487 old_notes: Vec<MidiNoteData>,
488 },
489 ModifyMidiControllers {
490 track_name: String,
491 clip_index: usize,
492 controller_indices: Vec<usize>,
493 new_controllers: Vec<MidiControllerData>,
494 old_controllers: Vec<MidiControllerData>,
495 },
496 DeleteMidiControllers {
497 track_name: String,
498 clip_index: usize,
499 controller_indices: Vec<usize>,
500 deleted_controllers: Vec<(usize, MidiControllerData)>,
501 },
502 InsertMidiControllers {
503 track_name: String,
504 clip_index: usize,
505 controllers: Vec<(usize, MidiControllerData)>,
506 },
507 DeleteMidiNotes {
508 track_name: String,
509 clip_index: usize,
510 note_indices: Vec<usize>,
511 deleted_notes: Vec<(usize, MidiNoteData)>,
512 },
513 InsertMidiNotes {
514 track_name: String,
515 clip_index: usize,
516 notes: Vec<(usize, MidiNoteData)>,
517 },
518 SetMidiSysExEvents {
519 track_name: String,
520 clip_index: usize,
521 new_sysex_events: Vec<MidiRawEventData>,
522 old_sysex_events: Vec<MidiRawEventData>,
523 },
524 #[cfg(all(unix, not(target_os = "macos")))]
525 TrackLoadLv2Plugin {
526 track_name: String,
527 plugin_uri: String,
528 },
529 TrackClearDefaultPassthrough {
530 track_name: String,
531 },
532 #[cfg(all(unix, not(target_os = "macos")))]
533 TrackSetLv2PluginState {
534 track_name: String,
535 instance_id: usize,
536 state: Lv2PluginState,
537 },
538 #[cfg(all(unix, not(target_os = "macos")))]
539 ClipSetLv2PluginState {
540 track_name: String,
541 clip_idx: usize,
542 instance_id: usize,
543 state: Lv2PluginState,
544 },
545 #[cfg(all(unix, not(target_os = "macos")))]
546 TrackUnloadLv2PluginInstance {
547 track_name: String,
548 instance_id: usize,
549 },
550 #[cfg(all(unix, not(target_os = "macos")))]
551 TrackGetLv2PluginControls {
552 track_name: String,
553 instance_id: usize,
554 },
555 #[cfg(all(unix, not(target_os = "macos")))]
556 ClipGetLv2PluginControls {
557 track_name: String,
558 clip_idx: usize,
559 instance_id: usize,
560 },
561 #[cfg(all(unix, not(target_os = "macos")))]
562 TrackLv2PluginControls {
563 track_name: String,
564 instance_id: usize,
565 controls: Vec<Lv2ControlPortInfo>,
566 instance_access_handle: Option<usize>,
567 },
568 #[cfg(all(unix, not(target_os = "macos")))]
569 ClipLv2PluginControls {
570 track_name: String,
571 clip_idx: usize,
572 instance_id: usize,
573 controls: Vec<Lv2ControlPortInfo>,
574 instance_access_handle: Option<usize>,
575 },
576 #[cfg(all(unix, not(target_os = "macos")))]
577 TrackGetLv2Midnam {
578 track_name: String,
579 },
580 #[cfg(all(unix, not(target_os = "macos")))]
581 TrackLv2Midnam {
582 track_name: String,
583 note_names: std::collections::HashMap<u8, String>,
584 },
585 TrackGetClapNoteNames {
586 track_name: String,
587 },
588 TrackClapNoteNames {
589 track_name: String,
590 note_names: std::collections::HashMap<u8, String>,
591 },
592 #[cfg(all(unix, not(target_os = "macos")))]
593 TrackSetLv2ControlValue {
594 track_name: String,
595 instance_id: usize,
596 index: u32,
597 value: f32,
598 },
599 #[cfg(all(unix, not(target_os = "macos")))]
600 ClipSetLv2ControlValue {
601 track_name: String,
602 clip_idx: usize,
603 instance_id: usize,
604 index: u32,
605 value: f32,
606 },
607 #[cfg(all(unix, not(target_os = "macos")))]
608 ClipLv2StateSnapshot {
609 track_name: String,
610 clip_idx: usize,
611 instance_id: usize,
612 state: Lv2PluginState,
613 },
614 #[cfg(unix)]
615 TrackGetPluginGraph {
616 track_name: String,
617 },
618 #[cfg(unix)]
619 TrackPluginGraph {
620 track_name: String,
621 plugins: Vec<PluginGraphPlugin>,
622 connections: Vec<PluginGraphConnection>,
623 },
624 #[cfg(unix)]
625 TrackConnectPluginAudio {
626 track_name: String,
627 from_node: PluginGraphNode,
628 from_port: usize,
629 to_node: PluginGraphNode,
630 to_port: usize,
631 },
632 #[cfg(unix)]
633 TrackConnectPluginMidi {
634 track_name: String,
635 from_node: PluginGraphNode,
636 from_port: usize,
637 to_node: PluginGraphNode,
638 to_port: usize,
639 },
640 #[cfg(unix)]
641 TrackDisconnectPluginAudio {
642 track_name: String,
643 from_node: PluginGraphNode,
644 from_port: usize,
645 to_node: PluginGraphNode,
646 to_port: usize,
647 },
648 #[cfg(unix)]
649 TrackDisconnectPluginMidi {
650 track_name: String,
651 from_node: PluginGraphNode,
652 from_port: usize,
653 to_node: PluginGraphNode,
654 to_port: usize,
655 },
656 #[cfg(all(unix, not(target_os = "macos")))]
657 ListLv2Plugins,
658 #[cfg(all(unix, not(target_os = "macos")))]
659 Lv2Plugins(Vec<Lv2PluginInfo>),
660 ListVst3Plugins,
661 Vst3Plugins(Vec<Vst3PluginInfo>),
662 ListClapPlugins,
663 ListClapPluginsWithCapabilities,
664 ClapPlugins(Vec<ClapPluginInfo>),
665 TrackLoadClapPlugin {
666 track_name: String,
667 plugin_path: String,
668 },
669 TrackUnloadClapPlugin {
670 track_name: String,
671 plugin_path: String,
672 },
673 TrackSetClapParameter {
674 track_name: String,
675 instance_id: usize,
676 param_id: u32,
677 value: f64,
678 },
679 ClipSetClapParameter {
680 track_name: String,
681 clip_idx: usize,
682 instance_id: usize,
683 param_id: u32,
684 value: f64,
685 },
686 TrackSetClapParameterAt {
687 track_name: String,
688 instance_id: usize,
689 param_id: u32,
690 value: f64,
691 frame: u32,
692 },
693 TrackBeginClapParameterEdit {
694 track_name: String,
695 instance_id: usize,
696 param_id: u32,
697 frame: u32,
698 },
699 TrackEndClapParameterEdit {
700 track_name: String,
701 instance_id: usize,
702 param_id: u32,
703 frame: u32,
704 },
705 TrackGetClapParameters {
706 track_name: String,
707 instance_id: usize,
708 },
709 TrackClapParameters {
710 track_name: String,
711 instance_id: usize,
712 parameters: Vec<ClapParameterInfo>,
713 },
714 TrackClapSnapshotState {
715 track_name: String,
716 instance_id: usize,
717 },
718 ClipClapSnapshotState {
719 track_name: String,
720 clip_idx: usize,
721 instance_id: usize,
722 },
723 TrackGetClapProcessor {
724 track_name: String,
725 instance_id: usize,
726 },
727 ClipGetClapProcessor {
728 track_name: String,
729 clip_idx: usize,
730 instance_id: usize,
731 },
732 TrackClapProcessor {
733 track_name: String,
734 instance_id: usize,
735 processor: crate::clap::SharedClapProcessor,
736 },
737 ClipClapProcessor {
738 track_name: String,
739 clip_idx: usize,
740 instance_id: usize,
741 processor: crate::clap::SharedClapProcessor,
742 },
743 TrackClapStateSnapshot {
744 track_name: String,
745 instance_id: usize,
746 plugin_path: String,
747 state: crate::clap::ClapPluginState,
748 },
749 ClipClapStateSnapshot {
750 track_name: String,
751 clip_idx: usize,
752 instance_id: usize,
753 plugin_path: String,
754 state: crate::clap::ClapPluginState,
755 },
756 TrackClapRestoreState {
757 track_name: String,
758 instance_id: usize,
759 state: crate::clap::ClapPluginState,
760 },
761 ClipClapRestoreState {
762 track_name: String,
763 clip_idx: usize,
764 instance_id: usize,
765 state: crate::clap::ClapPluginState,
766 },
767 TrackSnapshotAllClapStates {
768 track_name: String,
769 },
770 TrackSnapshotAllClapStatesDone {
771 track_name: String,
772 },
773 TrackLoadVst3Plugin {
774 track_name: String,
775 plugin_path: String,
776 },
777 TrackUnloadVst3PluginInstance {
778 track_name: String,
779 instance_id: usize,
780 },
781 TrackGetVst3Graph {
782 track_name: String,
783 },
784 TrackVst3Graph {
785 track_name: String,
786 plugins: Vec<Vst3GraphPlugin>,
787 connections: Vec<Vst3GraphConnection>,
788 },
789 TrackSetVst3Parameter {
790 track_name: String,
791 instance_id: usize,
792 param_id: u32,
793 value: f32,
794 },
795 TrackSetPluginBypassed {
796 track_name: String,
797 instance_id: usize,
798 format: String,
799 bypassed: bool,
800 },
801 TrackGetVst3Parameters {
802 track_name: String,
803 instance_id: usize,
804 },
805 TrackVst3Parameters {
806 track_name: String,
807 instance_id: usize,
808 parameters: Vec<crate::vst3::port::ParameterInfo>,
809 },
810 TrackGetVst3Processor {
811 track_name: String,
812 instance_id: usize,
813 },
814 ClipGetVst3Processor {
815 track_name: String,
816 clip_idx: usize,
817 instance_id: usize,
818 },
819 TrackVst3Processor {
820 track_name: String,
821 instance_id: usize,
822 processor: Arc<crate::vst3::Vst3Processor>,
823 },
824 ClipVst3Processor {
825 track_name: String,
826 clip_idx: usize,
827 instance_id: usize,
828 processor: Arc<crate::vst3::Vst3Processor>,
829 },
830 TrackVst3SnapshotState {
831 track_name: String,
832 instance_id: usize,
833 },
834 ClipVst3SnapshotState {
835 track_name: String,
836 clip_idx: usize,
837 instance_id: usize,
838 },
839 TrackVst3StateSnapshot {
840 track_name: String,
841 instance_id: usize,
842 state: crate::vst3::state::Vst3PluginState,
843 },
844 ClipVst3StateSnapshot {
845 track_name: String,
846 clip_idx: usize,
847 instance_id: usize,
848 state: crate::vst3::state::Vst3PluginState,
849 },
850 TrackVst3RestoreState {
851 track_name: String,
852 instance_id: usize,
853 state: crate::vst3::state::Vst3PluginState,
854 },
855 TrackConnectVst3Audio {
856 track_name: String,
857 from_node: Vst3GraphNode,
858 from_port: usize,
859 to_node: Vst3GraphNode,
860 to_port: usize,
861 },
862 TrackDisconnectVst3Audio {
863 track_name: String,
864 from_node: Vst3GraphNode,
865 from_port: usize,
866 to_node: Vst3GraphNode,
867 to_port: usize,
868 },
869 ClipMove {
870 kind: Kind,
871 from: ClipMoveFrom,
872 to: ClipMoveTo,
873 copy: bool,
874 },
875 Connect {
876 from_track: String,
877 from_port: usize,
878 to_track: String,
879 to_port: usize,
880 kind: Kind,
881 },
882 Disconnect {
883 from_track: String,
884 from_port: usize,
885 to_track: String,
886 to_port: usize,
887 kind: Kind,
888 },
889 OpenAudioDevice {
890 device: String,
891 input_device: Option<String>,
892 sample_rate_hz: i32,
893 bits: i32,
894 exclusive: bool,
895 period_frames: usize,
896 nperiods: usize,
897 sync_mode: bool,
898 },
899 JackAddAudioInputPort,
900 JackRemoveAudioInputPort(usize),
901 JackAddAudioOutputPort,
902 JackRemoveAudioOutputPort(usize),
903 OpenMidiInputDevice(String),
904 OpenMidiOutputDevice(String),
905 RequestSessionDiagnostics,
906 RequestMidiLearnMappingsReport,
907 ClearAllMidiLearnBindings,
908 SessionDiagnosticsReport {
909 track_count: usize,
910 frozen_track_count: usize,
911 audio_clip_count: usize,
912 midi_clip_count: usize,
913 #[cfg(all(unix, not(target_os = "macos")))]
914 lv2_instance_count: usize,
915 vst3_instance_count: usize,
916 clap_instance_count: usize,
917 pending_requests: usize,
918 workers_total: usize,
919 workers_ready: usize,
920 pending_hw_midi_events: usize,
921 playing: bool,
922 transport_sample: usize,
923 tempo_bpm: f64,
924 sample_rate_hz: usize,
925 cycle_samples: usize,
926 },
927 MidiLearnMappingsReport {
928 lines: Vec<String>,
929 },
930 HWInfo {
931 channels: usize,
932 rate: usize,
933 input: bool,
934 },
935 Undo,
936 Redo,
937 Panic,
938}
939
940#[derive(Clone, Debug)]
941pub enum Message {
942 Ready(usize),
943 Finished {
944 worker_id: usize,
945 track_name: String,
946 output_linear: Vec<f32>,
947 process_epoch: usize,
948 },
949 TracksFinished,
950
951 ProcessTrack(Arc<UnsafeMutex<Box<Track>>>),
952 ProcessOfflineBounce(OfflineBounceWork),
953 Channel(Sender<Self>),
954
955 Request(Action),
956 Response(Result<Action, String>),
957 HWMidiEvents(Vec<HwMidiEvent>),
958 HWMidiOutEvents(Vec<HwMidiEvent>),
959 ClearHWMidiOutEvents,
960 HWFinished,
961 OfflineBounceFinished {
962 result: Result<Action, String>,
963 },
964}
965
966#[cfg(test)]
967mod tests {
968 use super::{AudioClipData, MidiClipData, PitchCorrectionPointData};
969 use serde_json::json;
970
971 #[test]
972 fn audio_clip_data_serde_round_trips_nested_groups() {
973 let clip = AudioClipData {
974 name: "group.wav".to_string(),
975 start: 12,
976 length: 96,
977 offset: 3,
978 input_channel: 1,
979 muted: true,
980 peaks_file: Some("peaks/group.json".to_string()),
981 fade_enabled: false,
982 fade_in_samples: 10,
983 fade_out_samples: 20,
984 preview_name: Some("preview.wav".to_string()),
985 source_name: Some("source.wav".to_string()),
986 source_offset: Some(4),
987 source_length: Some(88),
988 pitch_correction_points: vec![PitchCorrectionPointData {
989 start_sample: 7,
990 length_samples: 11,
991 detected_midi_pitch: 60.1,
992 target_midi_pitch: 61.2,
993 clarity: 0.8,
994 }],
995 pitch_correction_frame_likeness: Some(0.5),
996 pitch_correction_inertia_ms: Some(123),
997 pitch_correction_formant_compensation: Some(false),
998 plugin_graph_json: Some(json!({"plugins":[],"connections":[{"kind":"Audio"}]})),
999 grouped_clips: vec![AudioClipData {
1000 name: "child.wav".to_string(),
1001 start: 0,
1002 length: 48,
1003 ..AudioClipData::default()
1004 }],
1005 };
1006
1007 let value = serde_json::to_value(&clip).expect("serialize");
1008 let restored: AudioClipData = serde_json::from_value(value).expect("deserialize");
1009
1010 assert_eq!(restored.name, clip.name);
1011 assert_eq!(restored.preview_name, clip.preview_name);
1012 assert_eq!(restored.source_name, clip.source_name);
1013 assert_eq!(restored.plugin_graph_json, clip.plugin_graph_json);
1014 assert_eq!(restored.grouped_clips.len(), 1);
1015 assert_eq!(restored.grouped_clips[0].name, "child.wav");
1016 assert_eq!(restored.pitch_correction_points[0].target_midi_pitch, 61.2);
1017 }
1018
1019 #[test]
1020 fn midi_clip_data_serde_round_trips_nested_groups() {
1021 let clip = MidiClipData {
1022 name: "group.mid".to_string(),
1023 start: 5,
1024 length: 64,
1025 offset: 2,
1026 input_channel: 3,
1027 muted: true,
1028 grouped_clips: vec![MidiClipData {
1029 name: "child.mid".to_string(),
1030 start: 0,
1031 length: 32,
1032 ..MidiClipData::default()
1033 }],
1034 };
1035
1036 let value = serde_json::to_value(&clip).expect("serialize");
1037 let restored: MidiClipData = serde_json::from_value(value).expect("deserialize");
1038
1039 assert_eq!(restored.name, clip.name);
1040 assert_eq!(restored.grouped_clips.len(), 1);
1041 assert_eq!(restored.grouped_clips[0].name, "child.mid");
1042 }
1043
1044 #[test]
1045 fn pitch_correction_point_data_serde_round_trips() {
1046 let point = PitchCorrectionPointData {
1047 start_sample: 10,
1048 length_samples: 20,
1049 detected_midi_pitch: 57.5,
1050 target_midi_pitch: 58.0,
1051 clarity: 0.9,
1052 };
1053
1054 let value = serde_json::to_value(&point).expect("serialize");
1055 let restored: PitchCorrectionPointData =
1056 serde_json::from_value(value).expect("deserialize");
1057
1058 assert_eq!(restored.start_sample, 10);
1059 assert_eq!(restored.length_samples, 20);
1060 assert_eq!(restored.detected_midi_pitch, 57.5);
1061 assert_eq!(restored.target_midi_pitch, 58.0);
1062 assert_eq!(restored.clarity, 0.9);
1063 }
1064
1065 #[test]
1066 fn audio_clip_data_deserializes_with_omitted_optional_fields() {
1067 let restored: AudioClipData = serde_json::from_value(json!({
1068 "name": "clip.wav",
1069 "start": 1,
1070 "length": 2,
1071 "offset": 3,
1072 "input_channel": 0,
1073 "muted": false,
1074 "fade_enabled": true,
1075 "fade_in_samples": 240,
1076 "fade_out_samples": 240,
1077 "pitch_correction_points": [],
1078 "grouped_clips": []
1079 }))
1080 .expect("deserialize");
1081
1082 assert_eq!(restored.name, "clip.wav");
1083 assert!(restored.peaks_file.is_none());
1084 assert!(restored.preview_name.is_none());
1085 assert!(restored.source_name.is_none());
1086 assert!(restored.source_offset.is_none());
1087 assert!(restored.source_length.is_none());
1088 assert!(restored.pitch_correction_points.is_empty());
1089 assert!(restored.plugin_graph_json.is_none());
1090 }
1091}