mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
traits MIDIRange and MIDIPoint
This commit is contained in:
parent
d06b95df2c
commit
8f0decbe4d
7 changed files with 236 additions and 235 deletions
|
|
@ -2,6 +2,7 @@ mod phrase; pub(crate) use phrase::*;
|
|||
mod jack; pub(crate) use self::jack::*;
|
||||
mod clip; pub(crate) use clip::*;
|
||||
mod clock; pub(crate) use clock::*;
|
||||
mod note; pub(crate) use note::*;
|
||||
mod player; pub(crate) use player::*;
|
||||
mod scene; pub(crate) use scene::*;
|
||||
mod track; pub(crate) use track::*;
|
||||
|
|
|
|||
94
crates/tek/src/api/note.rs
Normal file
94
crates/tek/src/api/note.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
use crate::*;
|
||||
use Ordering::Relaxed;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MIDIRangeModel {
|
||||
/// Length of visible time axis
|
||||
pub time_axis: Arc<AtomicUsize>,
|
||||
/// Earliest time displayed
|
||||
pub time_start: Arc<AtomicUsize>,
|
||||
/// Time step
|
||||
pub time_zoom: Arc<AtomicUsize>,
|
||||
/// Auto rezoom to fit in time axis
|
||||
pub time_lock: Arc<AtomicBool>,
|
||||
/// Length of visible note axis
|
||||
pub note_axis: Arc<AtomicUsize>,
|
||||
// Lowest note displayed
|
||||
pub note_lo: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl From<(usize, bool)> for MIDIRangeModel {
|
||||
fn from ((time_zoom, time_lock): (usize, bool)) -> Self {
|
||||
Self {
|
||||
note_axis: Arc::new(0.into()),
|
||||
note_lo: Arc::new(0.into()),
|
||||
time_axis: Arc::new(0.into()),
|
||||
time_start: Arc::new(0.into()),
|
||||
time_zoom: Arc::new(time_zoom.into()),
|
||||
time_lock: Arc::new(time_lock.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MIDIPointModel {
|
||||
/// Time coordinate of cursor
|
||||
pub time_point: Arc<AtomicUsize>,
|
||||
/// Note coordinate of cursor
|
||||
pub note_point: Arc<AtomicUsize>,
|
||||
/// Length of note that will be inserted, in pulses
|
||||
pub note_len: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Default for MIDIPointModel {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
time_point: Arc::new(0.into()),
|
||||
note_point: Arc::new(0.into()),
|
||||
note_len: Arc::new(24.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MIDIRange {
|
||||
fn time_zoom (&self) -> usize;
|
||||
fn set_time_zoom (&self, x: usize);
|
||||
fn time_lock (&self) -> bool;
|
||||
fn set_time_lock (&self, x: bool);
|
||||
fn time_start (&self) -> usize;
|
||||
fn set_time_start (&self, x: usize);
|
||||
fn note_lo (&self) -> usize;
|
||||
fn set_note_lo (&self, x: usize);
|
||||
fn note_axis (&self) -> usize;
|
||||
fn note_hi (&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait MIDIPoint {
|
||||
fn note_len (&self) -> usize;
|
||||
fn set_note_len (&self, x: usize);
|
||||
fn note_point (&self) -> usize;
|
||||
fn set_note_point (&self, x: usize);
|
||||
fn time_point (&self) -> usize;
|
||||
fn set_time_point (&self, x: usize);
|
||||
}
|
||||
|
||||
impl MIDIRange for MIDIRangeModel {
|
||||
fn time_zoom (&self) -> usize { self.time_zoom.load(Relaxed) }
|
||||
fn set_time_zoom (&self, x: usize) { self.time_zoom.store(x, Relaxed); }
|
||||
fn time_lock (&self) -> bool { self.time_lock.load(Relaxed) }
|
||||
fn set_time_lock (&self, x: bool) { self.time_lock.store(x, Relaxed); }
|
||||
fn time_start (&self) -> usize { self.time_start.load(Relaxed) }
|
||||
fn set_time_start (&self, x: usize) { self.time_start.store(x, Relaxed); }
|
||||
fn set_note_lo (&self, x: usize) { self.note_lo.store(x, Relaxed); }
|
||||
fn note_lo (&self) -> usize { self.note_lo.load(Relaxed) }
|
||||
fn note_axis (&self) -> usize { self.note_lo.load(Relaxed) }
|
||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||
}
|
||||
impl MIDIPoint for MIDIPointModel {
|
||||
fn note_len (&self) -> usize { self.note_len.load(Relaxed)}
|
||||
fn set_note_len (&self, x: usize) { self.note_len.store(x, Relaxed) }
|
||||
fn note_point (&self) -> usize { self.note_point.load(Relaxed) }
|
||||
fn set_note_point (&self, x: usize) { self.note_point.store(x, Relaxed) }
|
||||
fn time_point (&self) -> usize { self.time_point.load(Relaxed) }
|
||||
fn set_time_point (&self, x: usize) { self.time_point.store(x, Relaxed) }
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ mod engine; pub(crate) use engine::*;
|
|||
mod focus; pub(crate) use focus::*;
|
||||
mod input; pub(crate) use input::*;
|
||||
mod output; pub(crate) use output::*;
|
||||
mod perf; pub(crate) use perf::*;
|
||||
mod pitch; pub(crate) use pitch::*;
|
||||
mod space; pub(crate) use space::*;
|
||||
mod time; pub(crate) use time::*;
|
||||
|
|
|
|||
54
crates/tek/src/core/perf.rs
Normal file
54
crates/tek/src/core/perf.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use crate::*;
|
||||
|
||||
/// Performance counter
|
||||
pub struct PerfModel {
|
||||
pub enabled: bool,
|
||||
clock: quanta::Clock,
|
||||
// In nanoseconds
|
||||
used: AtomicF64,
|
||||
// In microseconds
|
||||
period: AtomicF64,
|
||||
}
|
||||
|
||||
impl Default for PerfModel {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
clock: quanta::Clock::new(),
|
||||
used: Default::default(),
|
||||
period: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PerfModel {
|
||||
pub fn get_t0 (&self) -> Option<u64> {
|
||||
if self.enabled {
|
||||
Some(self.clock.raw())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn update (&self, t0: Option<u64>, scope: &jack::ProcessScope) {
|
||||
if let Some(t0) = t0 {
|
||||
let t1 = self.clock.raw();
|
||||
self.used.store(
|
||||
self.clock.delta_as_nanos(t0, t1) as f64,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
self.period.store(
|
||||
scope.cycle_times().unwrap().period_usecs as f64,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn percentage (&self) -> Option<f64> {
|
||||
let period = self.period.load(Ordering::Relaxed) * 1000.0;
|
||||
if period > 0.0 {
|
||||
let used = self.used.load(Ordering::Relaxed);
|
||||
Some(100.0 * used / period)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,59 +386,6 @@ pub fn pulses_to_name (pulses: usize) -> &'static str {
|
|||
""
|
||||
}
|
||||
|
||||
/// Performance counter
|
||||
pub struct PerfModel {
|
||||
pub enabled: bool,
|
||||
clock: quanta::Clock,
|
||||
// In nanoseconds
|
||||
used: AtomicF64,
|
||||
// In microseconds
|
||||
period: AtomicF64,
|
||||
}
|
||||
|
||||
impl Default for PerfModel {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
clock: quanta::Clock::new(),
|
||||
used: Default::default(),
|
||||
period: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PerfModel {
|
||||
pub fn get_t0 (&self) -> Option<u64> {
|
||||
if self.enabled {
|
||||
Some(self.clock.raw())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn update (&self, t0: Option<u64>, scope: &jack::ProcessScope) {
|
||||
if let Some(t0) = t0 {
|
||||
let t1 = self.clock.raw();
|
||||
self.used.store(
|
||||
self.clock.delta_as_nanos(t0, t1) as f64,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
self.period.store(
|
||||
scope.cycle_times().unwrap().period_usecs as f64,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn percentage (&self) -> Option<f64> {
|
||||
let period = self.period.load(Ordering::Relaxed) * 1000.0;
|
||||
if period > 0.0 {
|
||||
let used = self.used.load(Ordering::Relaxed);
|
||||
Some(100.0 * used / period)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#[cfg(test)]
|
||||
//mod test {
|
||||
//use super::*;
|
||||
|
|
|
|||
|
|
@ -28,14 +28,13 @@ pub enum PhraseCommand {
|
|||
impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
||||
fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> {
|
||||
let length = ||state.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
|
||||
let range = state.range();
|
||||
let note_lo = ||range.note_lo.load(Relaxed);
|
||||
let time_start = ||range.time_start.load(Relaxed);
|
||||
let time_zoom = ||range.time_zoom();
|
||||
let point = state.point();
|
||||
let note_point = ||point.note_point();
|
||||
let time_point = ||point.time_point();
|
||||
let note_len = ||point.note_len();
|
||||
let note_lo = ||state.note_lo();
|
||||
let time_start = ||state.time_start();
|
||||
let time_zoom = ||state.time_zoom();
|
||||
let time_lock = ||state.time_lock();
|
||||
let note_point = ||state.note_point();
|
||||
let time_point = ||state.time_point();
|
||||
let note_len = ||state.note_len();
|
||||
Some(match from.event() {
|
||||
key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point() + 3),
|
||||
key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point().saturating_sub(3)),
|
||||
|
|
@ -54,7 +53,7 @@ impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
|||
key_pat!(Left) => SetTimeCursor(time_point().saturating_sub(note_len())),
|
||||
key_pat!(Right) => SetTimeCursor((time_point() + note_len()) % length()),
|
||||
key_pat!(Char('`')) => ToggleDirection,
|
||||
key_pat!(Char('z')) => SetTimeLock(!state.range().time_lock()),
|
||||
key_pat!(Char('z')) => SetTimeLock(!time_lock()),
|
||||
key_pat!(Char('-')) => SetTimeZoom(next_note_length(time_zoom())),
|
||||
key_pat!(Char('_')) => SetTimeZoom(next_note_length(time_zoom())),
|
||||
key_pat!(Char('=')) => SetTimeZoom(prev_note_length(time_zoom())),
|
||||
|
|
@ -75,27 +74,24 @@ impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
|||
impl Command<PhraseEditorModel> for PhraseCommand {
|
||||
fn execute (self, state: &mut PhraseEditorModel) -> Perhaps<Self> {
|
||||
use PhraseCommand::*;
|
||||
let range = state.range();
|
||||
let point = state.point();
|
||||
match self {
|
||||
Show(phrase) => { state.set_phrase(phrase.as_ref()); },
|
||||
PutNote => { state.put_note(false); },
|
||||
AppendNote => { state.put_note(true); },
|
||||
SetTimeZoom(x) => { range.set_time_zoom(x); },
|
||||
SetTimeLock(x) => { range.set_time_lock(x); },
|
||||
SetTimeScroll(x) => { range.set_time_start(x); },
|
||||
SetNoteScroll(x) => { range.set_note_lo(x); },
|
||||
SetNoteLength(x) => { point.set_note_len(x); },
|
||||
SetTimeCursor(x) => { point.set_time_point(x); },
|
||||
SetTimeZoom(x) => { state.set_time_zoom(x); },
|
||||
SetTimeLock(x) => { state.set_time_lock(x); },
|
||||
SetTimeScroll(x) => { state.set_time_start(x); },
|
||||
SetNoteScroll(x) => { state.set_note_lo(x); },
|
||||
SetNoteLength(x) => { state.set_note_len(x); },
|
||||
SetTimeCursor(x) => { state.set_time_point(x); },
|
||||
SetNoteCursor(note) => {
|
||||
let note = 127.min(note);
|
||||
let start = range.note_lo.load(Relaxed);
|
||||
point.note_point.store(note, Relaxed);
|
||||
let start = state.note_lo();
|
||||
state.set_note_point(note);
|
||||
if note < start {
|
||||
range.note_lo.store(note, Relaxed);
|
||||
state.set_note_lo(note)
|
||||
}
|
||||
},
|
||||
|
||||
_ => todo!("{:?}", self)
|
||||
}
|
||||
Ok(None)
|
||||
|
|
@ -116,9 +112,7 @@ impl Default for PhraseEditorModel {
|
|||
|
||||
render!(|self: PhraseEditorModel|self.mode);
|
||||
|
||||
pub trait PhraseViewMode: Render<Tui> + Debug + Send + Sync {
|
||||
fn range (&self) -> &PhraseEditorRange;
|
||||
fn point (&self) -> &PhraseEditorPoint;
|
||||
pub trait PhraseViewMode: Render<Tui> + MIDIRange + MIDIPoint + Debug + Send + Sync {
|
||||
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize);
|
||||
fn redraw (&mut self);
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>>;
|
||||
|
|
@ -129,13 +123,27 @@ pub trait PhraseViewMode: Render<Tui> + Debug + Send + Sync {
|
|||
}
|
||||
}
|
||||
|
||||
impl MIDIRange for PhraseEditorModel {
|
||||
fn time_zoom (&self) -> usize { self.mode.time_zoom() }
|
||||
fn set_time_zoom (&self, x: usize) { self.mode.set_time_zoom(x); }
|
||||
fn time_lock (&self) -> bool { self.mode.time_lock() }
|
||||
fn set_time_lock (&self, x: bool) { self.mode.set_time_lock(x); }
|
||||
fn time_start (&self) -> usize { self.mode.time_start() }
|
||||
fn set_time_start (&self, x: usize) { self.mode.set_time_start(x); }
|
||||
fn set_note_lo (&self, x: usize) { self.mode.set_note_lo(x); }
|
||||
fn note_lo (&self) -> usize { self.mode.note_lo() }
|
||||
fn note_axis (&self) -> usize { self.mode.note_lo() }
|
||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||
}
|
||||
impl MIDIPoint for PhraseEditorModel {
|
||||
fn note_len (&self) -> usize { self.mode.note_len()}
|
||||
fn set_note_len (&self, x: usize) { self.mode.set_note_len(x) }
|
||||
fn note_point (&self) -> usize { self.mode.note_point() }
|
||||
fn set_note_point (&self, x: usize) { self.mode.set_note_point(x) }
|
||||
fn time_point (&self) -> usize { self.mode.time_point() }
|
||||
fn set_time_point (&self, x: usize) { self.mode.set_time_point(x) }
|
||||
}
|
||||
impl PhraseViewMode for PhraseEditorModel {
|
||||
fn range (&self) -> &PhraseEditorRange {
|
||||
self.mode.range()
|
||||
}
|
||||
fn point (&self) -> &PhraseEditorPoint {
|
||||
self.mode.point()
|
||||
}
|
||||
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize) {
|
||||
self.mode.buffer_size(phrase)
|
||||
}
|
||||
|
|
@ -153,113 +161,15 @@ impl PhraseViewMode for PhraseEditorModel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PhraseEditorRange {
|
||||
/// Length of visible time axis
|
||||
pub time_axis: Arc<AtomicUsize>,
|
||||
/// Earliest time displayed
|
||||
pub time_start: Arc<AtomicUsize>,
|
||||
/// Time step
|
||||
pub time_zoom: Arc<AtomicUsize>,
|
||||
/// Auto rezoom to fit in time axis
|
||||
pub time_lock: Arc<AtomicBool>,
|
||||
/// Length of visible note axis
|
||||
pub note_axis: Arc<AtomicUsize>,
|
||||
// Lowest note displayed
|
||||
pub note_lo: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Default for PhraseEditorRange {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
time_axis: Arc::new(0.into()),
|
||||
time_start: Arc::new(0.into()),
|
||||
time_zoom: Arc::new(24.into()),
|
||||
time_lock: Arc::new(true.into()),
|
||||
note_axis: Arc::new(0.into()),
|
||||
note_lo: Arc::new(0.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PhraseEditorRange {
|
||||
pub fn time_zoom (&self) -> usize {
|
||||
self.time_zoom.load(Relaxed)
|
||||
}
|
||||
pub fn set_time_zoom (&self, x: usize) {
|
||||
self.time_zoom.store(x, Relaxed);
|
||||
}
|
||||
pub fn time_lock (&self) -> bool {
|
||||
self.time_lock.load(Relaxed)
|
||||
}
|
||||
pub fn set_time_lock (&self, x: bool) {
|
||||
self.time_lock.store(x, Relaxed);
|
||||
}
|
||||
pub fn time_start (&self) -> usize {
|
||||
self.time_start.load(Relaxed)
|
||||
}
|
||||
pub fn set_time_start (&self, x: usize) {
|
||||
self.time_start.store(x, Relaxed);
|
||||
}
|
||||
pub fn set_note_lo (&self, x: usize) {
|
||||
self.note_lo.store(x, Relaxed);
|
||||
}
|
||||
pub fn note_lo (&self) -> usize {
|
||||
self.note_lo.load(Relaxed)
|
||||
}
|
||||
pub fn note_axis (&self) -> usize {
|
||||
self.note_lo.load(Relaxed)
|
||||
}
|
||||
pub fn note_hi (&self) -> usize {
|
||||
self.note_lo() + self.note_axis()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PhraseEditorPoint {
|
||||
/// Time coordinate of cursor
|
||||
pub time_point: Arc<AtomicUsize>,
|
||||
/// Note coordinate of cursor
|
||||
pub note_point: Arc<AtomicUsize>,
|
||||
/// Length of note that will be inserted, in pulses
|
||||
pub note_len: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Default for PhraseEditorPoint {
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
time_point: Arc::new(0.into()),
|
||||
note_point: Arc::new(0.into()),
|
||||
note_len: Arc::new(24.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PhraseEditorPoint {
|
||||
pub fn note_len (&self) -> usize {
|
||||
self.note_len.load(Relaxed)
|
||||
}
|
||||
pub fn set_note_len (&self, x: usize) {
|
||||
self.note_len.store(x, Relaxed)
|
||||
}
|
||||
pub fn note_point (&self) -> usize {
|
||||
self.note_point.load(Relaxed)
|
||||
}
|
||||
pub fn time_point (&self) -> usize {
|
||||
self.time_point.load(Relaxed)
|
||||
}
|
||||
pub fn set_time_point (&self, x: usize) {
|
||||
self.time_point.store(x, Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
impl PhraseEditorModel {
|
||||
/// Put note at current position
|
||||
pub fn put_note (&mut self, advance: bool) {
|
||||
let mut redraw = false;
|
||||
if let Some(phrase) = self.phrase() {
|
||||
let mut phrase = phrase.write().unwrap();
|
||||
let note_start = self.point().time_point();
|
||||
let note_point = self.point().note_point();
|
||||
let note_len = self.point().note_len();
|
||||
let note_start = self.time_point();
|
||||
let note_point = self.note_point();
|
||||
let note_len = self.note_len();
|
||||
let note_end = note_start + note_len;
|
||||
let key: u7 = u7::from(note_point as u8);
|
||||
let vel: u7 = 100.into();
|
||||
|
|
@ -274,7 +184,7 @@ impl PhraseEditorModel {
|
|||
phrase.notes[note_end].push(note_off);
|
||||
}
|
||||
if advance {
|
||||
self.point().set_time_point(note_end);
|
||||
self.set_time_point(note_end);
|
||||
}
|
||||
redraw = true;
|
||||
}
|
||||
|
|
@ -282,6 +192,25 @@ impl PhraseEditorModel {
|
|||
self.mode.redraw();
|
||||
}
|
||||
}
|
||||
/// Make sure cursor is within range
|
||||
fn autoscroll (
|
||||
range: &impl MIDIRange,
|
||||
point: &impl MIDIPoint,
|
||||
height: usize
|
||||
) -> (usize, (usize, usize)) {
|
||||
let note_point = point.note_point();
|
||||
let mut note_lo = range.note_lo();
|
||||
let mut note_hi = 127.min((note_lo + height).saturating_sub(2));
|
||||
if note_point > note_hi {
|
||||
note_lo += note_point - note_hi;
|
||||
note_hi = note_point;
|
||||
range.set_note_lo(note_lo);
|
||||
}
|
||||
(note_point, (note_lo, note_hi))
|
||||
}
|
||||
/// Make sure best usage of screen space is achieved by default
|
||||
fn autozoom (&self) {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Arc<RwLock<Phrase>>> for PhraseEditorModel {
|
||||
|
|
@ -301,46 +230,7 @@ impl From<Option<Arc<RwLock<Phrase>>>> for PhraseEditorModel {
|
|||
impl std::fmt::Debug for PhraseEditorModel {
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
f.debug_struct("PhraseEditorModel")
|
||||
.field("range", &self.range())
|
||||
.field("point", &self.point())
|
||||
.field("point", &self)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn autoscroll_notes (
|
||||
range: &PhraseEditorRange, point: &PhraseEditorPoint, height: usize
|
||||
) -> (usize, (usize, usize)) {
|
||||
let note_point = point.note_point.load(Relaxed);
|
||||
let mut note_lo = range.note_lo.load(Relaxed);
|
||||
let mut note_hi = 127.min((note_lo + height).saturating_sub(2));
|
||||
if note_point > note_hi {
|
||||
note_lo += note_point - note_hi;
|
||||
note_hi = note_point;
|
||||
range.note_lo.store(note_lo, Relaxed);
|
||||
}
|
||||
(note_point, (note_lo, note_hi))
|
||||
}
|
||||
|
||||
//impl<'a, T: HasEditor> From<&'a T> for PhraseView<'a> {
|
||||
//fn from (state: &'a T) -> Self {
|
||||
//let editor = state.editor();
|
||||
//let (note_point, note_range) = autoscroll_notes(
|
||||
//&editor.range,
|
||||
//&editor.point,
|
||||
//editor.size.h()
|
||||
//);
|
||||
//Self {
|
||||
//note_point,
|
||||
//note_range,
|
||||
//time_start: editor.range.time_start.load(Relaxed),
|
||||
//time_point: editor.point.time_point.load(Relaxed),
|
||||
//note_len: editor.point.note_len.load(Relaxed),
|
||||
//phrase: editor.phrase.clone(),
|
||||
//mode: &editor.mode,
|
||||
//size: &editor.size,
|
||||
//now: &editor.now,
|
||||
//focused: state.editor_focused(),
|
||||
//entered: state.editor_entered(),
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ pub struct PianoHorizontal {
|
|||
/// Width and height of notes area at last render
|
||||
size: Measure<Tui>,
|
||||
/// The display window
|
||||
range: PhraseEditorRange,
|
||||
range: MIDIRangeModel,
|
||||
/// The note cursor
|
||||
point: PhraseEditorPoint,
|
||||
point: MIDIPointModel,
|
||||
/// The highlight color palette
|
||||
color: ItemPalette,
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ pub struct PianoHorizontal {
|
|||
impl PianoHorizontal {
|
||||
pub fn new (phrase: Option<&Arc<RwLock<Phrase>>>) -> Self {
|
||||
let size = Measure::new();
|
||||
let mut range = PhraseEditorRange::default();
|
||||
let mut range = MIDIRangeModel::from((24, true));
|
||||
range.time_axis = size.x.clone();
|
||||
range.note_axis = size.y.clone();
|
||||
let phrase = phrase.map(|p|p.clone());
|
||||
|
|
@ -28,7 +28,7 @@ impl PianoHorizontal {
|
|||
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
|
||||
Self {
|
||||
buffer: Default::default(),
|
||||
point: PhraseEditorPoint::default(),
|
||||
point: MIDIPointModel::default(),
|
||||
size,
|
||||
range,
|
||||
phrase,
|
||||
|
|
@ -241,6 +241,26 @@ impl PianoHorizontal {
|
|||
}
|
||||
}
|
||||
|
||||
impl MIDIRange for PianoHorizontal {
|
||||
fn time_zoom (&self) -> usize { self.range.time_zoom() }
|
||||
fn set_time_zoom (&self, x: usize) { self.range.set_time_zoom(x); }
|
||||
fn time_lock (&self) -> bool { self.range.time_lock() }
|
||||
fn set_time_lock (&self, x: bool) { self.range.set_time_lock(x); }
|
||||
fn time_start (&self) -> usize { self.range.time_start() }
|
||||
fn set_time_start (&self, x: usize) { self.range.set_time_start(x); }
|
||||
fn set_note_lo (&self, x: usize) { self.range.set_note_lo(x); }
|
||||
fn note_lo (&self) -> usize { self.range.note_lo() }
|
||||
fn note_axis (&self) -> usize { self.range.note_lo() }
|
||||
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
|
||||
}
|
||||
impl MIDIPoint for PianoHorizontal {
|
||||
fn note_len (&self) -> usize { self.point.note_len()}
|
||||
fn set_note_len (&self, x: usize) { self.point.set_note_len(x) }
|
||||
fn note_point (&self) -> usize { self.point.note_point() }
|
||||
fn set_note_point (&self, x: usize) { self.point.set_note_point(x) }
|
||||
fn time_point (&self) -> usize { self.point.time_point() }
|
||||
fn set_time_point (&self, x: usize) { self.point.set_time_point(x) }
|
||||
}
|
||||
impl PhraseViewMode for PianoHorizontal {
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>> {
|
||||
&self.phrase
|
||||
|
|
@ -248,12 +268,6 @@ impl PhraseViewMode for PianoHorizontal {
|
|||
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<Phrase>>> {
|
||||
&mut self.phrase
|
||||
}
|
||||
fn range (&self) -> &PhraseEditorRange {
|
||||
&self.range
|
||||
}
|
||||
fn point (&self) -> &PhraseEditorPoint {
|
||||
&self.point
|
||||
}
|
||||
/// Determine the required space to render the phrase.
|
||||
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize) {
|
||||
(phrase.length / self.range.time_zoom(), 128)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue