From 7656a53446a7a22fdb4539926691adea2dcfe060 Mon Sep 17 00:00:00 2001 From: PolyMeilex Date: Wed, 10 Jan 2024 19:58:08 +0100 Subject: [PATCH] Remove Rc> from OutputManager --- neothesia/src/output_manager/midi_backend.rs | 45 +++++++------ neothesia/src/output_manager/mod.rs | 63 ++++++++++++------- neothesia/src/output_manager/synth_backend.rs | 20 +++--- .../src/scene/menu_scene/iced_menu/mod.rs | 4 +- .../src/scene/playing_scene/midi_player.rs | 18 +++--- neothesia/src/target.rs | 5 +- 6 files changed, 91 insertions(+), 64 deletions(-) diff --git a/neothesia/src/output_manager/midi_backend.rs b/neothesia/src/output_manager/midi_backend.rs index 252ec6bc..ab9a60cc 100644 --- a/neothesia/src/output_manager/midi_backend.rs +++ b/neothesia/src/output_manager/midi_backend.rs @@ -1,6 +1,6 @@ -use std::collections::HashSet; +use std::{cell::RefCell, collections::HashSet, rc::Rc}; -use crate::output_manager::{OutputConnection, OutputDescriptor}; +use crate::output_manager::{OutputConnectionProxy, OutputDescriptor}; use midi_file::midly::{ self, @@ -14,18 +14,25 @@ struct ActiveNote { channel: u4, } -pub struct MidiOutputConnection { +struct MidiOutputConnectionInner { conn: midi_io::MidiOutputConnection, active_notes: HashSet, buf: Vec, } +#[derive(Clone)] +pub struct MidiOutputConnection { + inner: Rc>, +} + impl From for MidiOutputConnection { fn from(conn: midi_io::MidiOutputConnection) -> Self { Self { - conn, - active_notes: Default::default(), - buf: Vec::with_capacity(8), + inner: Rc::new(RefCell::new(MidiOutputConnectionInner { + conn, + active_notes: Default::default(), + buf: Vec::with_capacity(8), + })), } } } @@ -55,28 +62,30 @@ impl MidiBackend { } } -impl OutputConnection for MidiOutputConnection { - fn midi_event(&mut self, channel: u4, message: midly::MidiMessage) { +impl OutputConnectionProxy for MidiOutputConnection { + fn midi_event(&self, channel: u4, message: midly::MidiMessage) { + let inner = &mut *self.inner.borrow_mut(); match message { midly::MidiMessage::NoteOff { key, .. } => { - self.active_notes.remove(&ActiveNote { key, channel }); + inner.active_notes.remove(&ActiveNote { key, channel }); } midly::MidiMessage::NoteOn { key, .. } => { - self.active_notes.insert(ActiveNote { key, channel }); + inner.active_notes.insert(ActiveNote { key, channel }); } _ => {} } - self.buf.clear(); + inner.buf.clear(); let msg = midly::live::LiveEvent::Midi { channel, message }; - msg.write(&mut self.buf).unwrap(); + msg.write(&mut inner.buf).unwrap(); - self.conn.send(&self.buf).ok(); + inner.conn.send(&inner.buf).ok(); } - fn stop_all(&mut self) { - for note in std::mem::take(&mut self.active_notes).iter() { - self.buf.clear(); + fn stop_all(&self) { + let inner = &mut *self.inner.borrow_mut(); + for note in std::mem::take(&mut inner.active_notes).iter() { + inner.buf.clear(); let msg = LiveEvent::Midi { channel: note.channel, message: midly::MidiMessage::NoteOff { @@ -84,9 +93,9 @@ impl OutputConnection for MidiOutputConnection { vel: u7::new(0), }, }; - msg.write(&mut self.buf).unwrap(); + msg.write(&mut inner.buf).unwrap(); - self.conn.send(&self.buf).ok(); + inner.conn.send(&inner.buf).ok(); } } } diff --git a/neothesia/src/output_manager/mod.rs b/neothesia/src/output_manager/mod.rs index a993a4c5..4451c440 100644 --- a/neothesia/src/output_manager/mod.rs +++ b/neothesia/src/output_manager/mod.rs @@ -33,15 +33,36 @@ impl Display for OutputDescriptor { } } -pub trait OutputConnection { - fn midi_event(&mut self, channel: u4, msg: MidiMessage); - fn stop_all(&mut self); +trait OutputConnectionProxy { + fn midi_event(&self, channel: u4, msg: MidiMessage); + fn stop_all(&self); } -struct DummyOutput {} -impl OutputConnection for DummyOutput { - fn midi_event(&mut self, _channel: u4, _msg: MidiMessage) {} - fn stop_all(&mut self) {} +#[derive(Clone)] +pub enum OutputConnection { + Midi(midi_backend::MidiOutputConnection), + #[cfg(feature = "synth")] + Synth(synth_backend::SynthOutputConnection), + DummyOutput, +} + +impl OutputConnection { + pub fn midi_event(&self, channel: u4, msg: MidiMessage) { + match self { + OutputConnection::Midi(b) => b.midi_event(channel, msg), + #[cfg(feature = "synth")] + OutputConnection::Synth(b) => b.midi_event(channel, msg), + OutputConnection::DummyOutput => {} + } + } + pub fn stop_all(&self) { + match self { + OutputConnection::Midi(b) => b.stop_all(), + #[cfg(feature = "synth")] + OutputConnection::Synth(b) => b.stop_all(), + OutputConnection::DummyOutput => {} + } + } } pub struct OutputManager { @@ -49,7 +70,7 @@ pub struct OutputManager { synth_backend: Option, midi_backend: Option, - output_connection: (OutputDescriptor, Box), + output_connection: (OutputDescriptor, OutputConnection), } impl Default for OutputManager { @@ -82,7 +103,7 @@ impl OutputManager { synth_backend, midi_backend, - output_connection: (OutputDescriptor::DummyOutput, Box::new(DummyOutput {})), + output_connection: (OutputDescriptor::DummyOutput, OutputConnection::DummyOutput), } } @@ -109,33 +130,33 @@ impl OutputManager { OutputDescriptor::Synth(ref font) => { if let Some(ref mut synth) = self.synth_backend { if let Some(font) = font.clone() { - self.output_connection = - (desc, Box::new(synth.new_output_connection(&font))); + self.output_connection = ( + desc, + OutputConnection::Synth(synth.new_output_connection(&font)), + ); } else if let Some(path) = crate::utils::resources::default_sf2() { if path.exists() { - self.output_connection = - (desc, Box::new(synth.new_output_connection(&path))); + self.output_connection = ( + desc, + OutputConnection::Synth(synth.new_output_connection(&path)), + ); } } } } OutputDescriptor::MidiOut(ref info) => { if let Some(conn) = MidiBackend::new_output_connection(info) { - self.output_connection = (desc, Box::new(conn)); + self.output_connection = (desc, OutputConnection::Midi(conn)); } } OutputDescriptor::DummyOutput => { - self.output_connection = (desc, Box::new(DummyOutput {})); + self.output_connection = (desc, OutputConnection::DummyOutput); } } } } - pub fn midi_event(&mut self, channel: u4, msg: MidiMessage) { - self.output_connection.1.midi_event(channel, msg); - } - - pub fn stop_all(&mut self) { - self.output_connection.1.stop_all(); + pub fn connection(&self) -> &OutputConnection { + &self.output_connection.1 } } diff --git a/neothesia/src/output_manager/synth_backend.rs b/neothesia/src/output_manager/synth_backend.rs index 577419ed..788767e5 100644 --- a/neothesia/src/output_manager/synth_backend.rs +++ b/neothesia/src/output_manager/synth_backend.rs @@ -1,6 +1,6 @@ -use std::{error::Error, path::Path, sync::mpsc::Receiver}; +use std::{error::Error, path::Path, rc::Rc, sync::mpsc::Receiver}; -use crate::output_manager::{OutputConnection, OutputDescriptor}; +use crate::output_manager::{OutputConnectionProxy, OutputDescriptor}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use midi_file::midly::{self, num::u4}; @@ -82,7 +82,7 @@ impl SynthBackend { pub fn new_output_connection(&mut self, path: &Path) -> SynthOutputConnection { let (tx, rx) = std::sync::mpsc::channel::(); - let _stream = match self.sample_format { + let stream = match self.sample_format { cpal::SampleFormat::I8 => self.run::(rx, path), cpal::SampleFormat::I16 => self.run::(rx, path), cpal::SampleFormat::I32 => self.run::(rx, path), @@ -98,7 +98,10 @@ impl SynthBackend { sample_format => unimplemented!("Unsupported sample format '{sample_format}'"), }; - SynthOutputConnection { _stream, tx } + SynthOutputConnection { + _stream: Rc::new(stream), + tx, + } } pub fn get_outputs(&self) -> Vec { @@ -106,18 +109,19 @@ impl SynthBackend { } } +#[derive(Clone)] pub struct SynthOutputConnection { - _stream: cpal::Stream, + _stream: Rc, tx: std::sync::mpsc::Sender, } -impl OutputConnection for SynthOutputConnection { - fn midi_event(&mut self, channel: u4, msg: midly::MidiMessage) { +impl OutputConnectionProxy for SynthOutputConnection { + fn midi_event(&self, channel: u4, msg: midly::MidiMessage) { let event = libmidi_to_oxisynth_event(channel, msg); self.tx.send(event).ok(); } - fn stop_all(&mut self) { + fn stop_all(&self) { for channel in 0..16 { self.tx .send(oxisynth::MidiEvent::AllNotesOff { channel }) diff --git a/neothesia/src/scene/menu_scene/iced_menu/mod.rs b/neothesia/src/scene/menu_scene/iced_menu/mod.rs index 69b3d093..66186c5d 100644 --- a/neothesia/src/scene/menu_scene/iced_menu/mod.rs +++ b/neothesia/src/scene/menu_scene/iced_menu/mod.rs @@ -99,7 +99,7 @@ impl Program for AppUi { o => o, }; - target.output_manager.borrow_mut().connect(out) + target.output_manager.connect(out) } if let Some(port) = self.data.selected_input.clone() { @@ -113,7 +113,7 @@ impl Program for AppUi { } } Message::Tick => { - self.data.outputs = target.output_manager.borrow().outputs(); + self.data.outputs = target.output_manager.outputs(); self.data.inputs = target.input_manager.inputs(); if self.data.selected_output.is_none() { diff --git a/neothesia/src/scene/playing_scene/midi_player.rs b/neothesia/src/scene/playing_scene/midi_player.rs index b6407acd..1cee79ac 100644 --- a/neothesia/src/scene/playing_scene/midi_player.rs +++ b/neothesia/src/scene/playing_scene/midi_player.rs @@ -1,20 +1,18 @@ use midi_file::midly::{num::u4, MidiMessage}; use crate::{ - output_manager::OutputManager, + output_manager::OutputConnection, song::{PlayerConfig, Song}, target::Target, }; use std::{ - cell::RefCell, collections::{HashSet, VecDeque}, - rc::Rc, time::{Duration, Instant}, }; pub struct MidiPlayer { playback: midi_file::PlaybackState, - output_manager: Rc>, + output: OutputConnection, song: Song, play_along: PlayAlong, } @@ -30,7 +28,7 @@ impl MidiPlayer { Duration::from_secs(3), song.file.tracks.clone(), ), - output_manager: target.output_manager.clone(), + output: target.output_manager.connection().clone(), play_along: PlayAlong::new(user_keyboard_range), song, }; @@ -58,16 +56,14 @@ impl MidiPlayer { match config.player { PlayerConfig::Auto => { - self.output_manager - .borrow_mut() + self.output .midi_event(u4::new(event.channel), event.message); } PlayerConfig::Human => { // Let's play the sound, in case the user does not want it they can just set // no-output output in settings // TODO: Perhaps play on midi-in instead - self.output_manager - .borrow_mut() + self.output .midi_event(u4::new(event.channel), event.message); self.play_along .midi_event(MidiEventSource::File, &event.message); @@ -80,7 +76,7 @@ impl MidiPlayer { } fn clear(&mut self) { - self.output_manager.borrow_mut().stop_all(); + self.output.stop_all(); } } @@ -111,7 +107,7 @@ impl MidiPlayer { fn send_midi_programs_for_timestamp(&self, time: &Duration) { for (&channel, &p) in self.song.file.program_track.program_for_timestamp(time) { - self.output_manager.borrow_mut().midi_event( + self.output.midi_event( u4::new(channel), midi_file::midly::MidiMessage::ProgramChange { program: midi_file::midly::num::u7::new(p), diff --git a/neothesia/src/target.rs b/neothesia/src/target.rs index 6ed4dfbb..a74eb768 100644 --- a/neothesia/src/target.rs +++ b/neothesia/src/target.rs @@ -1,6 +1,3 @@ -use std::cell::RefCell; -use std::rc::Rc; - use crate::config::Config; use crate::input_manager::InputManager; use crate::render::TextRenderer; @@ -24,7 +21,7 @@ pub struct Target { pub text_renderer: TextRenderer, - pub output_manager: Rc>, + pub output_manager: OutputManager, pub input_manager: InputManager, pub song: Option, pub config: Config,