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