Skip to content

Commit

Permalink
Plug in track config
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Oct 4, 2023
1 parent e75b404 commit d462c08
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 63 deletions.
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
63 changes: 50 additions & 13 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.midi_file.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.midi_file = 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.midi_file.as_mut() {
song.config.tracks[track].player = config;
}
}
Message::TrackVisibilityConfig(track, visible) => {
if let Some(song) = target.midi_file.as_mut() {
song.config.tracks[track].visible = visible;
}
}
Message::VerticalGuidelines(v) => {
target.config.vertical_guidelines = v;
}
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.midi_file.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

0 comments on commit d462c08

Please sign in to comment.