launchkey_sdk/launchkey/
manager.rs1use crate::launchkey::bitmap::LaunchkeyBitmap;
2use crate::launchkey::commands::LaunchkeyCommand;
3use crate::launchkey::constants::{LaunchKeySku, DISABLE_DAW_MODE, ENABLE_DAW_MODE};
4use crate::launchkey::modes::encoder_mode::EncoderMode;
5use crate::launchkey::modes::fader_mode::FaderMode;
6use crate::launchkey::modes::pad_mode::PadMode;
7use crate::launchkey::surface::display::{Arrangement, GlobalDisplayTarget};
8use midir::{MidiOutput, MidiOutputPort};
9use std::any::TypeId;
10use std::cell::RefCell;
11use std::marker::PhantomData;
12use std::rc::Rc;
13use crate::launchkey::error::{LaunchkeyError, LaunchkeyInitError, MidiSendError};
14use crate::midi::to_hex::ToHexString;
15
16pub trait LaunchKeyState {}
18
19pub struct DAWMode;
21impl LaunchKeyState for DAWMode {}
22
23pub struct StandaloneMode;
25impl LaunchKeyState for StandaloneMode {}
26
27pub struct LaunchkeyManager<S: LaunchKeyState + 'static> {
30 conn_out: Rc<RefCell<midir::MidiOutputConnection>>,
31 sku: LaunchKeySku,
32 state: PhantomData<S>,
33}
34
35impl<S: LaunchKeyState> LaunchkeyManager<S> {
36 fn _enable_daw_mode(&mut self) -> Result<(), MidiSendError> {
38 println!("Enabling DAW Mode");
39 self._send_bytes(&ENABLE_DAW_MODE)
40 }
41
42 fn _disable_daw_mode(&mut self) -> Result<(), MidiSendError> {
44 println!("Disabling DAW Mode");
45 self._send_bytes(&DISABLE_DAW_MODE)
46 }
47
48 fn _send_command(&mut self, command: LaunchkeyCommand) -> Result<(), MidiSendError> {
50 match command {
51 LaunchkeyCommand::SetPadMode(ref pad_mode) => {
52 match pad_mode {
53 PadMode::Drum => self._send_command(LaunchkeyCommand::SetDrumDAWMode(false)),
54 PadMode::DrumDAW => self._send_command(LaunchkeyCommand::SetDrumDAWMode(true)),
55 _ => Ok(()),
56 }?;
57 self._send_bytes(&command.as_bytes(&self.sku))
58 }
59 command => self._send_bytes(&command.as_bytes(&self.sku)),
60 }
61 }
62
63 fn _send_bytes(&mut self, bytes: &[u8]) -> Result<(), MidiSendError> {
65 println!("Sending MIDI message: {}", &bytes.to_hex_string());
66 self.conn_out.borrow_mut().send(bytes)?;
67 Ok(())
68 }
69}
70
71impl LaunchkeyManager<StandaloneMode> {
72 pub fn new(
74 midi_out: MidiOutput,
75 port: &MidiOutputPort,
76 sku: LaunchKeySku,
77 ) -> Result<Self, LaunchkeyInitError> {
78 let conn_out = midi_out
79 .connect(port, "launchkey-manager")
80 .map_err(LaunchkeyInitError::MidiConnectError)?;
81 Ok(Self {
82 conn_out: Rc::new(RefCell::new(conn_out)),
83 sku,
84 state: PhantomData,
85 })
86 }
87
88 pub fn default() -> Result<Self, LaunchkeyInitError> {
90 let midi_out = MidiOutput::new("Custom DAW")?;
92
93 let ports = midi_out.ports();
94 if ports.is_empty() {
95 return Err(LaunchkeyInitError::DeviceNotFound("No MIDI output ports found".to_string()));
96 }
97
98 let out_port = ports
100 .iter()
101 .find(|port| {
102 midi_out
103 .port_name(port)
104 .unwrap_or_default()
105 .contains("MIDIOUT2")
106 })
107 .ok_or_else(|| LaunchkeyInitError::DeviceNotFound("Could not find MIDIOUT2 port".to_string()))?;
108
109 Self::new(midi_out, out_port, LaunchKeySku::Mini)
110 }
111
112 pub fn set_screen_text_global(
114 &mut self,
115 target: GlobalDisplayTarget,
116 arrangement: Arrangement,
117 ) -> Result<(), MidiSendError> {
118 self._send_command(LaunchkeyCommand::SetScreenTextGlobal {
119 target,
120 arrangement,
121 })
122 }
123
124 pub fn send_screen_bitmap(
126 &mut self,
127 target: GlobalDisplayTarget,
128 bitmap: LaunchkeyBitmap,
129 ) -> Result<(), MidiSendError> {
130 self._send_command(LaunchkeyCommand::SendScreenBitmap {
131 target,
132 bitmap: Box::new(bitmap),
133 })
134 }
135
136 pub fn into_daw_mode(mut self) -> Result<LaunchkeyManager<DAWMode>, LaunchkeyError> {
138 self._enable_daw_mode()?;
139 Ok(LaunchkeyManager {
140 conn_out: self.conn_out.clone(),
141 sku: self.sku.clone(),
142 state: PhantomData,
143 })
144 }
145}
146
147impl LaunchkeyManager<DAWMode> {
148 pub fn into_standalone_mode(
150 mut self,
151 ) -> Result<LaunchkeyManager<StandaloneMode>, LaunchkeyError> {
152 self._disable_daw_mode()?;
153 Ok(LaunchkeyManager {
154 conn_out: self.conn_out.clone(),
155 sku: self.sku.clone(),
156 state: PhantomData,
157 })
158 }
159
160 pub fn setup_default_element_modes(&mut self) -> Result<(), LaunchkeyError> {
162 self.send_command(LaunchkeyCommand::SetPadMode(PadMode::DAW))?;
163 self.send_command(LaunchkeyCommand::SetEncoderMode(EncoderMode::Plugin))?;
164 self.send_command(LaunchkeyCommand::SetFaderMode(FaderMode::Volume))?;
165
166 Ok(())
167 }
168
169 pub fn send_command(&mut self, command: LaunchkeyCommand) -> Result<(), MidiSendError> {
171 self._send_command(command)
172 }
173
174 pub fn send_commands(&mut self, commands: &[LaunchkeyCommand]) -> Result<(), MidiSendError> {
176 for command in commands {
177 self._send_command((*command).clone())?;
178 }
179 Ok(()) }
181}
182
183impl<S: LaunchKeyState + 'static> Drop for LaunchkeyManager<S> {
184 fn drop(&mut self) {
185 if TypeId::of::<S>() == TypeId::of::<DAWMode>() {
187 if let Err(err) = self._disable_daw_mode() {
188 eprintln!("Failed to disable DAW mode during cleanup: {}", err);
189 }
190 }
191 }
192}