From 6099e75c9b5c6e83c0275ee2539201e2a9bc72c7 Mon Sep 17 00:00:00 2001 From: Poly Date: Sun, 31 Jan 2021 14:55:04 +0100 Subject: [PATCH] Play Along Behind A Feature Flag --- Cargo.toml | 1 + src/scene/menu_scene/iced_menu.rs | 27 ++-- src/scene/menu_scene/mod.rs | 5 +- src/scene/playing_scene/mod.rs | 207 ++++++++++++++++++------------ 4 files changed, 151 insertions(+), 89 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b667595e..c500df69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" default = ["compile_shader","synth"] compile_shader = [] record=[] +play_along=[] synth=["cpal","fluidlite","fluidlite-lib"] [dependencies] diff --git a/src/scene/menu_scene/iced_menu.rs b/src/scene/menu_scene/iced_menu.rs index cdcde8f1..38e3fe69 100644 --- a/src/scene/menu_scene/iced_menu.rs +++ b/src/scene/menu_scene/iced_menu.rs @@ -1,8 +1,8 @@ use std::path::PathBuf; use iced_native::{ - image, Align, Checkbox, Color, Column, Command, Container, Element, HorizontalAlignment, Image, - Length, Program, Row, Text, VerticalAlignment, + image, Align, Color, Column, Command, Container, Element, HorizontalAlignment, Image, Length, + Program, Row, Text, VerticalAlignment, }; use iced_wgpu::Renderer; @@ -36,6 +36,7 @@ pub enum Message { PrevPressed, NextPressed, + #[cfg(feature = "play_along")] TogglePlayAlong(bool), EnterPressed, @@ -62,7 +63,10 @@ impl IcedMenu { } Self { + #[cfg(feature = "play_along")] play_along: state.config.play_along, + #[cfg(not(feature = "play_along"))] + play_along: false, midi_file: state.midi_file.is_some(), font_path: state.output_manager.selected_font_path.clone(), @@ -127,6 +131,7 @@ impl Program for IcedMenu { self.carousel.prev(); } } + #[cfg(feature = "play_along")] Message::TogglePlayAlong(is) => { self.play_along = is; } @@ -377,6 +382,7 @@ impl SongSelectControls { ) } + #[allow(unused_variables)] fn footer<'a>( play_button: &'a mut neo_btn::State, carousel: &Carousel, @@ -397,9 +403,13 @@ impl SongSelectControls { .width(Length::Units(150)) .on_press(Message::EnterPressed); - Column::new() - .spacing(10) - .push( + #[allow(unused_mut)] + let mut coll = Column::new().spacing(10); + + #[cfg(feature = "play_along")] + { + use iced_native::Checkbox; + coll = coll.push( Row::new() .height(Length::Shrink) .push( @@ -407,9 +417,10 @@ impl SongSelectControls { .style(CheckboxStyle {}), ) .push(Text::new("Play Along").color(Color::WHITE)), - ) - .push(btn) - .into() + ); + } + + coll.push(btn).into() } else { Row::new().into() }; diff --git a/src/scene/menu_scene/mod.rs b/src/scene/menu_scene/mod.rs index 9b130a71..666315f9 100644 --- a/src/scene/menu_scene/mod.rs +++ b/src/scene/menu_scene/mod.rs @@ -174,7 +174,10 @@ impl Scene for MenuScene { iced_menu::Message::OutputMainMenuDone(out) => { let program = self.iced_state.program(); - target.state.config.play_along = program.play_along; + #[cfg(feature = "play_along")] + { + target.state.config.play_along = program.play_along; + } target.state.output_manager.selected_output_id = Some(program.carousel.id()); diff --git a/src/scene/playing_scene/mod.rs b/src/scene/playing_scene/mod.rs index fab25a96..fba7ecd3 100644 --- a/src/scene/playing_scene/mod.rs +++ b/src/scene/playing_scene/mod.rs @@ -313,7 +313,6 @@ impl Scene for PlayingScene { } use std::collections::HashMap; -use std::sync::{mpsc, Arc, Mutex}; struct Player { midi_first_note_start: f32, @@ -324,13 +323,8 @@ struct Player { time: f32, rewind_controler: RewindControler, - - _midi_in_conn: Option>, - midi_in_rec: Option>, - - input_pressed_keys: [bool; 88], - required_notes: Arc>>, - waiting_for_note: bool, + #[cfg(feature = "play_along")] + play_along_controler: Option, } impl Player { @@ -348,46 +342,11 @@ impl Player { 0.0 }; - let input_pressed_keys = [false; 88]; - let required_notes = Arc::new(Mutex::new(HashMap::new())); - - let (_midi_in_conn, midi_in_rec) = if main_state.config.play_along { - let (tx, midi_in_rec) = mpsc::channel(); - let midi_in_conn = { - let midi_in = midir::MidiInput::new("Neothesia-in").unwrap(); - let in_ports = midi_in.ports(); - let in_port = &in_ports[1]; - - for (i, p) in in_ports.iter().enumerate() { - println!("{}: {}", i, midi_in.port_name(p).unwrap()); - } - - let required_notes = required_notes.clone(); - - midi_in - .connect( - in_port, - "neothesia-read-input", - move |_, message, _| { - if message.len() == 3 { - let note = message[1]; - if note >= 21 && note <= 108 { - if message[0] == 128 || message[2] == 0 { - tx.send((false, message[1], message[2])).unwrap(); - } else if message[0] == 144 { - required_notes.lock().unwrap().remove(¬e); - tx.send((true, message[1], message[2])).unwrap(); - } - } - } - }, - (), - ) - .unwrap() - }; - (Some(midi_in_conn), Some(midi_in_rec)) + #[cfg(feature = "play_along")] + let play_along_controler = if main_state.config.play_along { + Some(PlayAlongControler::new()) } else { - (None, None) + None }; let mut player = Self { @@ -399,13 +358,8 @@ impl Player { time: 0.0, rewind_controler: RewindControler::None, - - _midi_in_conn, - midi_in_rec, - - input_pressed_keys, - required_notes, - waiting_for_note: false, + #[cfg(feature = "play_along")] + play_along_controler, }; player.update(main_state); @@ -428,24 +382,9 @@ impl Player { let mut notes_state: [(bool, usize); 88] = [(false, 0); 88]; - for (id, is) in self.input_pressed_keys.iter().enumerate() { - notes_state[id] = (*is, 0); - } - - if let Some(midi_in_rec) = &self.midi_in_rec { - if let Ok(event) = midi_in_rec.try_recv() { - if event.0 { - self.input_pressed_keys[event.1 as usize - 21] = true; - main_state.output_manager.note_on(0, event.1, event.2) - } else { - self.input_pressed_keys[event.1 as usize - 21] = false; - main_state.output_manager.note_off(0, event.1) - } - } - if self.required_notes.lock().unwrap().len() == 0 && self.waiting_for_note == true { - self.waiting_for_note = false; - self.timer.resume(); - } + #[cfg(feature = "play_along")] + if let Some(controler) = &mut self.play_along_controler { + controler.update(main_state, &mut notes_state, &mut self.timer); } if self.timer.paused { @@ -463,7 +402,6 @@ impl Player { .collect(); let output_manager = &mut main_state.output_manager; - let mut required_notes = self.required_notes.lock().unwrap(); for n in filtered { use std::collections::hash_map::Entry; @@ -476,15 +414,15 @@ impl Player { if let Entry::Vacant(_e) = self.active_notes.entry(n.id) { self.active_notes.insert(n.id, n.clone()); - if main_state.config.play_along { - if n.note >= 21 && n.note <= 108 && n.ch != 9 { - required_notes.insert(n.note, n.clone()); - self.waiting_for_note = true; - self.timer.pause(); - } + #[cfg(feature = "play_along")] + if let Some(controler) = &mut self.play_along_controler { + controler.require_note(&mut self.timer, &n); } else { output_manager.note_on(n.ch, n.note, n.vel); } + + #[cfg(not(feature = "play_along"))] + output_manager.note_on(n.ch, n.note, n.vel); } } else if let Entry::Occupied(_e) = self.active_notes.entry(n.id) { self.active_notes.remove(&n.id); @@ -538,7 +476,11 @@ impl Player { main_state.output_manager.note_off(n.ch, n.note); } self.active_notes.clear(); - self.required_notes.lock().unwrap().clear(); + + #[cfg(feature = "play_along")] + if let Some(controler) = &mut self.play_along_controler { + controler.clear(); + } } } @@ -556,6 +498,111 @@ impl RewindControler { } } +#[cfg(feature = "play_along")] +use std::sync::{mpsc, Arc, Mutex}; + +#[cfg(feature = "play_along")] +struct PlayAlongControler { + _midi_in_conn: midir::MidiInputConnection<()>, + midi_in_rec: mpsc::Receiver<(bool, u8, u8)>, + + input_pressed_keys: [bool; 88], + required_notes: Arc>>, + waiting_for_note: bool, +} + +#[cfg(feature = "play_along")] +impl PlayAlongControler { + fn new() -> Self { + let input_pressed_keys = [false; 88]; + let required_notes = Arc::new(Mutex::new(HashMap::new())); + + let (tx, midi_in_rec) = mpsc::channel(); + + let _midi_in_conn = { + let midi_in = midir::MidiInput::new("Neothesia-in").unwrap(); + let in_ports = midi_in.ports(); + let in_port = &in_ports[1]; + + for (i, p) in in_ports.iter().enumerate() { + println!("{}: {}", i, midi_in.port_name(p).unwrap()); + } + + let required_notes = required_notes.clone(); + + midi_in + .connect( + in_port, + "neothesia-read-input", + move |_, message, _| { + if message.len() == 3 { + let note = message[1]; + if note >= 21 && note <= 108 { + if message[0] == 128 || message[2] == 0 { + tx.send((false, message[1], message[2])).unwrap(); + } else if message[0] == 144 { + required_notes.lock().unwrap().remove(¬e); + tx.send((true, message[1], message[2])).unwrap(); + } + } + } + }, + (), + ) + .unwrap() + }; + + Self { + _midi_in_conn, + midi_in_rec, + + input_pressed_keys, + required_notes, + waiting_for_note: false, + } + } + + fn update( + &mut self, + main_state: &mut MainState, + notes_state: &mut [(bool, usize); 88], + timer: &mut Timer, + ) { + for (id, is) in self.input_pressed_keys.iter().enumerate() { + notes_state[id] = (*is, 0); + } + + if let Ok(event) = self.midi_in_rec.try_recv() { + if event.0 { + self.input_pressed_keys[event.1 as usize - 21] = true; + main_state.output_manager.note_on(0, event.1, event.2) + } else { + self.input_pressed_keys[event.1 as usize - 21] = false; + main_state.output_manager.note_off(0, event.1) + } + } + if self.required_notes.lock().unwrap().len() == 0 && self.waiting_for_note == true { + self.waiting_for_note = false; + timer.resume(); + } + } + + fn require_note(&mut self, timer: &mut Timer, n: &MidiNote) { + if n.note >= 21 && n.note <= 108 && n.ch != 9 { + self.required_notes + .lock() + .unwrap() + .insert(n.note, n.clone()); + self.waiting_for_note = true; + timer.pause(); + } + } + + fn clear(&mut self) { + self.required_notes.lock().unwrap().clear(); + } +} + struct Toast { start_time: std::time::Instant, inner_draw: Box,