From 8db880e2d702eeb6adc8e56a98624f949e079e60 Mon Sep 17 00:00:00 2001 From: Poly Date: Wed, 2 Dec 2020 18:43:32 +0100 Subject: [PATCH] Improve Output Selectrion --- src/output_manager/midi_backend.rs | 21 +++++++-- src/output_manager/mod.rs | 37 ++++++++------- src/scene/menu_scene/iced_menu.rs | 75 ++++++++++++++++++------------ src/scene/menu_scene/mod.rs | 38 +++++++++------ 4 files changed, 105 insertions(+), 66 deletions(-) diff --git a/src/output_manager/midi_backend.rs b/src/output_manager/midi_backend.rs index 63f395a5..6c229ebe 100644 --- a/src/output_manager/midi_backend.rs +++ b/src/output_manager/midi_backend.rs @@ -15,17 +15,21 @@ impl MidiBackend { pub fn get_outputs(&self) -> Vec { let mut outs = Vec::new(); let ports = self.midi_out.ports(); - for p in ports { + for (id, p) in ports.into_iter().enumerate() { let name = match self.midi_out.port_name(&p).ok() { Some(name) => name, None => String::from("Unknown"), }; - outs.push(OutputDescriptor::MidiOut(MidiPortInfo { port: p, name })) + outs.push(OutputDescriptor::MidiOut(MidiPortInfo { + id, + port: p, + name, + })) } outs } - pub fn new_output_connection(port: MidiPortInfo) -> Option { + pub fn new_output_connection(port: &MidiPortInfo) -> Option { let midi_out = MidiOutput::new("midi_out_conn").ok(); if let Some(midi_out) = midi_out { @@ -47,8 +51,15 @@ impl OutputConnection for MidiOutputConnection { #[derive(Clone)] pub struct MidiPortInfo { - pub port: MidiOutputPort, - pub name: String, + id: usize, + port: MidiOutputPort, + name: String, +} + +impl PartialEq for MidiPortInfo { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.name == other.name + } } impl std::fmt::Display for MidiPortInfo { diff --git a/src/output_manager/mod.rs b/src/output_manager/mod.rs index 3ceeecc6..d932b0a7 100644 --- a/src/output_manager/mod.rs +++ b/src/output_manager/mod.rs @@ -9,7 +9,7 @@ use std::{ path::Path, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum OutputDescriptor { Synth, MidiOut(MidiPortInfo), @@ -38,7 +38,9 @@ pub struct OutputManager { synth_backend: Option, midi_backend: Option, - output_connection: Box, + output_connection: (OutputDescriptor, Box), + + pub selected_output_id: Option, } impl OutputManager { @@ -62,7 +64,8 @@ impl OutputManager { synth_backend, midi_backend, - output_connection: Box::new(DummyOutput {}), + output_connection: (OutputDescriptor::DummyOutput, Box::new(DummyOutput {})), + selected_output_id: None, } } @@ -82,28 +85,30 @@ impl OutputManager { } pub fn connect(&mut self, desc: OutputDescriptor) { - match desc { - OutputDescriptor::Synth => { - if let Some(ref mut synth) = self.synth_backend { - self.output_connection = Box::new(synth.new_output_connection()); + if desc != self.output_connection.0 { + match desc { + OutputDescriptor::Synth => { + if let Some(ref mut synth) = self.synth_backend { + self.output_connection = (desc, Box::new(synth.new_output_connection())); + } } - } - OutputDescriptor::MidiOut(info) => { - if let Some(conn) = MidiBackend::new_output_connection(info) { - self.output_connection = Box::new(conn); + OutputDescriptor::MidiOut(ref info) => { + if let Some(conn) = MidiBackend::new_output_connection(info) { + self.output_connection = (desc, Box::new(conn)); + } + } + OutputDescriptor::DummyOutput => { + self.output_connection = (desc, Box::new(DummyOutput {})); } - } - OutputDescriptor::DummyOutput => { - self.output_connection = Box::new(DummyOutput {}); } } } pub fn note_on(&mut self, ch: u8, key: u8, vel: u8) { - self.output_connection.note_on(ch, key, vel); + self.output_connection.1.note_on(ch, key, vel); } pub fn note_off(&mut self, ch: u8, key: u8) { - self.output_connection.note_off(ch, key); + self.output_connection.1.note_off(ch, key); } } diff --git a/src/scene/menu_scene/iced_menu.rs b/src/scene/menu_scene/iced_menu.rs index ad0124f2..b4f427d5 100644 --- a/src/scene/menu_scene/iced_menu.rs +++ b/src/scene/menu_scene/iced_menu.rs @@ -27,14 +27,22 @@ pub enum Message { OutputsUpdated(Vec), - MainMenuDone(lib_midi::Midi, OutputDescriptor), + MainMenuDone(lib_midi::Midi, usize, OutputDescriptor), } impl IcedMenu { - pub fn new(midi_file: Option, outputs: Vec) -> Self { + pub fn new( + midi_file: Option, + outputs: Vec, + out_id: Option, + ) -> Self { let mut carousel = Carousel::new(); carousel.update(outputs); + if let Some(id) = out_id { + carousel.id = id; + } + Self { midi_file, @@ -90,18 +98,20 @@ impl Program for IcedMenu { } Message::PlayPressed => { - // self.output_manager - // .borrow_mut() - // .connect(self.carousel.get_item().clone()); - if self.midi_file.is_some() { - async fn play(midi: lib_midi::Midi, out: OutputDescriptor) -> Message { - Message::MainMenuDone(midi, out) + async fn play( + midi: lib_midi::Midi, + id: usize, + out: OutputDescriptor, + ) -> Message { + Message::MainMenuDone(midi, id, out) } if self.midi_file.is_some() { if let Some(midi) = std::mem::replace(&mut self.midi_file, None) { - return Command::from(play(midi, self.carousel.get_item().clone())); + if let Some(port) = self.carousel.get_item() { + return Command::from(play(midi, self.carousel.id, port.clone())); + } } } } @@ -111,7 +121,7 @@ impl Program for IcedMenu { self.carousel.update(outs); } - Message::MainMenuDone(_, _) => {} + Message::MainMenuDone(_, _, _) => {} } Command::none() @@ -132,7 +142,11 @@ impl Program for IcedMenu { .on_press(Message::FileSelectPressed), ); - let item = self.carousel.get_item().to_string(); + let item = self + .carousel + .get_item() + .map(|o| o.to_string()) + .unwrap_or("Disconected".to_string()); let text = Text::new(item) .color(Color::WHITE) @@ -203,24 +217,25 @@ impl Program for IcedMenu { }; let footer: Element<_, _> = { - let content: Element = if self.midi_file.is_some() { - let btn = NeoBtn::new( - &mut self.play_button, - Text::new("Play") - .size(30) - .horizontal_alignment(HorizontalAlignment::Center) - .vertical_alignment(VerticalAlignment::Center) - .color(Color::WHITE), - ) - .min_height(50) - .height(Length::Fill) - .width(Length::Units(150)) - .on_press(Message::PlayPressed); + let content: Element = + if self.midi_file.is_some() && self.carousel.get_item().is_some() { + let btn = NeoBtn::new( + &mut self.play_button, + Text::new("Play") + .size(30) + .horizontal_alignment(HorizontalAlignment::Center) + .vertical_alignment(VerticalAlignment::Center) + .color(Color::WHITE), + ) + .min_height(50) + .height(Length::Fill) + .width(Length::Units(150)) + .on_press(Message::PlayPressed); - btn.into() - } else { - Row::new().into() - }; + btn.into() + } else { + Row::new().into() + }; let footer = Container::new(content) .padding(10) @@ -272,8 +287,8 @@ impl Carousel { } } - fn get_item(&self) -> &OutputDescriptor { - &self.outputs[self.id] + fn get_item(&self) -> Option<&OutputDescriptor> { + self.outputs.get(self.id) } } diff --git a/src/scene/menu_scene/mod.rs b/src/scene/menu_scene/mod.rs index d078e5a4..5dda76c1 100644 --- a/src/scene/menu_scene/mod.rs +++ b/src/scene/menu_scene/mod.rs @@ -33,6 +33,7 @@ impl MenuScene { let menu = IcedMenu::new( std::mem::replace(&mut state.midi_file, None), state.output_manager.get_outputs(), + state.output_manager.selected_output_id, ); let iced_state = iced_native::program::State::new( menu, @@ -119,22 +120,27 @@ impl Scene for MenuScene { self.iced_state.queue_event(event); } - match &event { - winit::event::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode { - Some(winit::event::VirtualKeyCode::Return) => { - if let winit::event::ElementState::Released = input.state { - self.iced_state - .queue_message(iced_menu::Message::PlayPressed) - } - } - Some(winit::event::VirtualKeyCode::Escape) => { - if let winit::event::ElementState::Released = input.state { - return SceneEvent::GoBack; + if let winit::event::WindowEvent::KeyboardInput { input, .. } = &event { + if let winit::event::ElementState::Released = input.state { + if let Some(key) = input.virtual_keycode { + match key { + winit::event::VirtualKeyCode::Space => self + .iced_state + .queue_message(iced_menu::Message::FileSelectPressed), + winit::event::VirtualKeyCode::Left => self + .iced_state + .queue_message(iced_menu::Message::PrevPressed), + winit::event::VirtualKeyCode::Right => self + .iced_state + .queue_message(iced_menu::Message::NextPressed), + winit::event::VirtualKeyCode::Return => self + .iced_state + .queue_message(iced_menu::Message::PlayPressed), + winit::event::VirtualKeyCode::Escape => return SceneEvent::GoBack, + _ => {} } } - _ => {} - }, - _ => {} + } } SceneEvent::None @@ -158,8 +164,10 @@ impl Scene for MenuScene { let event = crate::block_on(async { f.await }); match event { - iced_menu::Message::MainMenuDone(midi, out) => { + iced_menu::Message::MainMenuDone(midi, id, out) => { self.main_state.midi_file = Some(midi); + + self.main_state.output_manager.selected_output_id = Some(id); self.main_state.output_manager.connect(out); return SceneEvent::MainMenu(Event::Play);