use std::fmt;
use midir::MidiOutputConnection;
use crate::engine::TuringMachine;
use crate::error::Error;
use crate::outputs::StepOutputs;
pub struct MidiTuringMachine {
engine: TuringMachine,
conn_out: MidiOutputConnection,
channel: u8,
note_cc: Option<u8>,
velocity_cc: Option<u8>,
noise_cc_num: Option<u8>,
gate_note: u8,
last_note: Option<u8>,
}
impl fmt::Debug for MidiTuringMachine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MidiTuringMachine")
.field("engine", &self.engine)
.field("channel", &self.channel)
.field("note_cc", &self.note_cc)
.field("velocity_cc", &self.velocity_cc)
.field("noise_cc_num", &self.noise_cc_num)
.field("gate_note", &self.gate_note)
.field("last_note", &self.last_note)
.field("conn_out", &"<MidiOutputConnection>")
.finish()
}
}
impl MidiTuringMachine {
#[must_use]
pub fn new(engine: TuringMachine, conn_out: MidiOutputConnection, channel: u8) -> Self {
Self {
engine,
conn_out,
channel: channel.min(15),
note_cc: None,
velocity_cc: None,
noise_cc_num: None,
gate_note: 60,
last_note: None,
}
}
pub fn tick(&mut self) -> Result<StepOutputs, Error> {
let outputs = self.engine.tick();
if let Some(prev) = self.last_note {
self.conn_out.send(&[0x80 | self.channel, prev, 0])?;
}
if outputs.gate {
if let Some(note) = outputs.note {
let velocity = outputs.velocity.unwrap_or(64);
self.conn_out.send(&[0x90 | self.channel, note, velocity])?;
self.last_note = Some(note);
}
} else {
self.last_note = None;
}
if let Some(cc_num) = self.noise_cc_num {
self.conn_out
.send(&[0xB0 | self.channel, cc_num, outputs.noise_cc])?;
}
if let Some(cc_num) = self.note_cc
&& let Some(note) = outputs.note
{
self.conn_out.send(&[0xB0 | self.channel, cc_num, note])?;
}
if let Some(cc_num) = self.velocity_cc
&& let Some(velocity) = outputs.velocity
{
self.conn_out
.send(&[0xB0 | self.channel, cc_num, velocity])?;
}
Ok(outputs)
}
pub fn all_notes_off(&mut self) -> Result<(), Error> {
if let Some(note) = self.last_note.take() {
self.conn_out.send(&[0x80 | self.channel, note, 0])?;
}
Ok(())
}
pub fn set_channel(&mut self, channel: u8) {
self.channel = channel.min(15);
}
pub fn route_noise_to_cc(&mut self, cc: u8) {
self.noise_cc_num = Some(cc & 0x7F);
}
pub fn route_note_to_cc(&mut self, cc: u8) {
self.note_cc = Some(cc & 0x7F);
}
pub fn route_velocity_to_cc(&mut self, cc: u8) {
self.velocity_cc = Some(cc & 0x7F);
}
#[must_use]
pub fn engine(&self) -> &TuringMachine {
&self.engine
}
pub fn engine_mut(&mut self) -> &mut TuringMachine {
&mut self.engine
}
}