Skip to content

Commit

Permalink
auto-stop pending notes from previous events in scripted event iters …
Browse files Browse the repository at this point in the history
…and fixed event iters, to match the behaviour of cycle output
  • Loading branch information
emuell committed Jun 17, 2024
1 parent 2a81635 commit 17cdaa1
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 11 deletions.
63 changes: 59 additions & 4 deletions src/event/fixed.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::borrow::Cow;

use crate::{
event::{Event, EventIter, EventIterItem, NoteEvent, ParameterChangeEvent},
event::{new_note, Event, EventIter, EventIterItem, NoteEvent, ParameterChangeEvent},
BeatTimeBase, Note, PulseIterItem,
};

Expand All @@ -16,16 +16,71 @@ pub struct FixedEventIter {

impl FixedEventIter {
pub fn new(events: Vec<Event>) -> Self {
let mut events = events;
Self::normalize_events(&mut events);
let event_index = 0;
Self {
events,
event_index,
}
}

// Get a copy of the event that we're triggering
pub fn events(&self) -> Vec<Event> {
self.events.clone()
/// Access to the event that we're triggering
pub fn events(&self) -> &Vec<Event> {
&self.events
}

/// Add note-offs for all notes in the given event list
pub(crate) fn normalize_events(events: &mut Vec<Event>) {
let mut note_event_state = Vec::<Option<NoteEvent>>::new();
for event in &mut *events {
Self::normalize_event(event, &mut note_event_state);
}
if events.len() > 1 {
Self::normalize_event(events.first_mut().unwrap(), &mut note_event_state)
}
}

/// Add note-offs for all notes in the given event to stop pending notes from last runs.
/// This will only pad, resize the given event's note list with note-offs where necessary.
pub(crate) fn normalize_event(
event: &mut Event,
note_event_state: &mut Vec<Option<NoteEvent>>,
) {
if let Event::NoteEvents(note_events) = event {
if !note_events.iter().all(|n| n.is_none()) {
// auto-close previous note's note-ons, unless there is some explicit content
while note_events.len() < note_event_state.len() {
if note_event_state[note_events.len()]
.as_ref()
.is_some_and(|n| n.note.is_note_on())
{
note_events.push(new_note(Note::OFF));
} else {
note_events.push(None);
}
}
// update note state
if note_event_state.len() < note_events.len() {
note_event_state.resize(note_events.len(), None);
}
for (note_event_state, note_event) in
note_event_state.iter_mut().zip(note_events.iter())
{
if let Some(note_event) = note_event {
if note_event.note.is_note_on() {
*note_event_state = Some(note_event.clone());
} else {
*note_event_state = None;
}
}
}
}
// remove trailing none's from note state
while note_event_state.last().is_some_and(|n| n.is_none()) {
note_event_state.pop();
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/event/mutated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@ where
{
/// Upgrade a [`FixedEventIter`] to a [`MutatedEventIter`].
fn mutate(self, map: F) -> MutatedEventIter {
MutatedEventIter::new(self.events(), map)
MutatedEventIter::new(self.events().clone(), map)
}
}
19 changes: 13 additions & 6 deletions src/event/scripted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use mlua::prelude::*;

use crate::{
bindings::{note_events_from_value, LuaCallback, LuaTimeoutHook},
event::{fixed::FixedEventIter, NoteEvent},
BeatTimeBase, Event, EventIter, EventIterItem, PulseIterItem,
};

Expand All @@ -14,6 +15,7 @@ use crate::{
pub struct ScriptedEventIter {
timeout_hook: LuaTimeoutHook,
callback: LuaCallback,
note_event_state: Vec<Option<NoteEvent>>,
pulse_step: usize,
pulse_time_step: f64,
step: usize,
Expand All @@ -30,6 +32,7 @@ impl ScriptedEventIter {
timeout_hook.reset();
// initialize emitter context for the function
let mut callback = callback;
let note_event_state = Vec::new();
let pulse = PulseIterItem::default();
let pulse_step = 0;
let pulse_time_step = 0.0;
Expand All @@ -38,6 +41,7 @@ impl ScriptedEventIter {
Ok(Self {
timeout_hook,
callback,
note_event_state,
pulse_step,
pulse_time_step,
step,
Expand All @@ -54,7 +58,11 @@ impl ScriptedEventIter {
self.callback.set_context_step(self.step)?;
// invoke callback and evaluate the result
let events = note_events_from_value(&self.callback.call()?, None)?;
Ok(Some(vec![EventIterItem::new(Event::NoteEvents(events))]))
// normalize event
let mut event = Event::NoteEvents(events);
FixedEventIter::normalize_event(&mut event, &mut self.note_event_state);
// return as EventIterItem
Ok(Some(vec![EventIterItem::new(event)]))
}
}

Expand All @@ -63,6 +71,7 @@ impl Clone for ScriptedEventIter {
Self {
timeout_hook: self.timeout_hook.clone(),
callback: self.callback.clone(),
note_event_state: self.note_event_state.clone(),
pulse_step: self.pulse_step,
pulse_time_step: self.pulse_time_step,
step: self.step,
Expand All @@ -87,11 +96,7 @@ impl EventIter for ScriptedEventIter {
}
}

fn run(
&mut self,
pulse: PulseIterItem,
emit_event: bool,
) -> Option<Vec<EventIterItem>> {
fn run(&mut self, pulse: PulseIterItem, emit_event: bool) -> Option<Vec<EventIterItem>> {
// generate a new event and move or only update pulse counters
if emit_event {
let event = match self.next_event(pulse) {
Expand Down Expand Up @@ -137,5 +142,7 @@ impl EventIter for ScriptedEventIter {
if let Err(err) = self.callback.reset() {
self.callback.handle_error(&err);
}
// reset last event
self.note_event_state.clear();
}
}

0 comments on commit 17cdaa1

Please sign in to comment.