diff --git a/src/device/chain/sampler.rs b/src/device/chain/sampler.rs index b6488af3..5944c504 100644 --- a/src/device/chain/sampler.rs +++ b/src/device/chain/sampler.rs @@ -254,7 +254,7 @@ fn trigger (state: &mut Sampler) -> Usually { Ok(true) } fn select (state: &mut Sampler) -> Usually { - for (i, sample) in state.samples.values().enumerate() { + for (i, _sample) in state.samples.values().enumerate() { if i == state.cursor.0 { //state.voices.push(sample.play(0)) } diff --git a/src/device/launcher/handle.rs b/src/device/launcher/handle.rs index 9ebb3849..cf5a7f42 100644 --- a/src/device/launcher/handle.rs +++ b/src/device/launcher/handle.rs @@ -50,7 +50,7 @@ fn duplicate (_: &mut Launcher) -> Usually { } fn activate (state: &mut Launcher) -> Usually { if let ( - Some((scene_id, scene)), + Some((_scene_id, scene)), Some((track_id, track)), ) = (state.scene(), state.track()) { // Launch clip @@ -61,7 +61,7 @@ fn activate (state: &mut Launcher) -> Usually { state.transport.start()?; state.playing = TransportState::Starting; } - } else if let Some((scene_id, scene)) = state.scene() { + } else if let Some((_scene_id, scene)) = state.scene() { // Launch scene for (track_id, track) in state.tracks.iter().enumerate() { if let Some(phrase_id) = scene.clips.get(track_id) { @@ -72,7 +72,7 @@ fn activate (state: &mut Launcher) -> Usually { state.transport.start()?; state.playing = TransportState::Starting; } - } else if let Some((track_id, track)) = state.track() { + } else if let Some((_track_id, _track)) = state.track() { // Rename track? } diff --git a/src/device/launcher/mod.rs b/src/device/launcher/mod.rs index 0f3f2a11..8626ec65 100644 --- a/src/device/launcher/mod.rs +++ b/src/device/launcher/mod.rs @@ -186,12 +186,15 @@ pub fn render (state: &Launcher, buf: &mut Buffer, mut area: Rect) -> Usually Us } let track = track.unwrap().1; let sequencer = track.sequencer.state(); - crate::device::sequencer::horizontal::timer( - buf, x+5, y, - sequencer.time_axis.0, - sequencer.time_axis.0 + area.width, - 0 - ); - crate::device::sequencer::horizontal::keys( - buf, Rect { x, y: y + 1, width, height }, - sequencer.note_axis.1 - )?; - if let Some(id) = state.phrase_id() { - if let Some(phrase) = sequencer.phrases.get(id) { - crate::device::sequencer::horizontal::lanes( - buf, x, y + 1, - &phrase, - sequencer.timebase.ppq() as u32, - sequencer.time_zoom as u32, - sequencer.time_axis.0 as u32, - sequencer.time_axis.0 as u32 + area.width as u32, - sequencer.note_axis.0 as u32, - sequencer.note_axis.1 as u32, - ); + { + use crate::device::sequencer::horizontal::*; + timer(buf, x+5, y, sequencer.time_start, sequencer.time_start + area.width as usize, 0); + keys(buf, Rect { x, y: y + 1, width, height }, sequencer.note_start)?; + if let Some(Some(phrase)) = state.phrase_id().map(|id|sequencer.phrases.get(id)) { + let ppq = sequencer.timebase.ppq() as u32; + let zoom = sequencer.time_zoom as u32; + let t0 = sequencer.time_start as u32; + let t1 = t0 + area.width as u32; + let n0 = sequencer.note_start as u32; + let n1 = n0 + area.height as u32; + lanes(buf, x, y + 1, &phrase, ppq, zoom, t0, t1, n0, n1); } + let cursor_style = match view { + LauncherView::Sequencer => Style::default().green().not_dim(), + _ => Style::default().green().dim(), + }; + cursor(buf, x, y + 1, cursor_style, sequencer.time_cursor, sequencer.note_cursor); } - let cursor_style = match view { - LauncherView::Sequencer => Style::default().green().not_dim(), - _ => Style::default().green().dim(), - }; - crate::device::sequencer::horizontal::cursor(buf, x, y + 1, cursor_style, - sequencer.time_cursor, - sequencer.note_cursor - ); Ok(area) } fn draw_section_chains (state: &Launcher, buf: &mut Buffer, area: Rect) -> Usually { diff --git a/src/device/sequencer/handle.rs b/src/device/sequencer/handle.rs index 0e2f67b0..fce09111 100644 --- a/src/device/sequencer/handle.rs +++ b/src/device/sequencer/handle.rs @@ -50,10 +50,10 @@ fn note_add (s: &mut Sequencer) -> Usually { if s.sequence.is_none() { return Ok(false) } - let step = (s.time_axis.0 + s.time_cursor) as u32; + let step = (s.time_start + s.time_cursor) as u32; let start = (step as usize * s.timebase.ppq() / s.time_zoom) as u32; let end = ((step + 1) as usize * s.timebase.ppq() / s.time_zoom) as u32; - let key = u7::from_int_lossy((s.note_cursor + s.note_axis.0) as u8); + let key = u7::from_int_lossy((s.note_cursor + s.note_start) as u8); let note_on = MidiMessage::NoteOn { key, vel: 100.into() }; let note_off = MidiMessage::NoteOff { key, vel: 100.into() }; let sequence = &mut s.phrases[s.sequence.unwrap()].notes; @@ -73,27 +73,23 @@ fn note_del (_: &mut Sequencer) -> Usually { Ok(true) } fn time_cursor_inc (s: &mut Sequencer) -> Usually { - let time = s.time_axis.1 - s.time_axis.0; - s.time_cursor = ((time + s.time_cursor) + 1) % time; + s.time_cursor = s.time_cursor + 1; Ok(true) } fn time_cursor_dec (s: &mut Sequencer) -> Usually { - let time = s.time_axis.1 - s.time_axis.0; - s.time_cursor = ((time + s.time_cursor) - 1) % time; + s.time_cursor = s.time_cursor.saturating_sub(1); Ok(true) } fn note_cursor_inc (s: &mut Sequencer) -> Usually { - let note = s.note_axis.1 - s.note_axis.0; - s.note_cursor = ((note + s.note_cursor) + 1) % note; + s.note_cursor = s.note_cursor + 1; Ok(true) } fn note_cursor_dec (s: &mut Sequencer) -> Usually { - let note = s.note_axis.1 - s.note_axis.0; - s.note_cursor = ((note + s.note_cursor) - 1) % note; + s.note_cursor = s.note_cursor.saturating_sub(1); Ok(true) } fn cursor_up (s: &mut Sequencer) -> Usually { - match s.mode { + match s.view { SequencerView::Vertical => time_cursor_dec(s), SequencerView::Horizontal => note_cursor_dec(s), _ => Ok(false) @@ -101,7 +97,7 @@ fn cursor_up (s: &mut Sequencer) -> Usually { Ok(true) } fn cursor_down (s: &mut Sequencer) -> Usually { - match s.mode { + match s.view { SequencerView::Vertical => time_cursor_inc(s), SequencerView::Horizontal => note_cursor_inc(s), _ => Ok(false) @@ -109,7 +105,7 @@ fn cursor_down (s: &mut Sequencer) -> Usually { Ok(true) } fn cursor_left (s: &mut Sequencer) -> Usually { - match s.mode { + match s.view { SequencerView::Vertical => note_cursor_dec(s), SequencerView::Horizontal => time_cursor_dec(s), _ => Ok(false) @@ -117,7 +113,7 @@ fn cursor_left (s: &mut Sequencer) -> Usually { Ok(true) } fn cursor_right (s: &mut Sequencer) -> Usually { - match s.mode { + match s.view { SequencerView::Vertical => note_cursor_inc(s), SequencerView::Horizontal => time_cursor_inc(s), _ => Ok(false) @@ -133,7 +129,7 @@ fn cursor_duration_dec (_: &mut Sequencer) -> Usually { Ok(true) } fn mode_next (s: &mut Sequencer) -> Usually { - s.mode = s.mode.next(); + s.view = s.view.next(); Ok(true) } impl SequencerView { diff --git a/src/device/sequencer/horizontal.rs b/src/device/sequencer/horizontal.rs index c0e46b8f..67ec9fd0 100644 --- a/src/device/sequencer/horizontal.rs +++ b/src/device/sequencer/horizontal.rs @@ -5,40 +5,44 @@ pub fn draw ( s: &Sequencer, buf: &mut Buffer, mut area: Rect, - beat: usize ) -> Usually { area.x = area.x + 13; - let Rect { x, y, width, .. } = area; - keys(buf, area, s.note_axis.1)?; - timer(buf, x+6, y-1, s.time_axis.0, s.time_axis.1, beat as u16); - let height = 32.max(s.note_axis.1 - s.note_axis.0) / 2; + let Rect { x, y, width, height } = area; + keys(buf, area, s.note_start)?; + timer(buf, x+6, y-1, s.time_start, s.time_start + area.width as usize, 0); if let Some(phrase) = s.phrase() { lanes(buf, x, y, phrase, s.timebase.ppq() as u32, - s.time_zoom as u32, - s.time_axis.0 as u32, - s.time_axis.1 as u32, - s.note_axis.0 as u32, - s.note_axis.1 as u32, + s.time_zoom as u32, + s.time_start as u32, + s.time_start as u32 + area.width as u32, + s.note_start as u32, + s.note_start as u32 + area.height as u32, ); } - cursor(buf, x, y, Style::default().green().not_dim(), + cursor( + buf, + x, + y, + Style::default().green().not_dim(), s.time_cursor, s.note_cursor ); footer(s, buf, x, y, width, height); - Ok(Rect { - x: x - 13, - y: y, - width: s.time_axis.1 - s.time_axis.0 + 19, - height: height + 3 - }) + Ok(Rect { x: x - 13, y, width, height }) } -pub fn timer (buf: &mut Buffer, x: u16, y: u16, time0: u16, time1: u16, now: u16) { +pub fn timer ( + buf: &mut Buffer, + x: u16, + y: u16, + time0: usize, + time1: usize, + now: usize +) { for step in time0..time1 { - buf.set_string(x + step, y, &"-", if step == now { + buf.set_string(x + step as u16, y, &"-", if step == now { Style::default().yellow().bold().not_dim() } else { Style::default() @@ -46,18 +50,21 @@ pub fn timer (buf: &mut Buffer, x: u16, y: u16, time0: u16, time1: u16, now: u16 } } -pub fn keys (buf: &mut Buffer, area: Rect, note1: u16) -> Usually { +pub fn keys ( + buf: &mut Buffer, area: Rect, note_start: usize +) -> Usually { let bw = Style::default().dim(); let Rect { x, y, width, height } = area; let h = height.saturating_sub(2); for i in 0..h { let y = y + i; - buf.set_string(x + 1, y, KEYS_VERTICAL[(i % 6) as usize], bw); - buf.set_string(x + 2, y, "█", bw); - buf.set_string(x + 5, y, &"·".repeat(width.saturating_sub(6) as usize), bw.black()); + let key = KEYS_VERTICAL[(i % 6) as usize]; + key.blit(buf, x + 1, y, Some(bw)); + "█".blit(buf, x + 2, y, Some(bw)); + "·".repeat(width.saturating_sub(6) as usize).blit(buf, x + 5, y, Some(bw.black())); //buf.set_string(x + 3, y, &format!("{i}"), Style::default()); if i % 6 == 0 { - let octave = format!("C{}", ((note1 - i) / 6) as i8 - 4); + let octave = format!("C{}", ((note_start - i as usize) / 6) as i8 - 4); buf.set_string(x + 3, y, &octave, Style::default()); } } @@ -105,13 +112,11 @@ pub fn lanes ( } } -pub fn cursor (buf: &mut Buffer, x: u16, y: u16, style: Style, time_cursor: u16, note_cursor: u16) { - buf.set_string( - x + 5 + time_cursor, - y + note_cursor / 2, - if note_cursor % 2 == 0 { "▀" } else { "▄" }, - style - ); +pub fn cursor (buf: &mut Buffer, x: u16, y: u16, style: Style, time: usize, note: usize) { + let x = x + 5 + time as u16; + let y = y + note as u16 / 2; + let c = if note % 2 == 0 { "▀" } else { "▄" }; + c.blit(buf, x, y, Some(style)); } pub fn footer (s: &Sequencer, buf: &mut Buffer, mut x: u16, y: u16, width: u16, height: u16) { @@ -125,13 +130,13 @@ pub fn footer (s: &Sequencer, buf: &mut Buffer, mut x: u16, y: u16, width: u16, ["S", &format!("ync"), &format!("<4/4>")], ["Q", &format!("uant"), &format!("<1/{}>", 4 * s.time_zoom)], ["N", &format!("ote"), &format!("{} ({}-{})", - s.note_axis.0 + s.note_cursor, - s.note_axis.0, - s.note_axis.1 - 1)], + s.note_start + s.note_cursor, + s.note_start, + "X")], ["T", &format!("ime"), &format!("{} ({}-{})", - s.time_axis.0 + s.time_cursor + 1, - s.time_axis.0 + 1, - s.time_axis.1)], + s.time_start + s.time_cursor + 1, + s.time_start + 1, + "X")], ].iter().enumerate() { buf.set_string(x, y + height + 1, letter, Style::default().bold().yellow().dim()); x = x + 1; diff --git a/src/device/sequencer/mod.rs b/src/device/sequencer/mod.rs index 8985e4bb..1066f66d 100644 --- a/src/device/sequencer/mod.rs +++ b/src/device/sequencer/mod.rs @@ -34,17 +34,17 @@ pub struct Sequencer { /// Don't delete when recording. pub overdub: bool, /// Display mode - pub mode: SequencerView, + pub view: SequencerView, /// Range of notes to display - pub note_axis: (u16, u16), + pub note_start: usize, /// Position of cursor within note range - pub note_cursor: u16, + pub note_cursor: usize, /// PPM per display unit pub time_zoom: usize, /// Range of time steps to display - pub time_axis: (u16, u16), + pub time_start: usize, /// Position of cursor within time range - pub time_cursor: u16, + pub time_cursor: usize, } #[derive(Debug, Clone)] @@ -65,22 +65,22 @@ impl Sequencer { timebase: timebase.clone(), sequence: Some(0), - phrases: phrases.unwrap_or(vec![ + phrases: phrases.unwrap_or_else(||vec![ Phrase::new("Phrase0", 4*timebase.ppq() as u32, None) ]), - notes_on: vec![false;128], + transport, playing: TransportState::Starting, monitoring: true, recording: true, overdub: true, - transport, - mode: SequencerView::Horizontal, - note_axis: (36, 68), + view: SequencerView::Horizontal, + notes_on: vec![false;128], + note_start: 36, note_cursor: 0, time_zoom: 24, - time_axis: (0, 64), + time_start: 0, time_cursor: 0, }).activate(client) } @@ -89,76 +89,51 @@ impl Sequencer { self.phrases.get(self.sequence?) } } - impl PortList for Sequencer { - fn midi_ins (&self) -> Usually> { - Ok(vec![self.midi_in.name()?]) - } - fn midi_outs (&self) -> Usually> { - Ok(vec![self.midi_out.name()?]) - } + fn midi_ins (&self) -> Usually> { Ok(vec![self.midi_in.name()?]) } + fn midi_outs (&self) -> Usually> { Ok(vec![self.midi_out.name()?]) } } - fn render (s: &Sequencer, buf: &mut Buffer, area: Rect) -> Usually { - let Rect { x, y, width, .. } = area; - let (time0, time1) = s.time_axis; - let (note0, note1) = s.note_axis; + let Rect { x, y, width, height } = area; let pos = s.transport.query().unwrap().pos; let frame = pos.frame(); let usecs = s.timebase.frame_to_usec(frame as usize); let ustep = s.timebase.usec_per_step(s.time_zoom as usize); let steps = usecs / ustep; let header = draw_header(s, buf, area, steps)?; - let piano = match s.mode { + let piano = match s.view { SequencerView::Tiny => Rect { x, y, width, height: 0 }, SequencerView::Compact => Rect { x, y, width, height: 0 }, - SequencerView::Vertical => - self::vertical::draw(s, buf, Rect { - x, - y: y + header.height, - width: 3 + note1 - note0, - height: 3 + time1 - time0, - }, steps)?, - SequencerView::Horizontal => - self::horizontal::draw(s, buf, Rect { - x, - y: y + header.height, - width: area.width.max(3 + time1 - time0), - height: 3 + note1 - note0, - }, steps)?, + SequencerView::Vertical => self::vertical::draw(s, buf, Rect { + x, y: y + header.height, width, height, + }, steps)?, + SequencerView::Horizontal => self::horizontal::draw(s, buf, Rect { + x, y: y + header.height, width, height, + })?, }; Ok(draw_box(buf, Rect { - x, - y, + x, y, width: header.width.max(piano.width), height: header.height + piano.height })) } - -pub fn draw_header (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) -> Usually { - let Rect { x, y, .. } = area; - //let rep = beat / s.steps; - //let step = beat % s.steps; - //let reps = s.steps / s.time_zoom; - //let steps = s.steps % s.time_zoom; - //draw_timer(buf, x + width - 2, y + 1, &format!("{rep}.{step:02} / {reps}.{steps}")); +pub fn draw_header (s: &Sequencer, buf: &mut Buffer, area: Rect, _: usize) -> Usually { + let Rect { x, y, width, .. } = area; let style = Style::default().gray(); crate::device::transport::draw_play_stop(buf, x + 2, y + 1, &s.playing); - let separator = format!("├{}┤", "-".repeat((area.width - 2).into())); + let separator = format!("├{}┤", "-".repeat((width - 2).into())); separator.blit(buf, x, y + 2, Some(style.dim())); crate::device::transport::draw_rec(buf, x + 13, y + 1, s.recording); crate::device::transport::draw_dub(buf, x + 20, y + 1, s.overdub); crate::device::transport::draw_mon(buf, x + 27, y + 1, s.monitoring); let _ = draw_clips(s, buf, area)?; - Ok(Rect { x, y, width: area.width, height: 3 }) + Ok(Rect { x, y, width, height: 3 }) } -pub fn draw_timer ( - buf: &mut Buffer, x: u16, y: u16, timer: &str -) { +pub fn draw_timer (buf: &mut Buffer, x: u16, y: u16, timer: &str) { let style = Some(Style::default().gray().bold().not_dim()); timer.blit(buf, x - timer.len() as u16, y, style); } -fn draw_clips (s: &Sequencer, buf: &mut Buffer, area: Rect) -> Usually { +pub fn draw_clips (s: &Sequencer, buf: &mut Buffer, area: Rect) -> Usually { let Rect { x, y, .. } = area; let style = Style::default().gray(); for (i, sequence) in s.phrases.iter().enumerate() { diff --git a/src/device/sequencer/vertical.rs b/src/device/sequencer/vertical.rs index 67ed884c..4af552ff 100644 --- a/src/device/sequencer/vertical.rs +++ b/src/device/sequencer/vertical.rs @@ -8,13 +8,10 @@ pub fn draw ( beat: usize ) -> Usually { area.x = area.x + 13; - let Rect { x, y, .. } = area; keys(s, buf, area, beat); steps(s, buf, area, beat); - let height = (s.time_axis.1-s.time_axis.0)/2; - footer(s, buf, x, y, height); - playhead(s, buf, x, y); - Ok(Rect { x, y, width: area.width, height: height + 3 }) + playhead(s, buf, area.x, area.y); + Ok(area) } pub fn steps (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) { @@ -26,16 +23,14 @@ pub fn steps (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) { let bw = bg.dim(); let wh = bg.white(); let Rect { x, y, .. } = area; - let (time0, time1) = s.time_axis; - let (note0, note1) = s.note_axis; - for step in time0..time1 { - let y = y - time0 + step / 2; + for step in s.time_start..s.time_start+area.height as usize { + let y = y - (s.time_start + step / 2) as u16; let step = step as usize; - //buf.set_string(x + 5, y, &" ".repeat(32.max(note1-note0)as usize), bg); + //buf.set_string(x + 5, y, &" ".repeat(32.max(note1-s.note_start)as usize), bg); if step % s.time_zoom == 0 { buf.set_string(x + 2, y, &format!("{:2} ", step + 1), Style::default()); } - for k in note0..note1 { + for k in s.note_start..s.note_start+area.width as usize { let key = ::midly::num::u7::from_int_lossy(k as u8); if step % 2 == 0 { let (a, b, c) = ( @@ -52,12 +47,12 @@ pub fn steps (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) { (false, true) => ("▄", wh), (false, false) => ("·", bw), }; - buf.set_string(x + 5 + k - note0, y, character, style); + character.blit(buf, x + (5 + k - s.note_start) as u16, y, Some(style)); } } if beat == step as usize { buf.set_string(x + 4, y, if beat % 2 == 0 { "▀" } else { "▄" }, Style::default().yellow()); - for key in note0..note1 { + for key in s.note_start..s.note_start+area.width as usize { let _color = if s.notes_on[key as usize] { Style::default().red() } else { @@ -68,34 +63,18 @@ pub fn steps (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) { } } -pub fn footer (s: &Sequencer, buf: &mut Buffer, x: u16, y: u16, height: u16) { - buf.set_string(x + 2, y + height + 1, format!( - "Q 1/{} | N {} ({}-{}) | T {} ({}-{})", - 4 * s.time_zoom, - s.note_axis.0 + s.note_cursor, - s.note_axis.0, - s.note_axis.1 - 1, - s.time_axis.0 + s.time_cursor + 1, - s.time_axis.0 + 1, - s.time_axis.1, - ), Style::default().dim()); -} - pub fn playhead (s: &Sequencer, buf: &mut Buffer, x: u16, y: u16) { - buf.set_string( - x + 5 + s.note_cursor, - y + s.time_cursor / 2, - if s.time_cursor % 2 == 0 { "▀" } else { "▄" }, - Style::default() - ); + let x = x + 5 + s.note_cursor as u16; + let y = y + s.time_cursor as u16 / 2; + let c = if s.time_cursor % 2 == 0 { "▀" } else { "▄" }; + buf.set_string(x, y, c, Style::default()); } pub fn keys (s: &Sequencer, buf: &mut Buffer, area: Rect, beat: usize) { let ppq = s.timebase.ppq() as u32; let Rect { x, y, .. } = area; - let (note0, note1) = s.note_axis; - for key in note0..note1 { - let x = x + 5 + key - note0; + for key in s.note_start..s.note_start+area.width as usize { + let x = x + (5 + key - s.note_start) as u16; if key % 12 == 0 { let octave = format!("C{}", (key / 12) as i8 - 4); buf.set_string(x, y, &octave, Style::default());