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