Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/src/API/cycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,20 @@
> channel/voice index within the cycle. each channel in the cycle gets emitted and thus mapped
> separately, starting with the first channel index 1.

### iteration : [`integer`](../API/builtins/integer.md)<a name="iteration"></a>
> Iteration counter for the cycle that increases once per the whole cycle's output
> Starts from 1 when the cycle starts running or after it got reset.

### step : [`integer`](../API/builtins/integer.md)<a name="step"></a>
> Continues step counter for each channel, incrementing with each new mapped value in the cycle.
> Starts from 1 when the cycle starts running or after it got reset.

### step_length : [`number`](../API/builtins/number.md)<a name="step_length"></a>
> step length fraction within the cycle, where 1 is the total duration of a single cycle run.

### step_time : [`number`](../API/builtins/number.md)<a name="step_time"></a>
> step start fraction within the cycle, where 1 is the total duration of a single cycle run.

### trigger : [`Note`](../API/note.md#Note)[`?`](../API/builtins/nil.md)<a name="trigger"></a>
> Note that triggered the pattern, if any. Usually will be a monophonic note.
> To access the raw note number value use: `context.trigger.notes[1].key`
Expand Down
30 changes: 21 additions & 9 deletions src/bindings/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@ impl LuaCallback {
.unwrap_or("anonymous function".to_string())
}

/// Applies a function to itself and handles the error that may occur.
pub fn handle<F>(&mut self, fun: F)
where
F: FnOnce(&mut Self) -> LuaResult<()>,
{
if let Err(err) = fun(self) {
self.handle_error(&err);
}
}

/// Sets the emitters playback state for the callback.
pub fn set_context_playback_state(
&mut self,
Expand Down Expand Up @@ -306,11 +316,13 @@ impl LuaCallback {
channel: usize,
step: usize,
step_length: f64,
step_time: f64,
) -> LuaResult<()> {
let values = &mut self.context.borrow_mut::<CallbackContext>()?.values;
values.insert(b"channel", (channel + 1).into());
values.insert(b"step", step.wrapping_add(1).into());
values.insert(b"step_length", step_length.into());
values.insert(b"step_time", step_time.into());
Ok(())
}

Expand Down Expand Up @@ -363,17 +375,17 @@ impl LuaCallback {
}

/// Sets the cycle context for the mapping callbacks.
pub fn set_cycle_map_context(
&mut self,
playback_state: ContextPlaybackState,
time_base: &BeatTimeBase,
channel: usize,
step: usize,
step_length: f64,
) -> LuaResult<()> {
pub fn init_cycle_map_context(&mut self, time_base: &BeatTimeBase) -> LuaResult<()> {
let playback_state = ContextPlaybackState::Running;
let channel = 0;
let step = 0;
let step_length = 0.0;
let step_time = 0.0;
let iteration = 1;
self.set_context_cycle_iteration(iteration)?;
self.set_context_playback_state(playback_state)?;
self.set_context_time_base(time_base)?;
self.set_context_cycle_step(channel, step, step_length)?;
self.set_context_cycle_step(channel, step, step_length, step_time)?;
Ok(())
}

Expand Down
29 changes: 8 additions & 21 deletions src/emitter/scripted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,22 @@ impl Emitter for ScriptedEmitter {
// reset timeout
self.timeout_hook.reset();
// update function context with the new time base
if let Err(err) = self.callback.set_context_time_base(time_base) {
self.callback.handle_error(&err);
}
self.callback.handle(|c| c.set_context_time_base(time_base));
}

fn set_trigger_event(&mut self, event: &Event) {
// reset timeout
self.timeout_hook.reset();
// update function context from the new time base
if let Err(err) = self.callback.set_context_trigger_event(event) {
self.callback.handle_error(&err);
}
self.callback.handle(|c| c.set_context_trigger_event(event))
}

fn set_parameters(&mut self, parameters: ParameterSet) {
// reset timeout
self.timeout_hook.reset();
// update function context with the new parameters
if let Err(err) = self.callback.set_context_parameters(&parameters) {
self.callback.handle_error(&err);
}
self.callback
.handle(|c| c.set_context_parameters(&parameters));
}

fn run(&mut self, pulse: RhythmEvent, emit_event: bool) -> Option<Vec<EmitterEvent>> {
Expand Down Expand Up @@ -176,22 +171,14 @@ impl Emitter for ScriptedEmitter {
self.timeout_hook.reset();
// reset step counter
self.step = 0;
if let Err(err) = self.callback.set_context_step(self.step) {
self.callback.handle_error(&err);
}
self.callback.handle(|c| c.set_context_step(self.step));
// reset pulse counter
self.pulse_step = 0;
self.pulse_time_step = 0.0;
if let Err(err) = self
.callback
.set_context_pulse_step(self.pulse_step, self.pulse_time_step)
{
self.callback.handle_error(&err);
}
self.callback
.handle(|c| c.set_context_pulse_step(self.pulse_step, self.pulse_time_step));
// restore function
if let Err(err) = self.callback.reset() {
self.callback.handle_error(&err);
}
self.callback.handle(|c| c.reset());
// reset last event
self.note_event_state.clear();
}
Expand Down
104 changes: 41 additions & 63 deletions src/emitter/scripted_cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,8 @@ impl ScriptedCycleEmitter {
timeout_hook.reset();
let timeout_hook = Some(timeout_hook);
// initialize emitter context for the function
let playback_state = ContextPlaybackState::Running;
let channel = 0;
let step = 0;
let step_length = 0.0;
let mut mapping_callback = mapping_callback;
mapping_callback.set_cycle_map_context(
playback_state,
time_base,
channel,
step,
step_length,
)?;
mapping_callback.init_cycle_map_context(time_base)?;
let mappings = ScriptedCycleMapping::Function(mapping_callback);
let channel_steps = vec![];
Ok(Self {
Expand All @@ -159,6 +149,7 @@ impl ScriptedCycleEmitter {
channel_index: usize,
channel_step: usize,
step_length: f64,
step_time: f64,
event: CycleEvent,
) -> LuaResult<Vec<Option<NoteEvent>>> {
let mut note_events = {
Expand All @@ -169,6 +160,7 @@ impl ScriptedCycleEmitter {
channel_index,
channel_step,
step_length,
step_time,
)?;
// call mapping function
let result = mapping_callback.call_with_arg(event.as_str().as_ref())?;
Expand Down Expand Up @@ -216,6 +208,13 @@ impl ScriptedCycleEmitter {
// inject var callback values into cycle, if present
self.apply_variables_callback();

// set mapping callback playback state
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
callback.handle(|c| {
c.set_context_playback_state(ContextPlaybackState::Running)
.and(c.set_context_cycle_iteration(self.cycle.iteration()))
});
}
// run the cycle event generator
let events = {
match self.cycle.generate() {
Expand All @@ -235,13 +234,6 @@ impl ScriptedCycleEmitter {
}
};

// set mapping callback playback state
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
if let Err(err) = callback.set_context_playback_state(ContextPlaybackState::Running) {
callback.handle_error(&err);
}
}

// convert possibly mapped cycle channel items to a list of note events
let mut timed_note_events = CycleNoteEvents::new();
for (channel_index, channel_events) in events.into_iter().enumerate() {
Expand All @@ -256,7 +248,14 @@ impl ScriptedCycleEmitter {
let start = event.span().start();
let length = event.span().length();
let step_length = length.to_f64().unwrap_or(0.0);
match self.cycle_to_note_event(channel_index, channel_step, step_length, event) {
let step_time = start.to_f64().unwrap_or(0.0);
match self.cycle_to_note_event(
channel_index,
channel_step,
step_length,
step_time,
event,
) {
Err(err) => {
if let ScriptedCycleMapping::Function(callback) = &self.mappings {
callback.handle_error(&err)
Expand Down Expand Up @@ -330,11 +329,9 @@ impl ScriptedCycleEmitter {
match &mut self.mappings {
ScriptedCycleMapping::Function(mapping_callback) => {
// set playback state
if let Err(err) =
mapping_callback.set_context_playback_state(ContextPlaybackState::Seeking)
{
mapping_callback.handle_error(&err);
}
mapping_callback
.handle(|c| c.set_context_playback_state(ContextPlaybackState::Seeking));

if mapping_callback.is_stateful().unwrap_or(true) {
// run stateful callbacks but ignore results
for (channel_index, channel_events) in events.into_iter().enumerate() {
Expand All @@ -347,10 +344,12 @@ impl ScriptedCycleEmitter {
self.channel_steps[channel_index] += 1;
// update step in context
let step_length = event.span().length().to_f64().unwrap_or(0.0);
let step_time = event.span().start().to_f64().unwrap_or(0.0);
if let Err(err) = mapping_callback.set_context_cycle_step(
channel_index,
channel_step,
step_length,
step_time,
) {
mapping_callback.handle_error(&err);
return;
Expand Down Expand Up @@ -408,15 +407,13 @@ impl ScriptedCycleEmitter {
fn apply_variables_callback(&mut self) {
if let ScriptedCycleMapping::Function(callback) = &mut self.variables {
// update context
if let Err(err) = callback
.set_context_playback_state(ContextPlaybackState::Running)
.and(callback.set_context_parameters(
&self.parameters.iter().map(|(p, _)| Rc::clone(p)).collect(),
))
.and(callback.set_context_cycle_iteration(self.cycle.iteration()))
{
callback.handle_error(&err);
}
callback.handle(|c| {
c.set_context_playback_state(ContextPlaybackState::Running)
.and(c.set_context_parameters(
&self.parameters.iter().map(|(p, _)| Rc::clone(p)).collect(),
))
.and(c.set_context_cycle_iteration(self.cycle.iteration()))
});
// run
match callback.call() {
Err(err) => {
Expand Down Expand Up @@ -457,14 +454,10 @@ impl Emitter for ScriptedCycleEmitter {
}
// pass time base to callbacks
if let ScriptedCycleMapping::Function(callback) = &mut self.variables {
if let Err(err) = callback.set_context_time_base(time_base) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_time_base(time_base));
}
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
if let Err(err) = callback.set_context_time_base(time_base) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_time_base(time_base));
}
}

Expand All @@ -475,14 +468,10 @@ impl Emitter for ScriptedCycleEmitter {
}
// pass event to callbacks
if let ScriptedCycleMapping::Function(callback) = &mut self.variables {
if let Err(err) = callback.set_context_trigger_event(event) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_trigger_event(event));
}
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
if let Err(err) = callback.set_context_trigger_event(event) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_trigger_event(event));
}
}

Expand Down Expand Up @@ -523,16 +512,12 @@ impl Emitter for ScriptedCycleEmitter {

// pass parameters to the variables callback context
if let ScriptedCycleMapping::Function(callback) = &mut self.variables {
if let Err(err) = callback.set_context_parameters(&parameters) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_parameters(&parameters));
}

// pass parameters to the mapping callback context
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
if let Err(err) = callback.set_context_parameters(&parameters) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_parameters(&parameters));
}
}

Expand Down Expand Up @@ -567,27 +552,20 @@ impl Emitter for ScriptedCycleEmitter {
if let ScriptedCycleMapping::Function(callback) = &mut self.variables {
// reset iteration counter
let iteration = 0;
if let Err(err) = callback.set_context_cycle_iteration(iteration) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_cycle_iteration(iteration));
// restore function
if let Err(err) = callback.reset() {
callback.handle_error(&err);
}
callback.handle(|c| c.reset());
}
if let ScriptedCycleMapping::Function(callback) = &mut self.mappings {
// reset step counter
let channel = 0;
let step = 0;
let step_length = 0.0;
let step_time = 0.0;
self.channel_steps.clear();
if let Err(err) = callback.set_context_cycle_step(channel, step, step_length) {
callback.handle_error(&err);
}
callback.handle(|c| c.set_context_cycle_step(channel, step, step_length, step_time));
// restore function
if let Err(err) = callback.reset() {
callback.handle_error(&err);
}
callback.handle(|c| c.reset());
}
}
}
Loading
Loading