use crate::enums::led_light::color::LedColor;
use crate::enums::led_light::mode::LedMode;
use crate::errors::io::{ChannelCreationError, TransmissionError};
use crate::io::channel::Channel;
use bon::bon;
use midir::{MidiOutput, MidiOutputConnection};
pub struct ChannelOutput {
output_connection: MidiOutputConnection,
}
#[bon]
impl ChannelOutput {
#[builder]
pub fn new(
port: Option<usize>,
initialize_note_led: Option<bool>,
port_name: Option<&str>,
) -> Result<Self, ChannelCreationError> {
let midi_output = Self::get_midi()?;
let out_ports = midi_output.ports();
let chosen_port = port.unwrap_or(2);
let out_port = out_ports
.get(chosen_port)
.ok_or(ChannelCreationError::PortOutOfRange(chosen_port))?;
let mut output_connection = midi_output
.connect(out_port, port_name.unwrap_or("akai-midir-write-output"))
.map_err(|e| ChannelCreationError::EstablishingOutputConnection { source: e })?;
if initialize_note_led.unwrap_or(false) {
initialize_pads_led(&mut output_connection)
.map_err(|e| ChannelCreationError::LedInitialization { source: e })?;
}
Ok(Self { output_connection })
}
pub fn send(&mut self, data: &[u8]) -> Result<(), TransmissionError> {
send(&mut self.output_connection, data)
}
pub fn initialize_notes_led(&mut self) -> Result<(), TransmissionError> {
initialize_pads_led(&mut self.output_connection)
}
pub fn set_all_pads_color(
&mut self,
led_mode: LedMode,
color: LedColor,
) -> Result<(), TransmissionError> {
initialize_pads_led(&mut self.output_connection)?;
for i in 0..=86 {
self.set_pad_led(led_mode, i, color)?;
}
Ok(())
}
pub fn set_pad_led<T>(
&mut self,
led_mode: LedMode,
note: T,
color: LedColor,
) -> Result<(), TransmissionError>
where
T: Into<u8>,
{
let led_msg = [led_mode.into(), note.into(), color.into()];
self.send(led_msg.as_ref())
}
}
impl Channel for ChannelOutput {
#[allow(refining_impl_trait)]
fn get_midi() -> Result<MidiOutput, ChannelCreationError> {
MidiOutput::new("akai midir writing output")
.map_err(|e| ChannelCreationError::InitializingChannel { source: e })
}
}
fn initialize_pads_led(
output_connection: &mut MidiOutputConnection,
) -> Result<(), TransmissionError> {
let init_sysex: Vec<u8> = vec![
0xF0, 0x47, 0x7F, 0x29, 0x60, 0x00, 0x04, 0x42, 0x08, 0x02, 0x01, 0xF7, ];
send(output_connection, &init_sysex)
}
fn send(
output_connection: &mut MidiOutputConnection,
data: &[u8],
) -> Result<(), TransmissionError> {
output_connection
.send(data)
.map_err(|e| TransmissionError::Send {
data: data.to_vec(),
source: e,
})
}