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 ClearHistory,
295 BeginSessionRestore,
296 EndSessionRestore,
297 AddTrack {
298 name: String,
299 audio_ins: usize,
300 midi_ins: usize,
301 audio_outs: usize,
302 midi_outs: usize,
303 },
304 TrackAddAudioInput(String),
305 TrackAddAudioOutput(String),
306 TrackRemoveAudioInput(String),
307 TrackRemoveAudioOutput(String),
308 AddClip {
309 name: String,
310 track_name: String,
311 start: usize,
312 length: usize,
313 offset: usize,
314 input_channel: usize,
315 muted: bool,
316 peaks_file: Option<String>,
317 kind: Kind,
318 fade_enabled: bool,
319 fade_in_samples: usize,
320 fade_out_samples: usize,
321 source_name: Option<String>,
322 source_offset: Option<usize>,
323 source_length: Option<usize>,
324 preview_name: Option<String>,
325 pitch_correction_points: Vec<PitchCorrectionPointData>,
326 pitch_correction_frame_likeness: Option<f32>,
327 pitch_correction_inertia_ms: Option<u16>,
328 pitch_correction_formant_compensation: Option<bool>,
329 plugin_graph_json: Option<serde_json::Value>,
330 },
331 AddGroupedClip {
332 track_name: String,
333 kind: Kind,
334 audio_clip: Option<AudioClipData>,
335 midi_clip: Option<MidiClipData>,
336 },
337 RemoveClip {
338 track_name: String,
339 kind: Kind,
340 clip_indices: Vec<usize>,
341 },
342 SetClipFade {
343 track_name: String,
344 clip_index: usize,
345 kind: Kind,
346 fade_enabled: bool,
347 fade_in_samples: usize,
348 fade_out_samples: usize,
349 },
350 SetClipBounds {
351 track_name: String,
352 clip_index: usize,
353 kind: Kind,
354 start: usize,
355 length: usize,
356 offset: usize,
357 },
358 SetClipMuted {
359 track_name: String,
360 clip_index: usize,
361 kind: Kind,
362 muted: bool,
363 },
364 SetClipPluginGraphJson {
365 track_name: String,
366 clip_index: usize,
367 plugin_graph_json: Option<serde_json::Value>,
368 },
369 SetClipPitchCorrection {
370 track_name: String,
371 clip_index: usize,
372 preview_name: Option<String>,
373 source_name: Option<String>,
374 source_offset: Option<usize>,
375 source_length: Option<usize>,
376 pitch_correction_points: Vec<PitchCorrectionPointData>,
377 pitch_correction_frame_likeness: Option<f32>,
378 pitch_correction_inertia_ms: Option<u16>,
379 pitch_correction_formant_compensation: Option<bool>,
380 },
381 RenameClip {
382 track_name: String,
383 kind: Kind,
384 clip_index: usize,
385 new_name: String,
386 },
387 RenameTrack {
388 old_name: String,
389 new_name: String,
390 },
391 RemoveTrack(String),
392 TrackLevel(String, f32),
393 TrackBalance(String, f32),
394 TrackAutomationLevel(String, f32),
395 TrackAutomationBalance(String, f32),
396 TrackAutomationMute(String, bool),
397 TrackMeters {
398 track_name: String,
399 output_db: Vec<f32>,
400 },
401 RequestMeterSnapshot,
402 MeterSnapshot {
403 hw_out_db: Arc<Vec<f32>>,
404 track_meters: Arc<Vec<(String, Vec<f32>)>>,
405 },
406 TrackToggleArm(String),
407 TrackToggleMute(String),
408 TrackTogglePhase(String),
409 TrackToggleSolo(String),
410 TrackToggleInputMonitor(String),
411 TrackToggleDiskMonitor(String),
412 TrackArmMidiLearn {
413 track_name: String,
414 target: TrackMidiLearnTarget,
415 },
416 GlobalArmMidiLearn {
417 target: GlobalMidiLearnTarget,
418 },
419 TrackSetMidiLearnBinding {
420 track_name: String,
421 target: TrackMidiLearnTarget,
422 binding: Option<MidiLearnBinding>,
423 },
424 SetGlobalMidiLearnBinding {
425 target: GlobalMidiLearnTarget,
426 binding: Option<MidiLearnBinding>,
427 },
428 TrackSetVcaMaster {
429 track_name: String,
430 master_track: Option<String>,
431 },
432 TrackSetMidiLaneChannel {
433 track_name: String,
434 lane: usize,
435 channel: Option<u8>,
436 },
437 TrackSetFrozen {
438 track_name: String,
439 frozen: bool,
440 },
441 TrackOfflineBounce {
442 track_name: String,
443 output_path: String,
444 start_sample: usize,
445 length_samples: usize,
446 automation_lanes: Vec<OfflineAutomationLane>,
447 apply_fader: bool,
448 },
449 TrackOfflineBounceCancel {
450 track_name: String,
451 },
452 TrackOfflineBounceCancelAll,
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 TrackSetPluginBypassed {
781 track_name: String,
782 instance_id: usize,
783 format: String,
784 bypassed: bool,
785 },
786 TrackGetVst3Parameters {
787 track_name: String,
788 instance_id: usize,
789 },
790 TrackVst3Parameters {
791 track_name: String,
792 instance_id: usize,
793 parameters: Vec<crate::vst3::port::ParameterInfo>,
794 },
795 TrackGetVst3Processor {
796 track_name: String,
797 instance_id: usize,
798 },
799 ClipGetVst3Processor {
800 track_name: String,
801 clip_idx: usize,
802 instance_id: usize,
803 },
804 TrackVst3Processor {
805 track_name: String,
806 instance_id: usize,
807 processor: Arc<crate::vst3::Vst3Processor>,
808 },
809 ClipVst3Processor {
810 track_name: String,
811 clip_idx: usize,
812 instance_id: usize,
813 processor: Arc<crate::vst3::Vst3Processor>,
814 },
815 TrackVst3SnapshotState {
816 track_name: String,
817 instance_id: usize,
818 },
819 ClipVst3SnapshotState {
820 track_name: String,
821 clip_idx: usize,
822 instance_id: usize,
823 },
824 TrackVst3StateSnapshot {
825 track_name: String,
826 instance_id: usize,
827 state: crate::vst3::state::Vst3PluginState,
828 },
829 ClipVst3StateSnapshot {
830 track_name: String,
831 clip_idx: usize,
832 instance_id: usize,
833 state: crate::vst3::state::Vst3PluginState,
834 },
835 TrackVst3RestoreState {
836 track_name: String,
837 instance_id: usize,
838 state: crate::vst3::state::Vst3PluginState,
839 },
840 TrackConnectVst3Audio {
841 track_name: String,
842 from_node: Vst3GraphNode,
843 from_port: usize,
844 to_node: Vst3GraphNode,
845 to_port: usize,
846 },
847 TrackDisconnectVst3Audio {
848 track_name: String,
849 from_node: Vst3GraphNode,
850 from_port: usize,
851 to_node: Vst3GraphNode,
852 to_port: usize,
853 },
854 ClipMove {
855 kind: Kind,
856 from: ClipMoveFrom,
857 to: ClipMoveTo,
858 copy: bool,
859 },
860 Connect {
861 from_track: String,
862 from_port: usize,
863 to_track: String,
864 to_port: usize,
865 kind: Kind,
866 },
867 Disconnect {
868 from_track: String,
869 from_port: usize,
870 to_track: String,
871 to_port: usize,
872 kind: Kind,
873 },
874 OpenAudioDevice {
875 device: String,
876 input_device: Option<String>,
877 sample_rate_hz: i32,
878 bits: i32,
879 exclusive: bool,
880 period_frames: usize,
881 nperiods: usize,
882 sync_mode: bool,
883 },
884 JackAddAudioInputPort,
885 JackRemoveAudioInputPort(usize),
886 JackAddAudioOutputPort,
887 JackRemoveAudioOutputPort(usize),
888 OpenMidiInputDevice(String),
889 OpenMidiOutputDevice(String),
890 RequestSessionDiagnostics,
891 RequestMidiLearnMappingsReport,
892 ClearAllMidiLearnBindings,
893 SessionDiagnosticsReport {
894 track_count: usize,
895 frozen_track_count: usize,
896 audio_clip_count: usize,
897 midi_clip_count: usize,
898 #[cfg(all(unix, not(target_os = "macos")))]
899 lv2_instance_count: usize,
900 vst3_instance_count: usize,
901 clap_instance_count: usize,
902 pending_requests: usize,
903 workers_total: usize,
904 workers_ready: usize,
905 pending_hw_midi_events: usize,
906 playing: bool,
907 transport_sample: usize,
908 tempo_bpm: f64,
909 sample_rate_hz: usize,
910 cycle_samples: usize,
911 },
912 MidiLearnMappingsReport {
913 lines: Vec<String>,
914 },
915 HWInfo {
916 channels: usize,
917 rate: usize,
918 input: bool,
919 },
920 Undo,
921 Redo,
922 Panic,
923}
924
925#[derive(Clone, Debug)]
926pub enum Message {
927 Ready(usize),
928 Finished {
929 worker_id: usize,
930 track_name: String,
931 output_linear: Vec<f32>,
932 process_epoch: usize,
933 },
934 TracksFinished,
935
936 ProcessTrack(Arc<UnsafeMutex<Box<Track>>>),
937 ProcessOfflineBounce(OfflineBounceWork),
938 Channel(Sender<Self>),
939
940 Request(Action),
941 Response(Result<Action, String>),
942 HWMidiEvents(Vec<HwMidiEvent>),
943 HWMidiOutEvents(Vec<HwMidiEvent>),
944 ClearHWMidiOutEvents,
945 HWFinished,
946 OfflineBounceFinished {
947 result: Result<Action, String>,
948 },
949}
950
951#[cfg(test)]
952mod tests {
953 use super::{AudioClipData, MidiClipData, PitchCorrectionPointData};
954 use serde_json::json;
955
956 #[test]
957 fn audio_clip_data_serde_round_trips_nested_groups() {
958 let clip = AudioClipData {
959 name: "group.wav".to_string(),
960 start: 12,
961 length: 96,
962 offset: 3,
963 input_channel: 1,
964 muted: true,
965 peaks_file: Some("peaks/group.json".to_string()),
966 fade_enabled: false,
967 fade_in_samples: 10,
968 fade_out_samples: 20,
969 preview_name: Some("preview.wav".to_string()),
970 source_name: Some("source.wav".to_string()),
971 source_offset: Some(4),
972 source_length: Some(88),
973 pitch_correction_points: vec![PitchCorrectionPointData {
974 start_sample: 7,
975 length_samples: 11,
976 detected_midi_pitch: 60.1,
977 target_midi_pitch: 61.2,
978 clarity: 0.8,
979 }],
980 pitch_correction_frame_likeness: Some(0.5),
981 pitch_correction_inertia_ms: Some(123),
982 pitch_correction_formant_compensation: Some(false),
983 plugin_graph_json: Some(json!({"plugins":[],"connections":[{"kind":"Audio"}]})),
984 grouped_clips: vec![AudioClipData {
985 name: "child.wav".to_string(),
986 start: 0,
987 length: 48,
988 ..AudioClipData::default()
989 }],
990 };
991
992 let value = serde_json::to_value(&clip).expect("serialize");
993 let restored: AudioClipData = serde_json::from_value(value).expect("deserialize");
994
995 assert_eq!(restored.name, clip.name);
996 assert_eq!(restored.preview_name, clip.preview_name);
997 assert_eq!(restored.source_name, clip.source_name);
998 assert_eq!(restored.plugin_graph_json, clip.plugin_graph_json);
999 assert_eq!(restored.grouped_clips.len(), 1);
1000 assert_eq!(restored.grouped_clips[0].name, "child.wav");
1001 assert_eq!(restored.pitch_correction_points[0].target_midi_pitch, 61.2);
1002 }
1003
1004 #[test]
1005 fn midi_clip_data_serde_round_trips_nested_groups() {
1006 let clip = MidiClipData {
1007 name: "group.mid".to_string(),
1008 start: 5,
1009 length: 64,
1010 offset: 2,
1011 input_channel: 3,
1012 muted: true,
1013 grouped_clips: vec![MidiClipData {
1014 name: "child.mid".to_string(),
1015 start: 0,
1016 length: 32,
1017 ..MidiClipData::default()
1018 }],
1019 };
1020
1021 let value = serde_json::to_value(&clip).expect("serialize");
1022 let restored: MidiClipData = serde_json::from_value(value).expect("deserialize");
1023
1024 assert_eq!(restored.name, clip.name);
1025 assert_eq!(restored.grouped_clips.len(), 1);
1026 assert_eq!(restored.grouped_clips[0].name, "child.mid");
1027 }
1028
1029 #[test]
1030 fn pitch_correction_point_data_serde_round_trips() {
1031 let point = PitchCorrectionPointData {
1032 start_sample: 10,
1033 length_samples: 20,
1034 detected_midi_pitch: 57.5,
1035 target_midi_pitch: 58.0,
1036 clarity: 0.9,
1037 };
1038
1039 let value = serde_json::to_value(&point).expect("serialize");
1040 let restored: PitchCorrectionPointData =
1041 serde_json::from_value(value).expect("deserialize");
1042
1043 assert_eq!(restored.start_sample, 10);
1044 assert_eq!(restored.length_samples, 20);
1045 assert_eq!(restored.detected_midi_pitch, 57.5);
1046 assert_eq!(restored.target_midi_pitch, 58.0);
1047 assert_eq!(restored.clarity, 0.9);
1048 }
1049
1050 #[test]
1051 fn audio_clip_data_deserializes_with_omitted_optional_fields() {
1052 let restored: AudioClipData = serde_json::from_value(json!({
1053 "name": "clip.wav",
1054 "start": 1,
1055 "length": 2,
1056 "offset": 3,
1057 "input_channel": 0,
1058 "muted": false,
1059 "fade_enabled": true,
1060 "fade_in_samples": 240,
1061 "fade_out_samples": 240,
1062 "pitch_correction_points": [],
1063 "grouped_clips": []
1064 }))
1065 .expect("deserialize");
1066
1067 assert_eq!(restored.name, "clip.wav");
1068 assert!(restored.peaks_file.is_none());
1069 assert!(restored.preview_name.is_none());
1070 assert!(restored.source_name.is_none());
1071 assert!(restored.source_offset.is_none());
1072 assert!(restored.source_length.is_none());
1073 assert!(restored.pitch_correction_points.is_empty());
1074 assert!(restored.plugin_graph_json.is_none());
1075 }
1076}