diff --git a/.gitignore b/.gitignore index 4bc4b9d..fbd5be5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Cargo.lock **/*.rs.bk package-lock.json +.vscode/launch.json diff --git a/Cargo.toml b/Cargo.toml index 828ce8c..17910df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_midi" -version = "0.6.0" +version = "0.7.0" authors = ["Black Phlox "] edition = "2021" license = "MIT OR Apache-2.0" @@ -22,23 +22,24 @@ name = "bevy_midi" [dependencies] midir = "0.9" -crossbeam-channel = "0.5.6" +crossbeam-channel = "0.5.8" [dev-dependencies] -bevy_egui = { version = "0.20", features = ["immutable_ctx"]} -strum = { version = "0.24", features = ["derive"] } -bevy_mod_picking = "0.12" +bevy_egui = { version = "0.23", features = ["immutable_ctx"]} +strum = { version = "0.25", features = ["derive"] } +bevy_mod_picking = "0.17" [dependencies.bevy] -version = "0.10" +version = "0.12" default-features = false +features = ["multi-threaded"] [dev-dependencies.bevy] -version = "0.10" -features = ["bevy_core_pipeline","bevy_asset", "bevy_scene", "bevy_render", "bevy_winit", "bevy_gltf", "bevy_ui", "bevy_text"] +version = "0.12" +features = ["bevy_core_pipeline","bevy_asset", "bevy_scene", "bevy_render", "bevy_winit", "bevy_gltf", "bevy_ui", "bevy_text", "zstd", "tonemapping_luts", "ktx2", "hdr"] default-features = false [target.'cfg(target_os = "linux")'.dev-dependencies.bevy] -version = "0.10" +version = "0.12" features = ["x11", "wayland"] default-features = false diff --git a/README.md b/README.md index bfb86bb..0cca25d 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ See examples |0.7|0.4.X| |0.8|0.5.X| |0.10|0.6.X| +|0.12|0.7.X| # Licensing The project is under dual license MIT and Apache 2.0, so joink to your hearts content, just remember the license agreements. diff --git a/examples/egui.rs b/examples/egui.rs index 16626be..429a187 100644 --- a/examples/egui.rs +++ b/examples/egui.rs @@ -2,7 +2,10 @@ use std::iter::{Cycle, Peekable}; use bevy::prelude::*; use bevy_egui::{ - egui::{self, Color32, ColorImage, ImageButton, Key, TextureHandle, TextureOptions, Ui}, + egui::{ + self, load::SizedTexture, Color32, ColorImage, ImageButton, Key, TextureHandle, + TextureOptions, Ui, + }, EguiContext, EguiPlugin, }; use bevy_midi::prelude::*; @@ -14,10 +17,10 @@ use strum::{EnumCount, EnumIter, IntoEnumIterator}; fn main() { App::new() .add_plugins(DefaultPlugins) - .add_plugin(EguiPlugin) + .add_plugins(EguiPlugin) // Systems that create Egui widgets should be run during the `CoreStage::Update` stage, // or after the `EguiSystem::BeginFrame` system (which belongs to the `CoreStage::PreUpdate` stage). - .add_system(ui_example) + .add_systems(Update, ui_example) .init_resource::() .run(); } @@ -183,7 +186,7 @@ impl PianoRoll { } fn update_key_states(&mut self, ui: &mut Ui) { - let input = ui.input(|i| i.key_pressed(egui::Key::A)); + let _input = ui.input(|i| i.key_pressed(egui::Key::A)); let next_keys = std::array::from_fn(|index| ui.input(|i| i.key_down(KEYS[index]))); self.key_states @@ -214,7 +217,6 @@ impl PianoRoll { }); self.key_states = next_keys; - drop(input); } fn get_key_texture_tint(&self, note: NoteName, index: usize) -> Color32 { @@ -257,6 +259,7 @@ impl PianoRoll { ) }) .id(); + // Draw the actual piano keys for clicking ui.vertical(|ui| { ui.spacing_mut().item_spacing = bevy_egui::egui::Vec2 { @@ -271,7 +274,8 @@ impl PianoRoll { all_notes_iter.for_each(|(index, (note, _octave))| { let color = self.get_key_texture_tint(note, index); - let button_top = ImageButton::new(texture_id, TOP_KEY_SIZE).tint(color); + let button_top = + ImageButton::new(SizedTexture::new(texture_id, TOP_KEY_SIZE)).tint(color); if ui.add(button_top).clicked() { //sync.trigger_note(index, selected_instrument); println!("Pressed {}{}", KEY_RANGE[index % 12], index / 12); @@ -291,7 +295,8 @@ impl PianoRoll { let tint = self.get_key_texture_tint(note, index); let button_bottom = - ImageButton::new(texture_id, BOTTOM_KEY_SIZE).tint(tint); + ImageButton::new(SizedTexture::new(texture_id, BOTTOM_KEY_SIZE)) + .tint(tint); if ui.add(button_bottom).clicked() { //sync.trigger_note(index, selected_instrument); diff --git a/examples/input.rs b/examples/input.rs index 4932aba..a25caf4 100644 --- a/examples/input.rs +++ b/examples/input.rs @@ -28,14 +28,19 @@ fn main() { level: Level::WARN, filter: "bevy_midi=debug".to_string(), })) - .add_plugin(MidiInputPlugin) - .add_system(refresh_ports) - .add_system(connect) - .add_system(disconnect) - .add_system(show_ports) - .add_system(show_connection) - .add_system(show_last_message) - .add_startup_system(setup) + .add_plugins(MidiInputPlugin) + .add_systems(Startup, setup) + .add_systems( + Update, + ( + refresh_ports, + connect, + disconnect, + show_ports, + show_connection, + show_last_message, + ), + ) .run(); } @@ -96,7 +101,7 @@ fn show_last_message( mut midi_data: EventReader, mut instructions: Query<&mut Text, With>, ) { - for data in midi_data.iter() { + for data in midi_data.read() { let text_section = &mut instructions.single_mut().sections[3]; text_section.value = format!( "Last Message: {} - {:?}", diff --git a/examples/output.rs b/examples/output.rs index 2f210f1..433c837 100644 --- a/examples/output.rs +++ b/examples/output.rs @@ -30,14 +30,19 @@ fn main() { .insert_resource(MidiOutputSettings { port_name: "output", }) - .add_plugin(MidiOutputPlugin) - .add_system(refresh_ports) - .add_system(connect) - .add_system(disconnect) - .add_system(play_notes) - .add_system(show_ports) - .add_system(show_connection) - .add_startup_system(setup) + .add_plugins(MidiOutputPlugin) + .add_systems( + Update, + ( + refresh_ports, + connect, + disconnect, + play_notes, + show_ports, + show_connection, + ), + ) + .add_systems(Startup, setup) .run(); } diff --git a/examples/piano.rs b/examples/piano.rs index 8b27d45..84c8dc0 100644 --- a/examples/piano.rs +++ b/examples/piano.rs @@ -4,10 +4,7 @@ use bevy::{ prelude::*, }; use bevy_midi::prelude::*; -use bevy_mod_picking::{ - DefaultPickingPlugins, HoverEvent, PickableBundle, PickingCameraBundle, PickingEvent, - SelectionEvent, -}; +use bevy_mod_picking::prelude::*; fn main() { App::new() @@ -21,17 +18,21 @@ fn main() { filter: "bevy_midi=debug".to_string(), })) .add_plugins(DefaultPickingPlugins) - .add_plugin(MidiInputPlugin) + .add_plugins(MidiInputPlugin) .init_resource::() - .add_plugin(MidiOutputPlugin) + .add_plugins(MidiOutputPlugin) .init_resource::() - .add_startup_system(setup) - .add_system(handle_midi_input) - .add_system(connect_to_first_input_port) - .add_system(connect_to_first_output_port) - .add_system(print_events.in_base_set(CoreSet::PostUpdate)) - .add_system(display_press) - .add_system(display_release) + .add_systems(Startup, setup) + .add_systems( + Update, + ( + handle_midi_input, + connect_to_first_input_port, + connect_to_first_output_port, + display_press, + display_release, + ), + ) .run(); } @@ -41,52 +42,29 @@ struct Key { y_reset: f32, } -pub fn print_events( - mut events: EventReader, - mut commands: Commands, - mouse_button_input: Res>, -) { - for event in events.iter() { - let entity = match event { - PickingEvent::Selection(SelectionEvent::JustSelected(e)) => e, - PickingEvent::Selection(SelectionEvent::JustDeselected(e)) => e, - PickingEvent::Hover(HoverEvent::JustEntered(e)) => e, - PickingEvent::Hover(HoverEvent::JustLeft(e)) => e, - PickingEvent::Clicked(e) => e, - }; - - if mouse_button_input.pressed(MouseButton::Left) { - commands.entity(*entity).insert(PressedKey); - } else { - commands.entity(*entity).remove::(); - } - } -} - #[derive(Component)] struct PressedKey; #[rustfmt::skip] fn setup( - mut commands: Commands, + mut cmds: Commands, mut materials: ResMut>, asset_server: Res, ) { let mid = -6.3; // light - commands.spawn(PointLightBundle { + cmds.spawn(PointLightBundle { transform: Transform::from_xyz(0.0, 6.0, mid), ..Default::default() }); //Camera - commands.spawn(( + cmds.spawn(( Camera3dBundle { transform: Transform::from_xyz(8., 5., mid).looking_at(Vec3::new(0., 0., mid), Vec3::Y), ..Default::default() }, - PickingCameraBundle::default(), )); let pos: Vec3 = Vec3::new(0., 0., 0.); @@ -102,18 +80,18 @@ fn setup( let pos_black = pos + Vec3::new(0., 0.06, 0.); for i in 0..8 { - spawn_note(&mut commands, &w_mat, 0.00, pos, &mut white_key_0, i, "C"); - spawn_note(&mut commands, &b_mat, 0.15, pos_black, &mut black_key, i, "C#"); - spawn_note(&mut commands, &w_mat, 0.27, pos, &mut white_key_1, i, "D"); - spawn_note(&mut commands, &b_mat, 0.39, pos_black, &mut black_key, i, "D#"); - spawn_note(&mut commands, &w_mat, 0.54, pos, &mut white_key_2, i, "E"); - spawn_note(&mut commands, &w_mat, 0.69, pos, &mut white_key_0, i, "F"); - spawn_note(&mut commands, &b_mat, 0.85, pos_black, &mut black_key, i, "F#"); - spawn_note(&mut commands, &w_mat, 0.96, pos, &mut white_key_1, i, "G"); - spawn_note(&mut commands, &b_mat, 1.08, pos_black, &mut black_key, i, "G#"); - spawn_note(&mut commands, &w_mat, 1.19, pos, &mut white_key_1, i, "A"); - spawn_note(&mut commands, &b_mat, 1.31, pos_black, &mut black_key, i, "A#"); - spawn_note(&mut commands, &w_mat, 1.46, pos, &mut white_key_2, i, "B"); + spawn_note(&mut cmds, &w_mat, 0.00, pos, &mut white_key_0, i, "C"); + spawn_note(&mut cmds, &b_mat, 0.15, pos_black, &mut black_key, i, "C#/Db"); + spawn_note(&mut cmds, &w_mat, 0.27, pos, &mut white_key_1, i, "D"); + spawn_note(&mut cmds, &b_mat, 0.39, pos_black, &mut black_key, i, "D#/Eb"); + spawn_note(&mut cmds, &w_mat, 0.54, pos, &mut white_key_2, i, "E"); + spawn_note(&mut cmds, &w_mat, 0.69, pos, &mut white_key_0, i, "F"); + spawn_note(&mut cmds, &b_mat, 0.85, pos_black, &mut black_key, i, "F#/Gb"); + spawn_note(&mut cmds, &w_mat, 0.96, pos, &mut white_key_1, i, "G"); + spawn_note(&mut cmds, &b_mat, 1.08, pos_black, &mut black_key, i, "G#/Ab"); + spawn_note(&mut cmds, &w_mat, 1.19, pos, &mut white_key_1, i, "A"); + spawn_note(&mut cmds, &b_mat, 1.31, pos_black, &mut black_key, i, "A#/Bb"); + spawn_note(&mut cmds, &w_mat, 1.46, pos, &mut white_key_2, i, "B"); } } @@ -142,6 +120,12 @@ fn spawn_note( y_reset: pos.y, }, PickableBundle::default(), + On::>::target_commands_mut(|_click, entity_commands| { + entity_commands.insert(PressedKey); + }), + On::>::target_commands_mut(|_click, entity_commands| { + entity_commands.remove::(); + }), )); } @@ -162,7 +146,7 @@ fn handle_midi_input( mut midi_events: EventReader, query: Query<(Entity, &Key)>, ) { - for data in midi_events.iter() { + for data in midi_events.read() { let [_, index, _value] = data.message.msg; let off = index % 12; let oct = index.overflowing_div(12).0; diff --git a/src/input.rs b/src/input.rs index 5afb09d..cb10c2b 100644 --- a/src/input.rs +++ b/src/input.rs @@ -17,9 +17,9 @@ impl Plugin for MidiInputPlugin { .init_resource::() .add_event::() .add_event::() - .add_startup_system(setup) - .add_system(reply.in_base_set(CoreSet::PreUpdate)) - .add_system(debug); + .add_systems(Startup, setup) + .add_systems(PreUpdate, reply) + .add_systems(Update, debug); } } @@ -113,6 +113,8 @@ pub struct MidiData { pub message: MidiMessage, } +impl bevy::prelude::Event for MidiData {} + /// The [`Error`] type for midi input operations, accessible as an [`Event`](bevy::ecs::event::Event). #[derive(Clone, Debug)] pub enum MidiInputError { @@ -121,6 +123,7 @@ pub enum MidiInputError { } impl Error for MidiInputError {} +impl Event for MidiInputError {} impl Display for MidiInputError { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { match self { @@ -339,7 +342,7 @@ fn get_available_ports(input: &midir::MidiInput) -> Reply { // A system which debug prints note events fn debug(mut midi: EventReader) { - for data in midi.iter() { + for data in midi.read() { let pitch = data.message.msg[1]; let octave = pitch / 12; let key = KEY_RANGE[pitch as usize % 12]; diff --git a/src/output.rs b/src/output.rs index 7f0774f..3d49568 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,5 +1,6 @@ use super::MidiMessage; -use bevy::{prelude::*, tasks::IoTaskPool}; +use bevy::prelude::*; +use bevy::tasks::IoTaskPool; use crossbeam_channel::{Receiver, Sender}; use midir::ConnectErrorKind; pub use midir::MidiOutputPort; @@ -14,8 +15,8 @@ impl Plugin for MidiOutputPlugin { app.init_resource::() .init_resource::() .add_event::() - .add_startup_system(setup) - .add_system(reply.in_base_set(CoreSet::PreUpdate)); + .add_systems(Startup, setup) + .add_systems(PreUpdate, reply); } } @@ -107,6 +108,7 @@ pub enum MidiOutputError { } impl Error for MidiOutputError {} +impl Event for MidiOutputError {} impl Display for MidiOutputError { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { match self {