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