Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect track ui to new track config #95

Merged
merged 1 commit into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions midi-file/src/playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{sync::Arc, time::Duration};

use crate::{MidiEvent, MidiTrack};

#[derive(Debug, Default, Clone)]
#[derive(Debug, Clone)]
struct TrackState {
seen_events: usize,
}
Expand Down Expand Up @@ -34,7 +34,7 @@ impl PlaybackState {
}
}

let track_states = vec![TrackState::default(); tracks.len()];
let track_states = vec![TrackState { seen_events: 0 }; tracks.len()];

Self {
tracks,
Expand Down
1 change: 1 addition & 0 deletions neothesia-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl Recorder {
let mut waterfall = WaterfallRenderer::new(
&gpu,
&midi.tracks,
&[],
&config,
&transform_uniform,
keyboard_layout,
Expand Down
2 changes: 2 additions & 0 deletions neothesia-core/src/render/waterfall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ impl WaterfallRenderer {
pub fn new(
gpu: &Gpu,
tracks: &[MidiTrack],
hidden_tracks: &[usize],
config: &Config,
transform_uniform: &Uniform<TransformUniform>,
layout: piano_math::KeyboardLayout,
) -> Self {
let mut notes: Vec<_> = tracks
.iter()
.filter(|track| !hidden_tracks.contains(&track.track_id))
.flat_map(|track| track.notes.iter().cloned())
.collect();
// We want to render newer notes on top of old notes
Expand Down
7 changes: 4 additions & 3 deletions neothesia/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod iced_utils;
mod input_manager;
mod output_manager;
mod scene;
mod song;
mod target;
mod utils;

Expand All @@ -26,7 +27,7 @@ use winit::{
#[derive(Debug)]
pub enum NeothesiaEvent {
/// Go to playing scene
Play(midi_file::MidiFile),
Play(song::Song),
/// Go to main menu scene
MainMenu,
MidiInput {
Expand Down Expand Up @@ -117,10 +118,10 @@ impl Neothesia {

fn neothesia_event(&mut self, event: NeothesiaEvent, control_flow: &mut ControlFlow) {
match event {
NeothesiaEvent::Play(midi_file) => {
NeothesiaEvent::Play(song) => {
self.target.iced_manager.renderer.clear();

let to = playing_scene::PlayingScene::new(&self.target, midi_file);
let to = playing_scene::PlayingScene::new(&self.target, song);
self.game_scene = Box::new(to);
}
NeothesiaEvent::MainMenu => {
Expand Down
65 changes: 51 additions & 14 deletions neothesia/src/scene/menu_scene/iced_menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
iced_utils::iced_state::{Element, Program},
output_manager::OutputDescriptor,
scene::menu_scene::neo_btn::neo_button,
song::{PlayerConfig, Song},
target::Target,
NeothesiaEvent,
};
Expand Down Expand Up @@ -44,6 +45,8 @@ pub enum Message {
Play,

PlayAlongCheckbox(bool),
TrackPlayerConfig(usize, PlayerConfig),
TrackVisibilityConfig(usize, bool),

GoToPage(Step),
ExitApp,
Expand Down Expand Up @@ -94,7 +97,7 @@ impl Program for AppUi {
self.current = page;
}
Message::Play => {
if let Some(midi_file) = target.midi_file.as_ref() {
if let Some(song) = target.song.as_ref() {
if let Some(out) = self.data.selected_output.clone() {
let out = match out {
#[cfg(feature = "synth")]
Expand All @@ -113,7 +116,7 @@ impl Program for AppUi {

target
.proxy
.send_event(NeothesiaEvent::Play(midi_file.clone()))
.send_event(NeothesiaEvent::Play(song.clone()))
.ok();
}
}
Expand All @@ -124,7 +127,7 @@ impl Program for AppUi {
Message::MidiFileLoaded(midi) => {
if let Some((midi, path)) = midi {
target.config.last_opened_song = Some(path);
target.midi_file = Some(midi);
target.song = Some(Song::new(midi));
}
self.data.is_loading = false;
}
Expand Down Expand Up @@ -155,6 +158,16 @@ impl Program for AppUi {
Message::PlayAlongCheckbox(v) => {
target.config.play_along = v;
}
Message::TrackPlayerConfig(track, config) => {
if let Some(song) = target.song.as_mut() {
song.config.tracks[track].player = config;
}
}
Message::TrackVisibilityConfig(track, visible) => {
if let Some(song) = target.song.as_mut() {
song.config.tracks[track].visible = visible;
}
}
Message::VerticalGuidelines(v) => {
target.config.vertical_guidelines = v;
}
Expand Down Expand Up @@ -322,7 +335,7 @@ impl<'a> Step {

let mut content = top_padded(column);

if target.midi_file.is_some() {
if target.song.is_some() {
let play_along = checkbox(
"PlayAlong",
target.config.play_along,
Expand Down Expand Up @@ -440,35 +453,59 @@ impl<'a> Step {

fn track_selection(_data: &'a Data, target: &Target) -> Element<'a, Message> {
let mut tracks = Vec::new();
if let Some(midi) = target.midi_file.as_ref() {
for track in midi.tracks.iter().filter(|t| !t.notes.is_empty()) {
let (color, name) = if track.has_drums && !track.has_other_than_drums {
(iced_core::Color::from_rgb8(102, 102, 102), "Percussion")
if let Some(song) = target.song.as_ref() {
for track in song.file.tracks.iter().filter(|t| !t.notes.is_empty()) {
let config = &song.config.tracks[track.track_id];

let visible = config.visible;

let active = match config.player {
PlayerConfig::Mute => 0,
PlayerConfig::Auto => 1,
PlayerConfig::Human => 2,
};

let color = if (track.has_drums && !track.has_other_than_drums) || !visible {
iced_core::Color::from_rgb8(102, 102, 102)
} else {
let color_id = track.track_color_id % target.config.color_schema.len();
let color = &target.config.color_schema[color_id].base;
let color = iced_core::Color::from_rgb8(color.0, color.1, color.2);
iced_core::Color::from_rgb8(color.0, color.1, color.2)
};

let name = if track.has_drums && !track.has_other_than_drums {
"Percussion"
} else {
let instrument_id = track
.programs
.last()
.map(|p| p.program as usize)
.unwrap_or(0);
(color, midi_file::INSTRUMENT_NAMES[instrument_id])
midi_file::INSTRUMENT_NAMES[instrument_id]
};

let body = segment_button::segment_button()
.button("Mute", Message::Tick)
.button("Auto", Message::Tick)
.button("Human", Message::Tick)
.active(1)
.button(
"Mute",
Message::TrackPlayerConfig(track.track_id, PlayerConfig::Mute),
)
.button(
"Auto",
Message::TrackPlayerConfig(track.track_id, PlayerConfig::Auto),
)
.button(
"Human",
Message::TrackPlayerConfig(track.track_id, PlayerConfig::Human),
)
.active(active)
.active_color(color)
.build();
let card = track_card::track_card()
.title(name)
.subtitle(format!("{} Notes", track.notes.len()))
.track_color(color)
.body(body)
.on_icon_press(Message::TrackVisibilityConfig(track.track_id, !visible))
.build();
tracks.push(card.into());
}
Expand Down
8 changes: 4 additions & 4 deletions neothesia/src/scene/menu_scene/segment_button/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ impl iced_style::button::StyleSheet for SegmentButtonStyle {
fn hovered(&self, style: &Self::Style) -> button::Appearance {
let mut active = self.active(style);

if let Some(iced_core::Background::Color(ref mut background)) = active.background {
background.r += 0.05;
background.g += 0.05;
background.b += 0.05;
if let Some(iced_core::Background::Color(ref mut color)) = active.background {
color.r = (color.r + 0.05).min(1.0);
color.g = (color.g + 0.05).min(1.0);
color.b = (color.b + 0.05).min(1.0);
}

active
Expand Down
16 changes: 12 additions & 4 deletions neothesia/src/scene/menu_scene/track_card/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ pub struct TrackCard<'a, MSG> {
subtitle: String,
body: Option<Element<'a, MSG, Renderer>>,
track_color: Color,
on_icon_press: Option<MSG>,
}

impl<'a, MSG: 'a> TrackCard<'a, MSG> {
impl<'a, MSG: 'a + Clone> TrackCard<'a, MSG> {
pub fn new() -> Self {
Self {
title: String::new(),
subtitle: String::new(),
body: None,
track_color: Color::from_rgba8(210, 89, 222, 1.0),
on_icon_press: None,
}
}

Expand All @@ -35,6 +37,11 @@ impl<'a, MSG: 'a> TrackCard<'a, MSG> {
self
}

pub fn on_icon_press(mut self, msg: MSG) -> Self {
self.on_icon_press = Some(msg);
self
}

pub fn body(mut self, body: impl Into<Element<'a, MSG, Renderer>>) -> Self {
self.body = Some(body.into());
self
Expand All @@ -43,10 +50,11 @@ impl<'a, MSG: 'a> TrackCard<'a, MSG> {
pub fn build(self) -> iced_widget::Container<'a, MSG, Renderer> {
let header = {
iced_widget::row![
iced_widget::container(iced_widget::text(""))
iced_widget::button(iced_widget::text(""))
.width(40)
.height(40)
.style(theme::track_icon(self.track_color)),
.style(theme::track_icon_button(self.track_color))
.on_press_maybe(self.on_icon_press),
iced_widget::column(vec![
iced_widget::text(self.title).size(16).into(),
iced_widget::text(self.subtitle).size(14).into(),
Expand All @@ -68,6 +76,6 @@ impl<'a, MSG: 'a> TrackCard<'a, MSG> {
}
}

pub fn track_card<'a, MSG: 'a>() -> TrackCard<'a, MSG> {
pub fn track_card<'a, MSG: 'a + Clone>() -> TrackCard<'a, MSG> {
TrackCard::new()
}
25 changes: 19 additions & 6 deletions neothesia/src/scene/menu_scene/track_card/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,33 @@ impl iced_style::container::StyleSheet for ContainerStyle {
}
}

pub fn track_icon(color: iced_core::Color) -> iced_style::theme::Container {
iced_style::theme::Container::Custom(Box::new(TrackIconStyle(color)))
pub fn track_icon_button(color: iced_core::Color) -> iced_style::theme::Button {
iced_style::theme::Button::Custom(Box::new(TrackIconButtonStyle(color)))
}

struct TrackIconStyle(iced_core::Color);
struct TrackIconButtonStyle(iced_core::Color);

impl iced_style::container::StyleSheet for TrackIconStyle {
impl iced_style::button::StyleSheet for TrackIconButtonStyle {
type Style = iced_style::Theme;

fn appearance(&self, _style: &Self::Style) -> iced_style::container::Appearance {
iced_style::container::Appearance {
fn active(&self, _style: &Self::Style) -> iced_style::button::Appearance {
iced_style::button::Appearance {
background: Some(iced_core::Background::from(self.0)),
border_radius: BorderRadius::from(255.0),
..Default::default()
}
}

/// Produces the hovered [`Appearance`] of a button.
fn hovered(&self, style: &Self::Style) -> iced_style::button::Appearance {
let mut active = self.active(style);

if let Some(iced_core::Background::Color(ref mut color)) = active.background {
color.r = (color.r + 0.05).min(1.0);
color.g = (color.g + 0.05).min(1.0);
color.b = (color.b + 0.05).min(1.0);
}

active
}
}
15 changes: 12 additions & 3 deletions neothesia/src/scene/playing_scene/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use midi_file::midly::MidiMessage;
use neothesia_core::render::{QuadPipeline, TextRenderer};
use piano_math::KeyboardRange;

use crate::{config::Config, render::KeyboardRenderer, target::Target};
use crate::{config::Config, render::KeyboardRenderer, song::SongConfig, target::Target};

pub struct Keyboard {
renderer: KeyboardRenderer,
song_config: SongConfig,
}

fn get_layout(width: f32, height: f32) -> piano_math::KeyboardLayout {
Expand All @@ -18,7 +19,7 @@ fn get_layout(width: f32, height: f32) -> piano_math::KeyboardLayout {
}

impl Keyboard {
pub fn new(target: &Target) -> Self {
pub fn new(target: &Target, song_config: SongConfig) -> Self {
let layout = get_layout(
target.window_state.logical_size.width,
target.window_state.logical_size.height,
Expand All @@ -27,7 +28,10 @@ impl Keyboard {
let mut renderer = KeyboardRenderer::new(layout, target.config.vertical_guidelines);
renderer.position_on_bottom_of_parent(target.window_state.logical_size.height);

Self { renderer }
Self {
renderer,
song_config,
}
}

pub fn layout(&self) -> &piano_math::KeyboardLayout {
Expand Down Expand Up @@ -86,6 +90,11 @@ impl Keyboard {
let range_start = self.range().start() as usize;

for e in events {
let track = &self.song_config.tracks[e.track_id];
if !track.visible {
continue;
}

let (is_on, key) = match e.message {
MidiMessage::NoteOn { key, .. } => (true, key.as_int()),
MidiMessage::NoteOff { key, .. } => (false, key.as_int()),
Expand Down
Loading