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