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