Feat: begin slight refactoring
This commit is contained in:
105
src/midi.rs
105
src/midi.rs
@@ -2,10 +2,53 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use midir::{MidiInput, MidiOutput};
|
||||
|
||||
use crate::model::CcMemory;
|
||||
use cagire_forth::CcAccess;
|
||||
|
||||
pub const MAX_MIDI_OUTPUTS: usize = 4;
|
||||
pub const MAX_MIDI_INPUTS: usize = 4;
|
||||
pub const MAX_MIDI_DEVICES: usize = 4;
|
||||
|
||||
/// Raw CC memory storage type
|
||||
type CcMemoryInner = Arc<Mutex<[[[u8; 128]; 16]; MAX_MIDI_DEVICES]>>;
|
||||
|
||||
/// CC memory storage: [device][channel][cc_number] -> value
|
||||
/// Wrapped in a newtype to implement CcAccess (orphan rule)
|
||||
#[derive(Clone)]
|
||||
pub struct CcMemory(CcMemoryInner);
|
||||
|
||||
impl CcMemory {
|
||||
pub fn new() -> Self {
|
||||
Self(Arc::new(Mutex::new([[[0u8; 128]; 16]; MAX_MIDI_DEVICES])))
|
||||
}
|
||||
|
||||
fn inner(&self) -> &CcMemoryInner {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Set a CC value (for testing)
|
||||
#[allow(dead_code)]
|
||||
pub fn set_cc(&self, device: usize, channel: usize, cc: usize, value: u8) {
|
||||
if let Ok(mut mem) = self.0.lock() {
|
||||
mem[device.min(MAX_MIDI_DEVICES - 1)][channel.min(15)][cc.min(127)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CcMemory {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl CcAccess for CcMemory {
|
||||
fn get_cc(&self, device: usize, channel: usize, cc: usize) -> u8 {
|
||||
self.0
|
||||
.lock()
|
||||
.ok()
|
||||
.map(|mem| mem[device.min(MAX_MIDI_DEVICES - 1)][channel.min(15)][cc.min(127)])
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MidiDeviceInfo {
|
||||
@@ -46,7 +89,7 @@ pub fn list_midi_inputs() -> Vec<MidiDeviceInfo> {
|
||||
|
||||
pub struct MidiState {
|
||||
output_conns: [Option<midir::MidiOutputConnection>; MAX_MIDI_OUTPUTS],
|
||||
input_conns: [Option<midir::MidiInputConnection<(CcMemory, usize)>>; MAX_MIDI_INPUTS],
|
||||
input_conns: [Option<midir::MidiInputConnection<(CcMemoryInner, usize)>>; MAX_MIDI_INPUTS],
|
||||
pub selected_outputs: [Option<usize>; MAX_MIDI_OUTPUTS],
|
||||
pub selected_inputs: [Option<usize>; MAX_MIDI_INPUTS],
|
||||
pub cc_memory: CcMemory,
|
||||
@@ -65,7 +108,7 @@ impl MidiState {
|
||||
input_conns: [None, None, None, None],
|
||||
selected_outputs: [None; MAX_MIDI_OUTPUTS],
|
||||
selected_inputs: [None; MAX_MIDI_INPUTS],
|
||||
cc_memory: Arc::new(Mutex::new([[[0u8; 128]; 16]; MAX_MIDI_OUTPUTS])),
|
||||
cc_memory: CcMemory::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +142,7 @@ impl MidiState {
|
||||
let ports = midi_in.ports();
|
||||
let port = ports.get(port_index).ok_or("MIDI input port not found")?;
|
||||
|
||||
let cc_mem = Arc::clone(&self.cc_memory);
|
||||
let cc_mem = Arc::clone(self.cc_memory.inner());
|
||||
let conn = midi_in
|
||||
.connect(
|
||||
port,
|
||||
@@ -133,60 +176,46 @@ impl MidiState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_note_on(&mut self, device: u8, channel: u8, note: u8, velocity: u8) {
|
||||
fn send_message(&mut self, device: u8, message: &[u8]) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0x90 | (channel & 0x0F);
|
||||
let _ = conn.send(&[status, note & 0x7F, velocity & 0x7F]);
|
||||
let _ = conn.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_note_on(&mut self, device: u8, channel: u8, note: u8, velocity: u8) {
|
||||
let status = 0x90 | (channel & 0x0F);
|
||||
self.send_message(device, &[status, note & 0x7F, velocity & 0x7F]);
|
||||
}
|
||||
|
||||
pub fn send_note_off(&mut self, device: u8, channel: u8, note: u8) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0x80 | (channel & 0x0F);
|
||||
let _ = conn.send(&[status, note & 0x7F, 0]);
|
||||
}
|
||||
let status = 0x80 | (channel & 0x0F);
|
||||
self.send_message(device, &[status, note & 0x7F, 0]);
|
||||
}
|
||||
|
||||
pub fn send_cc(&mut self, device: u8, channel: u8, cc: u8, value: u8) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0xB0 | (channel & 0x0F);
|
||||
let _ = conn.send(&[status, cc & 0x7F, value & 0x7F]);
|
||||
}
|
||||
let status = 0xB0 | (channel & 0x0F);
|
||||
self.send_message(device, &[status, cc & 0x7F, value & 0x7F]);
|
||||
}
|
||||
|
||||
pub fn send_pitch_bend(&mut self, device: u8, channel: u8, value: u16) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0xE0 | (channel & 0x0F);
|
||||
let lsb = (value & 0x7F) as u8;
|
||||
let msb = ((value >> 7) & 0x7F) as u8;
|
||||
let _ = conn.send(&[status, lsb, msb]);
|
||||
}
|
||||
let status = 0xE0 | (channel & 0x0F);
|
||||
let lsb = (value & 0x7F) as u8;
|
||||
let msb = ((value >> 7) & 0x7F) as u8;
|
||||
self.send_message(device, &[status, lsb, msb]);
|
||||
}
|
||||
|
||||
pub fn send_pressure(&mut self, device: u8, channel: u8, value: u8) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0xD0 | (channel & 0x0F);
|
||||
let _ = conn.send(&[status, value & 0x7F]);
|
||||
}
|
||||
let status = 0xD0 | (channel & 0x0F);
|
||||
self.send_message(device, &[status, value & 0x7F]);
|
||||
}
|
||||
|
||||
pub fn send_program_change(&mut self, device: u8, channel: u8, program: u8) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let status = 0xC0 | (channel & 0x0F);
|
||||
let _ = conn.send(&[status, program & 0x7F]);
|
||||
}
|
||||
let status = 0xC0 | (channel & 0x0F);
|
||||
self.send_message(device, &[status, program & 0x7F]);
|
||||
}
|
||||
|
||||
pub fn send_realtime(&mut self, device: u8, msg: u8) {
|
||||
let slot = (device as usize).min(MAX_MIDI_OUTPUTS - 1);
|
||||
if let Some(conn) = &mut self.output_conns[slot] {
|
||||
let _ = conn.send(&[msg]);
|
||||
}
|
||||
self.send_message(device, &[msg]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user