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