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