From d39d7baf166aa6fcd1f11db0aa781eeaa3a6563d Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 12 Oct 2023 19:32:04 +0200 Subject: [PATCH] Remove NoreView, change appearance of the sustain line May have NoteView later if having a scene graph turns out to be a good idea. --- LICENSE | 5 ++ src/engine.rs | 4 +- src/lane.rs | 4 +- src/stave.rs | 123 +++++++++++++------------------------------------- 4 files changed, 41 insertions(+), 95 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9..2f2cc26 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,8 @@ +The project's code and accompanying files are distributed under Apache License Version 2.0, with exception of +the music MIDI file samples that are published under Creative Commons Attribution-NonCommercial (BY-NC) license. +Dependencies of the project may have their own licenses that are different from the project's. + +------------------------------------------------------------------------------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/src/engine.rs b/src/engine.rs index 725d502..ca5f035 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -9,7 +9,7 @@ use midly::MidiMessage; use vst::event::Event; use vst::plugin::Plugin; -use crate::lane::MIDI_CC_SUSTAIN; +use crate::lane::MIDI_CC_SUSTAIN_ID; use crate::midi_vst::Vst; /// uSecs from the start. @@ -145,7 +145,7 @@ impl Engine { let ev = LiveEvent::Midi { channel: 0.into(), message: MidiMessage::Controller { - controller: MIDI_CC_SUSTAIN.into(), + controller: MIDI_CC_SUSTAIN_ID.into(), value: 0.into(), }, }; diff --git a/src/lane.rs b/src/lane.rs index 3d12023..9eb7828 100644 --- a/src/lane.rs +++ b/src/lane.rs @@ -16,9 +16,9 @@ pub type Level = u8; pub type ChannelId = u8; pub type EventId = u64; -pub const MIDI_CC_MODWHEEL: ControllerId = 1; +pub const MIDI_CC_MODWHEEL_ID: ControllerId = 1; // Damper pedal -pub const MIDI_CC_SUSTAIN: ControllerId = 64; +pub const MIDI_CC_SUSTAIN_ID: ControllerId = 64; pub fn switch_cc_on(x: Level) -> bool { // Pianoteq seem to support continuous damper values, may support this later. diff --git a/src/stave.rs b/src/stave.rs index 66cd54c..a8534f2 100644 --- a/src/stave.rs +++ b/src/stave.rs @@ -9,73 +9,15 @@ use eframe::egui::{ }; use egui::Rgba; use ordered_float::OrderedFloat; -use wmidi::Velocity; use crate::engine::TransportTime; use crate::lane::{ - switch_cc_on, EventId, Lane, LaneEvent, LaneEventType, Level, Note, Pitch, MIDI_CC_SUSTAIN, + EventId, Lane, LaneEvent, LaneEventType, Level, Note, Pitch, MIDI_CC_SUSTAIN_ID, }; use crate::{lane, Pix}; pub type StaveTime = i64; -/* Could not get a better idea yet. Having rectangles with normalized dimensions in the view models. -These can be used both to draw notes in view functions, and as means to determine -clicks and selection/drag state of a note. -Time step is 1 uSec, vertical half tone step is 1. Bottom-left 0,0 is origin. -Control events in negative y coords, 1-width bands each. */ - -#[derive(Debug)] -pub struct NoteView { - rect: Rect, -} - -#[derive(Debug)] -pub struct ControllerView { - // Stub: have to see how to better represent these values. -} - -// Does it make sense now to use a dyn Trait instead? -// Is it really needed? Likely will not be using it for selection. -#[derive(Debug)] -pub enum EventView { - Note(NoteView), - Controller(ControllerView), -} - -impl From<&LaneEvent> for EventView { - fn from(event: &LaneEvent) -> Self { - match &event.event { - LaneEventType::Note(n) => EventView::Note(NoteView { - rect: NoteView::note_rect(event.at as StaveTime, n), - }), - LaneEventType::Controller(_) => EventView::Controller(ControllerView {}), - } - } -} - -impl NoteView { - pub fn note_rect( - at: StaveTime, - Note { - pitch, duration, .. - }: &Note, - ) -> Rect { - let y = *pitch as Pix + 0.5; - let x_end = (at + *duration as StaveTime) as Pix; - Rect { - min: Pos2 { - x: at as Pix, - y: y - 0.5, - }, - max: Pos2 { - x: x_end, - y: y + 0.5, - }, - } - } -} - // Tone 60 is C3, tones start at C-2 (21) const PIANO_LOWEST_KEY: Pitch = 21; const PIANO_KEY_COUNT: Pitch = 88; @@ -258,6 +200,7 @@ impl Stave { &Color32::from_black_alpha(15), ); let track = self.track.read().expect("Cannot read track."); + let mut last_damper_value: (StaveTime, Level) = (0, 0); for i in 0..track.events.len() { let event = &track.events[i]; match &event.event { @@ -269,7 +212,6 @@ impl Stave { event, ¬e.pitch, ); - let note_rect = NoteView::note_rect(event.at as StaveTime, ¬e); let clicked = ui.input(|i| i.pointer.button_clicked(PointerButton::Primary)); if clicked && note_hovered { @@ -277,23 +219,29 @@ impl Stave { } self.draw_note( &painter, - note, - ¬e_rect, - y, + note.velocity, + ( + event.at as StaveTime, + (event.at + note.duration) as StaveTime, + ), + *y, half_tone_step, self.note_selection.contains(&event), ); } } - LaneEventType::Controller(v) if v.controller_id == MIDI_CC_SUSTAIN => { + LaneEventType::Controller(v) if v.controller_id == MIDI_CC_SUSTAIN_ID => { if let Some(y) = key_ys.get(&PIANO_DAMPER_LINE) { + let at = event.at as StaveTime; self.draw_cc( &painter, - event.at as StaveTime, + last_damper_value, + at, v.value, *y, half_tone_step, ); + last_damper_value = (at, v.value); } } _ => (), /*println!( @@ -507,43 +455,36 @@ impl Stave { fn draw_note( &self, painter: &Painter, - Note { velocity, .. }: &Note, - rect: &Rect, - y: &Pix, + velocity: Level, + x_range: (StaveTime, StaveTime), + y: Pix, height: Pix, selected: bool, ) { - let h = rect.height() * height; let paint_rect = Rect { min: Pos2 { - x: self.x_from_time(rect.min.x as StaveTime), - y: y - h * 0.45, + x: self.x_from_time(x_range.0), + y: y - height * 0.45, }, max: Pos2 { - x: self.x_from_time(rect.max.x as StaveTime), - y: y + h * 0.45, + x: self.x_from_time(x_range.1), + y: y + height * 0.45, }, }; let stroke_color = note_color(&velocity, selected); - painter.rect(paint_rect, Rounding::ZERO, stroke_color, Stroke::NONE); + painter.rect_filled(paint_rect, Rounding::ZERO, stroke_color); } - fn draw_cc(&self, painter: &Painter, at: StaveTime, value: Level, y: Pix, height: Pix) { - let h = height * 0.95; - let on = switch_cc_on(value); - painter.circle( - Pos2::new( - self.x_from_time(at), - if on { y - (h / 4.0) } else { y + (h / 4.0) }, - ), - h / 4.0, - if on { - Rgba::from_rgb(0.3, 0.1, 0.1) - } else { - Rgba::from_rgb(0.1, 0.1, 0.3) - }, - Stroke::NONE, - ) + fn draw_cc( + &self, + painter: &Painter, + last_value: (StaveTime, Level), + at: StaveTime, + value: Level, + y: Pix, + height: Pix, + ) { + self.draw_note(painter, value, (last_value.0, at), y, height, false) } fn draw_grid( @@ -592,7 +533,7 @@ impl Stave { y: clip.max.y, }, }; - painter.rect(area, Rounding::ZERO, *color, Stroke::NONE); + painter.rect_filled(area, Rounding::ZERO, *color); painter.vline( area.min.x, clip.y_range(),