From d77fdcca04f1503ddd73e392e2a69b948fd2899f Mon Sep 17 00:00:00 2001 From: subalterngames Date: Sun, 31 Dec 2023 11:02:28 -0500 Subject: [PATCH] compiles. fixed clippy warnings --- audio/src/conn.rs | 15 ++- common/src/effect.rs | 14 ++ common/src/effect/effect_type.rs | 71 ++++++---- common/src/lib.rs | 5 +- common/src/midi_track.rs | 14 +- common/src/state.rs | 9 +- data/text.csv | 1 + io/src/effects_panel.rs | 97 ++++++------- render/src/effects_panel.rs | 127 +++++++++++------- render/src/effects_panel/effect_field.rs | 103 ++++++++------ .../src/effects_panel/effect_field_state.rs | 10 +- .../src/effects_panel/effect_field_values.rs | 6 +- render/src/panel.rs | 1 + render/src/panels.rs | 6 + text/src/lib.rs | 32 +++-- 15 files changed, 311 insertions(+), 200 deletions(-) diff --git a/audio/src/conn.rs b/audio/src/conn.rs index 2d53169..0b6f88b 100644 --- a/audio/src/conn.rs +++ b/audio/src/conn.rs @@ -225,16 +225,23 @@ impl Conn { let mut end_time = 0; for track in tracks.iter() { let notes = track.get_playback_notes(state.time.playback); - let track_effects = track - .get_audio_effects(); - let mut effects = track_effects.iter().filter(|e| e.time >= state.time.playback).copied().collect::>(); + let track_effects = track.get_audio_effects(); + let mut effects = track_effects + .iter() + .filter(|e| e.time >= state.time.playback) + .copied() + .collect::>(); effects.sort(); // Set the track's effect values to the last values up until playback time. let program = &self.state.programs[&track.channel]; let mut chorus = program.chorus; let mut pan = program.pan; let mut reverb = program.reverb; - let mut prior_effects = track_effects.iter().filter(|e| e.time < state.time.playback).copied().collect::>(); + let mut prior_effects = track_effects + .iter() + .filter(|e| e.time < state.time.playback) + .copied() + .collect::>(); prior_effects.sort(); for effect in prior_effects { match effect.effect { diff --git a/common/src/effect.rs b/common/src/effect.rs index e47c4ef..a292145 100644 --- a/common/src/effect.rs +++ b/common/src/effect.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use std::cmp::Ordering; +use crate::EffectType; + /// A timed synthesizer effect. #[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)] pub struct Effect { @@ -12,6 +14,18 @@ pub struct Effect { pub effect: effect_type::EffectType, } +impl Effect { + /// Returns true if the effect is at, or is ongoing during, time `time` (in PPQ). + pub fn at_time(&self, time: u64) -> bool { + match &self.effect { + EffectType::PitchBend { value: _, duration } => { + self.time == time || (self.time < time && self.time + duration >= time) + } + _ => self.time == time, + } + } +} + impl Ord for Effect { fn cmp(&self, other: &Self) -> Ordering { self.time.cmp(&other.time) diff --git a/common/src/effect/effect_type.rs b/common/src/effect/effect_type.rs index 5576aba..81b11cc 100644 --- a/common/src/effect/effect_type.rs +++ b/common/src/effect/effect_type.rs @@ -1,9 +1,8 @@ use crate::MIDDLE_C; use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; use strum::EnumCount; use strum_macros::EnumCount as EnumCountMacro; -use std::hash::{Hash, Hasher}; - pub const MAX_PITCH_BEND: u16 = 16383; @@ -41,9 +40,15 @@ impl EffectType { EffectType::Chorus(500), EffectType::Reverb(500), EffectType::Pan(0), - EffectType::PitchBend { value: 0, duration: 0}, + EffectType::PitchBend { + value: 0, + duration: 0, + }, EffectType::ChannelPressure(0), - EffectType::PolyphonicKeyPressure { key: MIDDLE_C,value: 0} + EffectType::PolyphonicKeyPressure { + key: MIDDLE_C, + value: 0, + }, ] } @@ -55,11 +60,9 @@ impl EffectType { *value += 1; return true; } - } else { - if *value > 0 { - *value -= 1; - return true; - } + } else if *value > 0 { + *value -= 1; + return true; } } Self::Pan(value) => { @@ -68,11 +71,9 @@ impl EffectType { *value += 1; return true; } - } else { - if *value > -500 { - *value -= 1; - return true; - } + } else if *value > -500 { + *value -= 1; + return true; } } Self::PitchBend { value, duration: _ } => { @@ -81,11 +82,9 @@ impl EffectType { *value += 1; return true; } - } else { - if *value > 0 { - *value -= 1; - return true; - } + } else if *value > 0 { + *value -= 1; + return true; } } Self::ChannelPressure(value) | Self::PolyphonicKeyPressure { key: _, value } => { @@ -94,11 +93,9 @@ impl EffectType { *value += 1; return true; } - } else { - if *value > 0 { - *value -= 1; - return true; - } + } else if *value > 0 { + *value -= 1; + return true; } } } @@ -111,10 +108,28 @@ impl EffectType { } /// Source: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=21e3ab42f76ccbc05b6b61560cbd29ec - fn get_ordinal(&self) -> u8 { + pub fn get_ordinal(&self) -> u8 { let ptr_to_option = (self as *const Self) as *const u8; - unsafe { - *ptr_to_option + unsafe { *ptr_to_option } + } + + pub fn get_value_string(&self) -> String { + match self { + Self::Chorus(value) | Self::Reverb(value) | Self::PitchBend { value, duration: _ } => { + value.to_string() + } + Self::Pan(value) => value.to_string(), + Self::ChannelPressure(value) | Self::PolyphonicKeyPressure { key: _, value } => { + value.to_string() + } + } + } + + pub fn get_secondary_value(&self) -> Option { + match self { + Self::PitchBend { value: _, duration } => Some(duration.to_string()), + Self::PolyphonicKeyPressure { key, value: _ } => Some(key.to_string()), + _ => None, } } } @@ -129,4 +144,4 @@ impl Hash for EffectType { fn hash(&self, state: &mut H) { self.get_ordinal().hash(state) } -} \ No newline at end of file +} diff --git a/common/src/lib.rs b/common/src/lib.rs index d7b403d..0afa88c 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -27,7 +27,10 @@ mod paths_state; mod state; pub mod time; pub mod view; -pub use effect::{effect_type::{EffectType, MAX_PITCH_BEND}, Effect}; +pub use effect::{ + effect_type::{EffectType, MAX_PITCH_BEND}, + Effect, +}; pub use event::Event; pub use index::Index; mod indexed_values; diff --git a/common/src/midi_track.rs b/common/src/midi_track.rs index d41bc51..373fbb7 100644 --- a/common/src/midi_track.rs +++ b/common/src/midi_track.rs @@ -1,4 +1,4 @@ -use crate::{Effect, EffectType, Note, MAX_VOLUME, MAX_PITCH_BEND}; +use crate::{Effect, EffectType, Note, MAX_PITCH_BEND, MAX_VOLUME}; use serde::{Deserialize, Serialize}; /// A MIDI track has some notes. @@ -59,7 +59,7 @@ impl MidiTrack { let mut effects = vec![]; for effect in self.effects.iter() { // Lerp the pitch bends. - if let EffectType::PitchBend { value, duration} = effect.effect { + if let EffectType::PitchBend { value, duration } = effect.effect { // Prevent a divide by zero error. if duration == 0 { continue; @@ -67,7 +67,13 @@ impl MidiTrack { let dv = (value as f64 / duration as f64) as u16; let mut pitch_value = 0; for t in 0..duration { - effects.push(Effect { time: effect.time + t, effect: EffectType::PitchBend { value: pitch_value, duration: 1 }}); + effects.push(Effect { + time: effect.time + t, + effect: EffectType::PitchBend { + value: pitch_value, + duration: 1, + }, + }); pitch_value += dv; if pitch_value > MAX_PITCH_BEND { break; @@ -76,7 +82,7 @@ impl MidiTrack { } // Add the effect. else { - effects.push(effect.clone()); + effects.push(*effect); } } effects.sort(); diff --git a/common/src/state.rs b/common/src/state.rs index 71c37f5..612627d 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -1,7 +1,7 @@ use crate::music_panel_field::MusicPanelField; use crate::{ - EditMode, EffectType, Index, IndexedEditModes, IndexedValues, InputState, Music, PanelType, PianoRollMode, - Selection, Time, View, + EditMode, EffectType, Index, IndexedEditModes, IndexedValues, InputState, Music, PanelType, + PianoRollMode, Selection, Time, View, }; use ini::Ini; use serde::{Deserialize, Serialize}; @@ -56,10 +56,7 @@ impl State { let piano_roll_mode = PianoRollMode::Time; let edit_mode = EditMode::indexed(); let selection = Selection::default(); - let effect_types = IndexedValues::new( - 0, - EffectType::get_array() - ); + let effect_types = IndexedValues::new(0, EffectType::get_array()); Self { music, view, diff --git a/data/text.csv b/data/text.csv index d71457e..55af686 100644 --- a/data/text.csv +++ b/data/text.csv @@ -391,6 +391,7 @@ TITLE_EXPORT_STATE,Exporting... TITLE_EXPORT_SETTINGS,Settings TITLE_QUIT,Really quit? TITLE_LINKS,Open a link in your browser +TITLE_EFFECTS,Effects TITLE_BPM,BPM TITLE_GAIN,Gain MAIN_MENU_HELP,Help: diff --git a/io/src/effects_panel.rs b/io/src/effects_panel.rs index 78e1536..bba4995 100644 --- a/io/src/effects_panel.rs +++ b/io/src/effects_panel.rs @@ -1,6 +1,6 @@ use crate::panel::*; use common::config::parse; -use common::{Effect, EffectType, MAX_NOTE, MIN_NOTE, MAX_PITCH_BEND}; +use common::{Effect, EffectType, MAX_NOTE, MAX_PITCH_BEND, MIN_NOTE}; use ini::Ini; /// Add, remove, or adjust effects. @@ -36,7 +36,11 @@ impl EffectsPanel { match Self::get_effect(state) { Some(effect) => { // Increment by an extra delta. - if let EffectType::PitchBend { value: _, duration: _ } = effect.effect { + if let EffectType::PitchBend { + value: _, + duration: _, + } = effect.effect + { let mut incremented = false; for i in 0..self.pitch_bend_sensitivity { if !effect.effect.increment(up) { @@ -53,12 +57,10 @@ impl EffectsPanel { } } // Increment by one. - else { - if effect.effect.increment(up) { - Some(Snapshot::from_states(s0, state)) - } else { - None - } + else if effect.effect.increment(up) { + Some(Snapshot::from_states(s0, state)) + } else { + None } } None => self.add_effect(state, conn), @@ -81,16 +83,14 @@ impl EffectsPanel { } else { None } + } else if key > MIN_NOTE { + effect.effect = EffectType::PolyphonicKeyPressure { + key: key - 1, + value, + }; + Some(Snapshot::from_states(s0, state)) } else { - if key > MIN_NOTE { - effect.effect = EffectType::PolyphonicKeyPressure { - key: key - 1, - value, - }; - Some(Snapshot::from_states(s0, state)) - } else { - None - } + None } } else { None @@ -115,16 +115,14 @@ impl EffectsPanel { } else { None } + } else if value > 0 { + effect.effect = EffectType::PitchBend { + value, + duration: duration - 1, + }; + Some(Snapshot::from_states(s0, state)) } else { - if value > 0 { - effect.effect = EffectType::PitchBend { - value, - duration: duration - 1 - }; - Some(Snapshot::from_states(s0, state)) - } else { - None - } + None } } else { None @@ -151,7 +149,10 @@ impl EffectsPanel { // Sort by time. effects.sort(); // Get the chronologically last effect of this type. - let last = effects.iter().filter(|e| selected_effect.valueless_eq(&e.effect)).last(); + let last = effects + .iter() + .filter(|e| selected_effect.valueless_eq(&e.effect)) + .last(); let program = &conn.state.programs[&track.channel]; // Get a new effect type. // Try to use the value of the last effect of this type, if it exists. @@ -170,8 +171,8 @@ impl EffectsPanel { }, _ => match &last { Some(effect) => effect.effect, - None => selected_effect.clone() - } + None => selected_effect, + }, }; // Get a new effect. track.effects.push(Effect { @@ -196,8 +197,7 @@ impl EffectsPanel { Some(track) => track .effects .iter_mut() - .filter(|e| e.time == state.time.cursor && ve.eq(&e.effect)) - .next(), + .find(|e| e.time == state.time.cursor && ve.eq(&e.effect)), None => None, } } @@ -221,7 +221,7 @@ impl Panel for EffectsPanel { input, text, ), - TtsString::from(self.tooltips.get_tooltip( + self.tooltips.get_tooltip( "EFFECTS_PANE_INPUT_TTS_VALUE", &[ InputEvent::IncrementEffectValue, @@ -229,11 +229,12 @@ impl Panel for EffectsPanel { ], input, text, - )), + ), ]; // Add a new effect. - if let EffectType::PolyphonicKeyPressure { value: _, key: _} = state.effect_types.get() { - tts_strings.push(TtsString::from(self.tooltips.get_tooltip( + if let EffectType::PolyphonicKeyPressure { value: _, key: _ } = state.effect_types.get() + { + tts_strings.push(self.tooltips.get_tooltip( "EFFECTS_PANEL_INPUT_TTS_AFTERTOUCH", &[ InputEvent::IncrementAftertouchNote, @@ -241,10 +242,13 @@ impl Panel for EffectsPanel { ], input, text, - ))); - } - else if let EffectType::PitchBend { value: _, duration: _} = state.effect_types.get() { - tts_strings.push(TtsString::from(self.tooltips.get_tooltip( + )); + } else if let EffectType::PitchBend { + value: _, + duration: _, + } = state.effect_types.get() + { + tts_strings.push(self.tooltips.get_tooltip( "EFFECTS_PANEL_STATUS_TTS_PITCH_BEND_DURATION", &[ InputEvent::IncrementPitchBendDuration, @@ -252,7 +256,7 @@ impl Panel for EffectsPanel { ], input, text, - ))); + )); } tts.enqueue(tts_strings); None @@ -265,7 +269,7 @@ impl Panel for EffectsPanel { let value = match effect.effect { EffectType::Chorus(value) | EffectType::Reverb(value) - | EffectType::PitchBend { value, duration: _} => value.to_string(), + | EffectType::PitchBend { value, duration: _ } => value.to_string(), EffectType::Pan(value) => value.to_string(), EffectType::ChannelPressure(value) | EffectType::PolyphonicKeyPressure { key: _, value } => value.to_string(), @@ -279,8 +283,7 @@ impl Panel for EffectsPanel { "EFFECTS_PANEL_STATUS_TTS_AFTERTOUCH_KEY", &[&key.to_string()], ))); - } - else if let EffectType::PitchBend { value: _, duration } = effect.effect { + } else if let EffectType::PitchBend { value: _, duration } = effect.effect { tts_strings.push(TtsString::from(text.get_with_values( "EFFECTS_PANEL_STATUS_TTS_PITCH_BEND_DURATION", &[&duration.to_string()], @@ -305,17 +308,15 @@ impl Panel for EffectsPanel { self.increment_effect_value(state, conn, true) } else if input.happened(&InputEvent::DecrementEffectValue) { self.increment_effect_value(state, conn, false) - } else if input.happened(&InputEvent::IncrementAftertouchNote) { + } else if input.happened(&InputEvent::IncrementAftertouchNote) { self.increment_aftertouch(state, conn, true) } else if input.happened(&InputEvent::DecrementAftertouchNote) { self.increment_aftertouch(state, conn, false) - } - else if input.happened(&InputEvent::IncrementPitchBendDuration) { + } else if input.happened(&InputEvent::IncrementPitchBendDuration) { self.increment_pitch_bend(state, conn, true) } else if input.happened(&InputEvent::DecrementPitchBendDuration) { self.increment_pitch_bend(state, conn, false) - } - else { + } else { None } } diff --git a/render/src/effects_panel.rs b/render/src/effects_panel.rs index 2b9427e..edd2784 100644 --- a/render/src/effects_panel.rs +++ b/render/src/effects_panel.rs @@ -1,22 +1,21 @@ mod effect_field; -mod effect_field_values; mod effect_field_state; +mod effect_field_values; use crate::get_effects_panel_width; use crate::panel::*; use common::EffectType; use effect_field::EffectField; -use effect_field_values::EffectFieldValues; use effect_field_state::EffectFieldState; - +use effect_field_values::EffectFieldValues; +use strum::EnumCount; pub(crate) struct EffectsPanel { panel: Panel, effect_fields: [EffectField; 6], - effect_types: [EffectType; 6] } impl EffectsPanel { - pub fn new(config: &Ini, state: &State, renderer: &Renderer, text: &Text) -> Self { + pub fn new(config: &Ini, renderer: &Renderer, text: &Text) -> Self { // Get the panel. let size = [ get_effects_panel_width(text), @@ -33,66 +32,100 @@ impl EffectsPanel { let x = position[0] + 1; let mut y = position[1] + 1; let width = size[0] - 2; - let mut effect_types = state.effect_types.clone(); - let mut effects = vec![]; - effect_types.index.set(0); - for i in 0..effect_types.index.get_length() { - effects.push(EffectField::new(x, &mut y, width, &mut effect_types, text)); + let mut effect_fields = vec![]; + for effect_type in EffectType::get_array() { + effect_fields.push(EffectField::new(x, &mut y, width, &effect_type, text)); } - let effect_fields: [EffectField; 6] = effects.try_into().unwrap(); Self { panel, - effect_fields, - effect_types: EffectType::get_array() + effect_fields: effect_fields.try_into().unwrap(), } } + + fn get_effect_index(effect_type: &EffectType) -> usize { + effect_type.get_ordinal() as usize + } } impl Drawable for EffectsPanel { - fn update( - &self, - renderer: &Renderer, - state: &State, - _: &Conn, - _: &Text, - _: &PathsState, - ) { + fn update(&self, renderer: &Renderer, state: &State, _: &Conn, _: &Text, _: &PathsState) { // Render the panel. let focus = self.panel.has_focus(state); self.panel.update(focus, renderer); - + // Is there a playable track? - match state.music.get_selected_track() { - Some(track) => { - // Generate states for each type of field. - let mut field_states = [EffectFieldState::default(); EffectType::len()]; - // Mark fields as selected and/or current. + if let Some(track) = state.music.get_selected_track() { + // Generate states for each type of field. + let mut field_states = [EffectFieldState::default(); EffectType::COUNT]; + // Get all effects at the cursor. + for effect in track + .effects + .iter() + .filter(|e| e.at_time(state.time.cursor)) + { + // Get the index of the effect. + let i = Self::get_effect_index(&effect.effect); + // This effect is happening now. + field_states[i].now = true; + // Set the effect type. + field_states[i].effect_type = Some(effect.effect); + } + if focus { + // Mark fields as selected. if let Some((_, effects)) = state.selection.get_selection(&state.music) { for effect in effects { - for (i, e) in self.effect_types.iter().enumerate() { - // This type of effect is selected. - if e.valueless_eq(&effect.effect) { - field_states[i].selected = true; - } - // This type of effect is at the playback cursor. - match effect.effect { - // Check whether the effect is in range. - EffectType::PitchBend { value: _, duration } { - if effect.time == state.time.cursor || (effect.time < state.time.cursor && effect.time + duration >= state.time.cursor) - } - } + let i = Self::get_effect_index(&effect.effect); + if field_states[i].now { + field_states[i].selected = true; } } } - // Get the effects at this time. - let current_effects = track.effects.iter().filter(|e| e.time == state.time.cursor).map(|e| ValuelessEffectType::from(e.effect)).collect::>(); - for ((field, selected), effect) in self.effects.iter().zip(selected).zip(current_effects) { - - } } - None => { - for e in self.effects.iter() { - renderer.text(&e.label, &ColorKey::NoFocus); + // Render. + let selected_in_panel_index = state.effect_types.index.get(); + for (i, (field_state, ui_field)) in + field_states.iter().zip(&self.effect_fields).enumerate() + { + let (key_color, values_focus) = if focus { + // Draw the background of a selected note. + if field_state.selected { + renderer.rectangle(&ui_field.rect, &ColorKey::NoteSelected); + (ColorKey::Separator, false) + } else { + match field_state.effect_type { + Some(_) => (ColorKey::Key, true), + None => (ColorKey::Separator, false), + } + } + } else { + (ColorKey::NoFocus, false) + }; + // Draw corners. + if i == selected_in_panel_index { + renderer.corners(&ui_field.rect, focus); + } + // Draw the label. + renderer.text(&ui_field.label, &key_color); + let effect = match field_state.effect_type { + Some(effect) => effect, + None => EffectType::get_array()[i], + }; + // Draw the values. + match &ui_field.values { + EffectFieldValues::One(list) => { + renderer.list(&effect.get_value_string(), list, [focus, values_focus]) + } + EffectFieldValues::Two(key_lists) => { + // Draw the primary value. + renderer.key_list( + &effect.get_value_string(), + &key_lists[0], + [focus, values_focus], + ); + if let Some(v) = effect.get_secondary_value() { + renderer.key_list(&v, &key_lists[1], [focus, values_focus]); + } + } } } } diff --git a/render/src/effects_panel/effect_field.rs b/render/src/effects_panel/effect_field.rs index 5732711..7751477 100644 --- a/render/src/effects_panel/effect_field.rs +++ b/render/src/effects_panel/effect_field.rs @@ -1,7 +1,7 @@ -use common::{IndexedValues, EffectType}; +use super::effect_field_values::EffectFieldValues; use crate::field_params::{KeyList, Label, List, Rectangle}; +use common::EffectType; use text::Text; -use super::effect_field_values::EffectFieldValues; const VALUE_WIDTH: u32 = 5; @@ -9,56 +9,75 @@ const VALUE_WIDTH: u32 = 5; #[derive(Debug)] pub(super) struct EffectField { /// The label of the effect's name. - label: Label, + pub label: Label, /// The render data for the values of the effect's fields. - values: EffectFieldValues, + pub values: EffectFieldValues, /// The rectangle of the effect's UI widget, spanning the label and the values. - rect: Rectangle, + pub rect: Rectangle, } impl EffectField { - pub(super) fn new(x: u32, y: &mut u32, width: u32, effect_types: &mut IndexedValues, text: &Text) -> Self { - let e = effect_types.get(); + pub(super) fn new( + x: u32, + y: &mut u32, + width: u32, + effect_type: &EffectType, + text: &Text, + ) -> Self { // Get the title label by getting the effect name. - let label = Label::new([x, *y], text.get_effect_type_name(&e).to_string()); + let label = Label::new([x, *y], text.get_effect_type_name(effect_type).to_string()); // Get the value field. - let (values, dy) = match e { - EffectType::PitchBend { value: _, duration: _} => { - (EffectFieldValues::Two([KeyList::new( - text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PITCH_BEND_VALUE"), - [x, *y + 1], - width, - VALUE_WIDTH, - ), - KeyList::new( - text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PITCH_BEND_DURATION"), - [x, *y + 2], - width, - VALUE_WIDTH, - ),]), 4) - } - EffectType::PolyphonicKeyPressure { key: _, value: _} => { - (EffectFieldValues::Two([KeyList::new( - text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PRESSURE_NOTE"), - [x, *y + 1], - width, - VALUE_WIDTH, - ), - KeyList::new( - text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PRESSURE_VALUE"), - [x, *y + 2], - width, - VALUE_WIDTH, - ),]), 4) - } - _ => (EffectFieldValues::One(List::new([x, *y + 1], VALUE_WIDTH)), 3) + let (values, dy) = match effect_type { + EffectType::PitchBend { + value: _, + duration: _, + } => ( + EffectFieldValues::Two([ + KeyList::new( + text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PITCH_BEND_VALUE"), + [x, *y + 1], + width, + VALUE_WIDTH, + ), + KeyList::new( + text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PITCH_BEND_DURATION"), + [x, *y + 2], + width, + VALUE_WIDTH, + ), + ]), + 4, + ), + EffectType::PolyphonicKeyPressure { key: _, value: _ } => ( + EffectFieldValues::Two([ + KeyList::new( + text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PRESSURE_NOTE"), + [x, *y + 1], + width, + VALUE_WIDTH, + ), + KeyList::new( + text.get("EFFECTS_PANEL_POLYPHONIC_KEY_PRESSURE_VALUE"), + [x, *y + 2], + width, + VALUE_WIDTH, + ), + ]), + 4, + ), + _ => ( + EffectFieldValues::One(List::new([x, *y + 1], VALUE_WIDTH)), + 3, + ), }; // Get the background rectangle. let rect = Rectangle::new([x, *y], [width, dy]); // Increment the y value. *y += dy; - // Increment so we can set the next effect. - effect_types.index.increment(true); - Self { label, values, rect } + Self { + label, + values, + rect, + } } -} \ No newline at end of file +} diff --git a/render/src/effects_panel/effect_field_state.rs b/render/src/effects_panel/effect_field_state.rs index 248709c..3208582 100644 --- a/render/src/effects_panel/effect_field_state.rs +++ b/render/src/effects_panel/effect_field_state.rs @@ -1,8 +1,12 @@ +use common::EffectType; + /// The state of an effect UI field. #[derive(Default, Copy, Clone, Eq, PartialEq, Debug)] pub(super) struct EffectFieldState { - /// If true, the user selected at least one effect of this type. + /// If true, the user selected at least one effect of this type in the piano roll panel. pub selected: bool, /// If true, there is an effect of this type at the cursor time. - pub current: bool, -} \ No newline at end of file + pub now: bool, + /// The associated effect. + pub effect_type: Option, +} diff --git a/render/src/effects_panel/effect_field_values.rs b/render/src/effects_panel/effect_field_values.rs index 913d7fd..f191ec7 100644 --- a/render/src/effects_panel/effect_field_values.rs +++ b/render/src/effects_panel/effect_field_values.rs @@ -1,9 +1,9 @@ -use crate::field_params::{List, KeyList}; +use crate::field_params::{KeyList, List}; /// The values of an effect field. /// Some effects have one value, some have two. #[derive(Debug)] pub(super) enum EffectFieldValues { One(List), - Two([KeyList; 2]) -} \ No newline at end of file + Two([KeyList; 2]), +} diff --git a/render/src/panel.rs b/render/src/panel.rs index 4cbffa4..328db96 100644 --- a/render/src/panel.rs +++ b/render/src/panel.rs @@ -36,6 +36,7 @@ impl Panel { PanelType::ExportSettings => text.get("TITLE_EXPORT_SETTINGS"), PanelType::Quit => text.get("TITLE_QUIT"), PanelType::Links => text.get("TITLE_LINKS"), + PanelType::Effects => text.get("TITLE_EFFECTS"), }; let title_position = [position[0] + 2, position[1]]; let title = LabelRectangle::new(title_position, title); diff --git a/render/src/panels.rs b/render/src/panels.rs index 54d4712..3a5a1b9 100644 --- a/render/src/panels.rs +++ b/render/src/panels.rs @@ -1,3 +1,4 @@ +use crate::effects_panel::EffectsPanel; use crate::export_panel::ExportPanel; use crate::export_settings_panel::ExportSettingsPanel; use crate::links_panel::LinksPanel; @@ -30,6 +31,8 @@ pub struct Panels { quit_panel: QuitPanel, /// The links panel. links_panel: LinksPanel, + /// The effects panel. + effects_panel: EffectsPanel, } impl Panels { @@ -52,6 +55,7 @@ impl Panels { ExportSettingsPanel::new(config, renderer, &conn.exporter, text); let quit_panel = QuitPanel::new(config, renderer, text, input); let links_panel = LinksPanel::new(config, renderer, text, input); + let effects_panel = EffectsPanel::new(config, renderer, text); Self { music_panel, main_menu, @@ -62,6 +66,7 @@ impl Panels { export_settings_panel, quit_panel, links_panel, + effects_panel, } } @@ -95,6 +100,7 @@ impl Panels { PanelType::ExportSettings => &self.export_settings_panel, PanelType::Quit => &self.quit_panel, PanelType::Links => &self.links_panel, + PanelType::Effects => &self.effects_panel, }; // Draw the panel. panel.update(renderer, state, conn, text, paths_state); diff --git a/text/src/lib.rs b/text/src/lib.rs index 106c3cf..a925071 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -12,9 +12,7 @@ use std::path::Path; pub use value_map::ValueMap; mod tts_string; use common::config::parse; -use common::{ - EditMode, EffectType, Event, Paths, PianoRollMode, Time, MIN_NOTE, PPQ_F, PPQ_U, -}; +use common::{EditMode, EffectType, Event, Paths, PianoRollMode, Time, MIN_NOTE, PPQ_F, PPQ_U}; use csv::Reader; use hashbrown::HashMap; use ini::Ini; @@ -168,7 +166,7 @@ pub struct Text { note_names: Vec, /// Boolean display strings. booleans: ValueMap, - effect_types: ValueMap + effect_types: ValueMap, } impl Text { @@ -200,13 +198,17 @@ impl Text { [true, false], [text["TRUE"].clone(), text["FALSE"].clone()], ); - let effect_types = ValueMap::new_from_strings(EffectType::get_array(), - [text["EFFECT_TYPE_CHORUS"].clone(), - text["EFFECT_TYPE_PAN"].clone(), - text["EFFECT_TYPE_REVERB"].clone(), - text["EFFECT_TYPE_PITCH_BEND"].clone(), - text["EFFECT_TYPE_CHANNEL_PRESSURE"].clone(), - text["EFFECT_TYPE_POLYPHONIC_KEY_PRESSURE"].clone()]); + let effect_types = ValueMap::new_from_strings( + EffectType::get_array(), + [ + text["EFFECT_TYPE_CHORUS"].clone(), + text["EFFECT_TYPE_PAN"].clone(), + text["EFFECT_TYPE_REVERB"].clone(), + text["EFFECT_TYPE_PITCH_BEND"].clone(), + text["EFFECT_TYPE_CHANNEL_PRESSURE"].clone(), + text["EFFECT_TYPE_POLYPHONIC_KEY_PRESSURE"].clone(), + ], + ); Self { text, keycodes_spoken, @@ -215,7 +217,7 @@ impl Text { piano_roll_modes, note_names, booleans, - effect_types + effect_types, } } @@ -348,14 +350,16 @@ impl Text { /// Returns the name of a note or event. pub fn get_event_name(&self, event: &Event<'_>) -> String { match event { - Event::Effect { effect, index: _ } => self.get_effect_type_name(&effect.effect).to_string(), + Event::Effect { effect, index: _ } => { + self.get_effect_type_name(&effect.effect).to_string() + } Event::Note { note, index: _ } => note.get_name().to_string(), } } /// Returns the name of an effect type. pub fn get_effect_type_name<'a>(&'a self, effect: &EffectType) -> &'a str { - &self.effect_types.get(effect) + self.effect_types.get(effect) } pub fn get_max_effect_type_length(&self) -> u32 {