mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
sequencer: merge Sequencer and SequencerTrack
This commit is contained in:
parent
1d3d3875fe
commit
6206a43b4a
8 changed files with 171 additions and 190 deletions
|
|
@ -11,13 +11,12 @@ pub struct Arranger {
|
||||||
/// Currently selected element.
|
/// Currently selected element.
|
||||||
pub selected: ArrangerFocus,
|
pub selected: ArrangerFocus,
|
||||||
/// Collection of tracks.
|
/// Collection of tracks.
|
||||||
pub tracks: Vec<SequencerTrack>,
|
pub tracks: Vec<Sequencer>,
|
||||||
/// Collection of scenes.
|
/// Collection of scenes.
|
||||||
pub scenes: Vec<Scene>,
|
pub scenes: Vec<Scene>,
|
||||||
pub focused: bool,
|
pub focused: bool,
|
||||||
pub entered: bool,
|
pub entered: bool,
|
||||||
pub fixed_height: bool,
|
pub fixed_height: bool,
|
||||||
pub sequencer: Sequencer,
|
|
||||||
pub transport: Option<Arc<RwLock<TransportToolbar>>>,
|
pub transport: Option<Arc<RwLock<TransportToolbar>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +31,6 @@ impl Arranger {
|
||||||
entered: true,
|
entered: true,
|
||||||
focused: true,
|
focused: true,
|
||||||
fixed_height: false,
|
fixed_height: false,
|
||||||
sequencer: Sequencer::new(),
|
|
||||||
transport: None
|
transport: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,10 @@ pub const KEYMAP_ARRANGER: &'static [KeyBinding<Arranger>] = keymap!(Arranger {
|
||||||
}],
|
}],
|
||||||
[Char('.'), NONE, "arranger_increment", "set next clip at cursor", |arranger: &mut Arranger| {
|
[Char('.'), NONE, "arranger_increment", "set next clip at cursor", |arranger: &mut Arranger| {
|
||||||
arranger.phrase_next();
|
arranger.phrase_next();
|
||||||
arranger.sequencer.phrase = arranger.phrase().map(Clone::clone);
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Char(','), NONE, "arranger_decrement", "set previous clip at cursor", |arranger: &mut Arranger| {
|
[Char(','), NONE, "arranger_decrement", "set previous clip at cursor", |arranger: &mut Arranger| {
|
||||||
arranger.phrase_prev();
|
arranger.phrase_prev();
|
||||||
arranger.sequencer.phrase = arranger.phrase().map(Clone::clone);
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}],
|
}],
|
||||||
[Enter, NONE, "arranger_activate", "activate item at cursor", |arranger: &mut Arranger| {
|
[Enter, NONE, "arranger_activate", "activate item at cursor", |arranger: &mut Arranger| {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ use super::Arranger;
|
||||||
|
|
||||||
/// Track management methods
|
/// Track management methods
|
||||||
impl Arranger {
|
impl Arranger {
|
||||||
pub fn track (&self) -> Option<&SequencerTrack> {
|
pub fn track (&self) -> Option<&Sequencer> {
|
||||||
self.selected.track().map(|t|self.tracks.get(t)).flatten()
|
self.selected.track().map(|t|self.tracks.get(t)).flatten()
|
||||||
}
|
}
|
||||||
pub fn track_mut (&mut self) -> Option<&mut SequencerTrack> {
|
pub fn track_mut (&mut self) -> Option<&mut Sequencer> {
|
||||||
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
|
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
|
||||||
}
|
}
|
||||||
pub fn track_next (&mut self) {
|
pub fn track_next (&mut self) {
|
||||||
|
|
@ -16,11 +16,11 @@ impl Arranger {
|
||||||
pub fn track_prev (&mut self) {
|
pub fn track_prev (&mut self) {
|
||||||
self.selected.track_prev()
|
self.selected.track_prev()
|
||||||
}
|
}
|
||||||
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut SequencerTrack> {
|
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut Sequencer> {
|
||||||
self.tracks.push(name.map_or_else(
|
self.tracks.push(name.map_or_else(
|
||||||
|| SequencerTrack::new(&self.track_default_name()),
|
|| Sequencer::new(&self.track_default_name()),
|
||||||
|name| SequencerTrack::new(name),
|
|name| Sequencer::new(name),
|
||||||
)?);
|
));
|
||||||
let index = self.tracks.len() - 1;
|
let index = self.tracks.len() - 1;
|
||||||
Ok(&mut self.tracks[index])
|
Ok(&mut self.tracks[index])
|
||||||
}
|
}
|
||||||
|
|
@ -32,13 +32,13 @@ impl Arranger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn track_name_max_len (tracks: &[SequencerTrack]) -> usize {
|
pub fn track_name_max_len (tracks: &[Sequencer]) -> usize {
|
||||||
tracks.iter()
|
tracks.iter()
|
||||||
.map(|s|s.name.len())
|
.map(|s|s.name.len())
|
||||||
.fold(0, usize::max)
|
.fold(0, usize::max)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn track_clip_name_lengths (tracks: &[SequencerTrack]) -> Vec<(usize, usize)> {
|
pub fn track_clip_name_lengths (tracks: &[Sequencer]) -> Vec<(usize, usize)> {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{
|
let mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{
|
||||||
let len = 2 + track.phrases
|
let len = 2 + track.phrases
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ submod! {
|
||||||
sequencer_cli
|
sequencer_cli
|
||||||
sequencer_handle
|
sequencer_handle
|
||||||
sequencer_render
|
sequencer_render
|
||||||
sequencer_track
|
|
||||||
arranger
|
arranger
|
||||||
arranger_cli
|
arranger_cli
|
||||||
arranger_focus
|
arranger_focus
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// A collection of phrases to play on each track.
|
/// A collection of phrases to play on each track.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub clips: Vec<Option<usize>>,
|
pub clips: Vec<Option<usize>>,
|
||||||
|
|
@ -13,14 +14,14 @@ impl Scene {
|
||||||
Self { name, clips, }
|
Self { name, clips, }
|
||||||
}
|
}
|
||||||
/// Returns the pulse length of the longest phrase in the scene
|
/// Returns the pulse length of the longest phrase in the scene
|
||||||
pub fn pulses (&self, tracks: &[SequencerTrack]) -> usize {
|
pub fn pulses (&self, tracks: &[Sequencer]) -> usize {
|
||||||
self.clips.iter().enumerate()
|
self.clips.iter().enumerate()
|
||||||
.filter_map(|(i, c)|c.map(|c|tracks[i].phrases.get(c)))
|
.filter_map(|(i, c)|c.map(|c|tracks[i].phrases.get(c)))
|
||||||
.filter_map(|p|p)
|
.filter_map(|p|p)
|
||||||
.fold(0, |a, p|a.max(p.read().unwrap().length))
|
.fold(0, |a, p|a.max(p.read().unwrap().length))
|
||||||
}
|
}
|
||||||
/// Returns true if all phrases in the scene are currently playing
|
/// Returns true if all phrases in the scene are currently playing
|
||||||
pub fn is_playing (&self, tracks: &[SequencerTrack]) -> bool {
|
pub fn is_playing (&self, tracks: &[Sequencer]) -> bool {
|
||||||
self.clips.iter().enumerate()
|
self.clips.iter().enumerate()
|
||||||
.all(|(track_index, phrase_index)|match phrase_index {
|
.all(|(track_index, phrase_index)|match phrase_index {
|
||||||
Some(i) => tracks[track_index].sequence == Some(*i),
|
Some(i) => tracks[track_index].sequence == Some(*i),
|
||||||
|
|
@ -35,7 +36,7 @@ pub fn scene_name_max_len (scenes: &[Scene]) -> usize {
|
||||||
.fold(0, usize::max)
|
.fold(0, usize::max)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scene_ppqs (tracks: &[SequencerTrack], scenes: &[Scene]) -> Vec<(usize, usize)> {
|
pub fn scene_ppqs (tracks: &[Sequencer], scenes: &[Scene]) -> Vec<(usize, usize)> {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut scenes: Vec<(usize, usize)> = scenes.iter().map(|scene|{
|
let mut scenes: Vec<(usize, usize)> = scenes.iter().map(|scene|{
|
||||||
let pulses = scene.pulses(tracks);
|
let pulses = scene.pulses(tracks);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use tek_core::Direction;
|
||||||
|
|
||||||
/// Phrase editor.
|
/// Phrase editor.
|
||||||
pub struct Sequencer {
|
pub struct Sequencer {
|
||||||
|
|
@ -20,12 +21,42 @@ pub struct Sequencer {
|
||||||
pub ppq: usize,
|
pub ppq: usize,
|
||||||
pub note_axis: FixedAxis<usize>,
|
pub note_axis: FixedAxis<usize>,
|
||||||
pub time_axis: ScaledAxis<usize>,
|
pub time_axis: ScaledAxis<usize>,
|
||||||
|
/// Play input through output.
|
||||||
|
pub monitoring: bool,
|
||||||
|
/// Write input to sequence.
|
||||||
|
pub recording: bool,
|
||||||
|
/// Overdub input to sequence.
|
||||||
|
pub overdub: bool,
|
||||||
|
/// Map: tick -> MIDI events at tick
|
||||||
|
pub phrases: Vec<Arc<RwLock<Phrase>>>,
|
||||||
|
/// Phrase selector
|
||||||
|
pub sequence: Option<usize>,
|
||||||
|
/// Output from current sequence.
|
||||||
|
pub midi_out: Option<Port<MidiOut>>,
|
||||||
|
/// MIDI output buffer
|
||||||
|
midi_out_buf: Vec<Vec<Vec<u8>>>,
|
||||||
|
/// Send all notes off
|
||||||
|
pub reset: bool, // TODO?: after Some(nframes)
|
||||||
|
/// Highlight keys on piano roll.
|
||||||
|
pub notes_in: [bool;128],
|
||||||
|
/// Highlight keys on piano roll.
|
||||||
|
pub notes_out: [bool;128],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sequencer {
|
impl Sequencer {
|
||||||
pub fn new () -> Self {
|
pub fn new (name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: "".into(),
|
name: name.into(),
|
||||||
|
monitoring: false,
|
||||||
|
recording: false,
|
||||||
|
overdub: true,
|
||||||
|
phrases: vec![],
|
||||||
|
sequence: None,
|
||||||
|
midi_out: None,
|
||||||
|
midi_out_buf: vec![Vec::with_capacity(16);16384],
|
||||||
|
reset: true,
|
||||||
|
notes_in: [false;128],
|
||||||
|
notes_out: [false;128],
|
||||||
buffer: Default::default(),
|
buffer: Default::default(),
|
||||||
keys: keys_vert(),
|
keys: keys_vert(),
|
||||||
entered: false,
|
entered: false,
|
||||||
|
|
@ -48,4 +79,128 @@ impl Sequencer {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn toggle_monitor (&mut self) {
|
||||||
|
self.monitoring = !self.monitoring;
|
||||||
|
}
|
||||||
|
pub fn toggle_record (&mut self) {
|
||||||
|
self.recording = !self.recording;
|
||||||
|
}
|
||||||
|
pub fn toggle_overdub (&mut self) {
|
||||||
|
self.overdub = !self.overdub;
|
||||||
|
}
|
||||||
|
pub fn process (
|
||||||
|
&mut self,
|
||||||
|
input: Option<MidiIter>,
|
||||||
|
timebase: &Arc<Timebase>,
|
||||||
|
playing: Option<TransportState>,
|
||||||
|
started: Option<(usize, usize)>,
|
||||||
|
quant: usize,
|
||||||
|
reset: bool,
|
||||||
|
scope: &ProcessScope,
|
||||||
|
(frame0, frames): (usize, usize),
|
||||||
|
(_usec0, _usecs): (usize, usize),
|
||||||
|
period: f64,
|
||||||
|
) {
|
||||||
|
if self.midi_out.is_some() {
|
||||||
|
// Clear the section of the output buffer that we will be using
|
||||||
|
for frame in &mut self.midi_out_buf[0..frames] {
|
||||||
|
frame.clear();
|
||||||
|
}
|
||||||
|
// Emit "all notes off" at start of buffer if requested
|
||||||
|
if self.reset {
|
||||||
|
all_notes_off(&mut self.midi_out_buf);
|
||||||
|
self.reset = false;
|
||||||
|
} else if reset {
|
||||||
|
all_notes_off(&mut self.midi_out_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (
|
||||||
|
Some(TransportState::Rolling), Some((start_frame, _)), Some(phrase)
|
||||||
|
) = (
|
||||||
|
playing, started, self.sequence.and_then(|id|self.phrases.get_mut(id))
|
||||||
|
) {
|
||||||
|
phrase.read().map(|phrase|{
|
||||||
|
if self.midi_out.is_some() {
|
||||||
|
phrase.process_out(
|
||||||
|
&mut self.midi_out_buf,
|
||||||
|
&mut self.notes_out,
|
||||||
|
timebase,
|
||||||
|
(frame0.saturating_sub(start_frame), frames, period)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
let mut phrase = phrase.write().unwrap();
|
||||||
|
let length = phrase.length;
|
||||||
|
// Monitor and record input
|
||||||
|
if input.is_some() && (self.recording || self.monitoring) {
|
||||||
|
// For highlighting keys and note repeat
|
||||||
|
for (frame, event, bytes) in parse_midi_input(input.unwrap()) {
|
||||||
|
match event {
|
||||||
|
LiveEvent::Midi { message, .. } => {
|
||||||
|
if self.monitoring {
|
||||||
|
self.midi_out_buf[frame].push(bytes.to_vec())
|
||||||
|
}
|
||||||
|
if self.recording {
|
||||||
|
phrase.record_event({
|
||||||
|
let pulse = timebase.frame_to_pulse(
|
||||||
|
(frame0 + frame - start_frame) as f64
|
||||||
|
);
|
||||||
|
let quantized = (
|
||||||
|
pulse / quant as f64
|
||||||
|
).round() as usize * quant;
|
||||||
|
let looped = quantized % length;
|
||||||
|
looped
|
||||||
|
}, message);
|
||||||
|
}
|
||||||
|
match message {
|
||||||
|
MidiMessage::NoteOn { key, .. } => {
|
||||||
|
self.notes_in[key.as_int() as usize] = true;
|
||||||
|
}
|
||||||
|
MidiMessage::NoteOff { key, .. } => {
|
||||||
|
self.notes_in[key.as_int() as usize] = false;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if input.is_some() && self.midi_out.is_some() && self.monitoring {
|
||||||
|
for (frame, event, bytes) in parse_midi_input(input.unwrap()) {
|
||||||
|
self.process_monitor_event(frame, &event, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(out) = &mut self.midi_out {
|
||||||
|
write_midi_output(&mut out.writer(scope), &self.midi_out_buf, frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn process_monitor_event (&mut self, frame: usize, event: &LiveEvent, bytes: &[u8]) {
|
||||||
|
match event {
|
||||||
|
LiveEvent::Midi { message, .. } => {
|
||||||
|
self.write_to_output_buffer(frame, bytes);
|
||||||
|
self.process_monitor_message(&message);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] fn write_to_output_buffer (&mut self, frame: usize, bytes: &[u8]) {
|
||||||
|
self.midi_out_buf[frame].push(bytes.to_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn process_monitor_message (&mut self, message: &MidiMessage) {
|
||||||
|
match message {
|
||||||
|
MidiMessage::NoteOn { key, .. } => {
|
||||||
|
self.notes_in[key.as_int() as usize] = true;
|
||||||
|
}
|
||||||
|
MidiMessage::NoteOff { key, .. } => {
|
||||||
|
self.notes_in[key.as_int() as usize] = false;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub struct SequencerCli {
|
||||||
impl Sequencer {
|
impl Sequencer {
|
||||||
pub fn from_args () -> Self {
|
pub fn from_args () -> Self {
|
||||||
let args = SequencerCli::parse();
|
let args = SequencerCli::parse();
|
||||||
let mut seq = Self::new();
|
let mut seq = Self::new("");
|
||||||
if let Some(name) = args.name {
|
if let Some(name) = args.name {
|
||||||
seq.name = name.clone();
|
seq.name = name.clone();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
use tek_core::Direction;
|
|
||||||
|
|
||||||
/// A sequencer track.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SequencerTrack {
|
|
||||||
pub name: String,
|
|
||||||
/// Play input through output.
|
|
||||||
pub monitoring: bool,
|
|
||||||
/// Write input to sequence.
|
|
||||||
pub recording: bool,
|
|
||||||
/// Overdub input to sequence.
|
|
||||||
pub overdub: bool,
|
|
||||||
/// Map: tick -> MIDI events at tick
|
|
||||||
pub phrases: Vec<Arc<RwLock<Phrase>>>,
|
|
||||||
/// Phrase selector
|
|
||||||
pub sequence: Option<usize>,
|
|
||||||
/// Output from current sequence.
|
|
||||||
pub midi_out: Option<Port<MidiOut>>,
|
|
||||||
/// MIDI output buffer
|
|
||||||
midi_out_buf: Vec<Vec<Vec<u8>>>,
|
|
||||||
/// Send all notes off
|
|
||||||
pub reset: bool, // TODO?: after Some(nframes)
|
|
||||||
/// Highlight keys on piano roll.
|
|
||||||
pub notes_in: [bool;128],
|
|
||||||
/// Highlight keys on piano roll.
|
|
||||||
pub notes_out: [bool;128],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SequencerTrack {
|
|
||||||
pub fn new (name: &str) -> Usually<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
monitoring: false,
|
|
||||||
recording: false,
|
|
||||||
overdub: true,
|
|
||||||
phrases: vec![],
|
|
||||||
sequence: None,
|
|
||||||
midi_out: None,
|
|
||||||
midi_out_buf: vec![Vec::with_capacity(16);16384],
|
|
||||||
reset: true,
|
|
||||||
notes_in: [false;128],
|
|
||||||
notes_out: [false;128],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn toggle_monitor (&mut self) {
|
|
||||||
self.monitoring = !self.monitoring;
|
|
||||||
}
|
|
||||||
pub fn toggle_record (&mut self) {
|
|
||||||
self.recording = !self.recording;
|
|
||||||
}
|
|
||||||
pub fn toggle_overdub (&mut self) {
|
|
||||||
self.overdub = !self.overdub;
|
|
||||||
}
|
|
||||||
pub fn process (
|
|
||||||
&mut self,
|
|
||||||
input: Option<MidiIter>,
|
|
||||||
timebase: &Arc<Timebase>,
|
|
||||||
playing: Option<TransportState>,
|
|
||||||
started: Option<(usize, usize)>,
|
|
||||||
quant: usize,
|
|
||||||
reset: bool,
|
|
||||||
scope: &ProcessScope,
|
|
||||||
(frame0, frames): (usize, usize),
|
|
||||||
(_usec0, _usecs): (usize, usize),
|
|
||||||
period: f64,
|
|
||||||
) {
|
|
||||||
if self.midi_out.is_some() {
|
|
||||||
// Clear the section of the output buffer that we will be using
|
|
||||||
for frame in &mut self.midi_out_buf[0..frames] {
|
|
||||||
frame.clear();
|
|
||||||
}
|
|
||||||
// Emit "all notes off" at start of buffer if requested
|
|
||||||
if self.reset {
|
|
||||||
all_notes_off(&mut self.midi_out_buf);
|
|
||||||
self.reset = false;
|
|
||||||
} else if reset {
|
|
||||||
all_notes_off(&mut self.midi_out_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let (
|
|
||||||
Some(TransportState::Rolling), Some((start_frame, _)), Some(phrase)
|
|
||||||
) = (
|
|
||||||
playing, started, self.sequence.and_then(|id|self.phrases.get_mut(id))
|
|
||||||
) {
|
|
||||||
phrase.read().map(|phrase|{
|
|
||||||
if self.midi_out.is_some() {
|
|
||||||
phrase.process_out(
|
|
||||||
&mut self.midi_out_buf,
|
|
||||||
&mut self.notes_out,
|
|
||||||
timebase,
|
|
||||||
(frame0.saturating_sub(start_frame), frames, period)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).unwrap();
|
|
||||||
let mut phrase = phrase.write().unwrap();
|
|
||||||
let length = phrase.length;
|
|
||||||
// Monitor and record input
|
|
||||||
if input.is_some() && (self.recording || self.monitoring) {
|
|
||||||
// For highlighting keys and note repeat
|
|
||||||
for (frame, event, bytes) in parse_midi_input(input.unwrap()) {
|
|
||||||
match event {
|
|
||||||
LiveEvent::Midi { message, .. } => {
|
|
||||||
if self.monitoring {
|
|
||||||
self.midi_out_buf[frame].push(bytes.to_vec())
|
|
||||||
}
|
|
||||||
if self.recording {
|
|
||||||
phrase.record_event({
|
|
||||||
let pulse = timebase.frame_to_pulse(
|
|
||||||
(frame0 + frame - start_frame) as f64
|
|
||||||
);
|
|
||||||
let quantized = (
|
|
||||||
pulse / quant as f64
|
|
||||||
).round() as usize * quant;
|
|
||||||
let looped = quantized % length;
|
|
||||||
looped
|
|
||||||
}, message);
|
|
||||||
}
|
|
||||||
match message {
|
|
||||||
MidiMessage::NoteOn { key, .. } => {
|
|
||||||
self.notes_in[key.as_int() as usize] = true;
|
|
||||||
}
|
|
||||||
MidiMessage::NoteOff { key, .. } => {
|
|
||||||
self.notes_in[key.as_int() as usize] = false;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if input.is_some() && self.midi_out.is_some() && self.monitoring {
|
|
||||||
for (frame, event, bytes) in parse_midi_input(input.unwrap()) {
|
|
||||||
self.process_monitor_event(frame, &event, bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(out) = &mut self.midi_out {
|
|
||||||
write_midi_output(&mut out.writer(scope), &self.midi_out_buf, frames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn process_monitor_event (&mut self, frame: usize, event: &LiveEvent, bytes: &[u8]) {
|
|
||||||
match event {
|
|
||||||
LiveEvent::Midi { message, .. } => {
|
|
||||||
self.write_to_output_buffer(frame, bytes);
|
|
||||||
self.process_monitor_message(&message);
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline] fn write_to_output_buffer (&mut self, frame: usize, bytes: &[u8]) {
|
|
||||||
self.midi_out_buf[frame].push(bytes.to_vec());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn process_monitor_message (&mut self, message: &MidiMessage) {
|
|
||||||
match message {
|
|
||||||
MidiMessage::NoteOn { key, .. } => {
|
|
||||||
self.notes_in[key.as_int() as usize] = true;
|
|
||||||
}
|
|
||||||
MidiMessage::NoteOff { key, .. } => {
|
|
||||||
self.notes_in[key.as_int() as usize] = false;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue