Skip to content

Commit

Permalink
Play Along Behind A Feature Flag
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Jan 31, 2021
1 parent d8b6377 commit 6099e75
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 89 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2018"
default = ["compile_shader","synth"]
compile_shader = []
record=[]
play_along=[]
synth=["cpal","fluidlite","fluidlite-lib"]

[dependencies]
Expand Down
27 changes: 19 additions & 8 deletions src/scene/menu_scene/iced_menu.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -36,6 +36,7 @@ pub enum Message {
PrevPressed,
NextPressed,

#[cfg(feature = "play_along")]
TogglePlayAlong(bool),

EnterPressed,
Expand All @@ -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(),
Expand Down Expand Up @@ -127,6 +131,7 @@ impl Program for IcedMenu {
self.carousel.prev();
}
}
#[cfg(feature = "play_along")]
Message::TogglePlayAlong(is) => {
self.play_along = is;
}
Expand Down Expand Up @@ -377,6 +382,7 @@ impl SongSelectControls {
)
}

#[allow(unused_variables)]
fn footer<'a>(
play_button: &'a mut neo_btn::State,
carousel: &Carousel,
Expand All @@ -397,19 +403,24 @@ 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(
Checkbox::new(play_along, "", Message::TogglePlayAlong)
.style(CheckboxStyle {}),
)
.push(Text::new("Play Along").color(Color::WHITE)),
)
.push(btn)
.into()
);
}

coll.push(btn).into()
} else {
Row::new().into()
};
Expand Down
5 changes: 4 additions & 1 deletion src/scene/menu_scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
207 changes: 127 additions & 80 deletions src/scene/playing_scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -324,13 +323,8 @@ struct Player {
time: f32,

rewind_controler: RewindControler,

_midi_in_conn: Option<midir::MidiInputConnection<()>>,
midi_in_rec: Option<mpsc::Receiver<(bool, u8, u8)>>,

input_pressed_keys: [bool; 88],
required_notes: Arc<Mutex<HashMap<u8, MidiNote>>>,
waiting_for_note: bool,
#[cfg(feature = "play_along")]
play_along_controler: Option<PlayAlongControler>,
}

impl Player {
Expand All @@ -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(&note);
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 {
Expand All @@ -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);

Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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();
}
}
}

Expand All @@ -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<Mutex<HashMap<u8, MidiNote>>>,
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(&note);
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<dyn Fn(&mut Target)>,
Expand Down

0 comments on commit 6099e75

Please sign in to comment.