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