Feat: add hidden mode and new documentation
This commit is contained in:
@@ -125,6 +125,11 @@ pub enum SeqCommand {
|
||||
muted: std::collections::HashSet<(usize, usize)>,
|
||||
soloed: std::collections::HashSet<(usize, usize)>,
|
||||
},
|
||||
ScriptUpdate {
|
||||
script: String,
|
||||
speed: crate::model::PatternSpeed,
|
||||
length: usize,
|
||||
},
|
||||
StopAll,
|
||||
ResetScriptState,
|
||||
Shutdown,
|
||||
@@ -166,6 +171,7 @@ pub struct SharedSequencerState {
|
||||
pub event_count: usize,
|
||||
pub tempo: f64,
|
||||
pub beat: f64,
|
||||
pub script_trace: Option<ExecutionTrace>,
|
||||
}
|
||||
|
||||
pub struct SequencerSnapshot {
|
||||
@@ -174,6 +180,7 @@ pub struct SequencerSnapshot {
|
||||
pub event_count: usize,
|
||||
pub tempo: f64,
|
||||
pub beat: f64,
|
||||
script_trace: Option<ExecutionTrace>,
|
||||
}
|
||||
|
||||
impl From<&SharedSequencerState> for SequencerSnapshot {
|
||||
@@ -184,6 +191,7 @@ impl From<&SharedSequencerState> for SequencerSnapshot {
|
||||
event_count: s.event_count,
|
||||
tempo: s.tempo,
|
||||
beat: s.beat,
|
||||
script_trace: s.script_trace.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,6 +205,7 @@ impl SequencerSnapshot {
|
||||
event_count: 0,
|
||||
tempo: 0.0,
|
||||
beat: 0.0,
|
||||
script_trace: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +245,10 @@ impl SequencerSnapshot {
|
||||
pub fn get_trace(&self, bank: usize, pattern: usize, step: usize) -> Option<&ExecutionTrace> {
|
||||
self.step_traces.get(&(bank, pattern, step))
|
||||
}
|
||||
|
||||
pub fn script_trace(&self) -> Option<&ExecutionTrace> {
|
||||
self.script_trace.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SequencerHandle {
|
||||
@@ -555,6 +568,12 @@ pub struct SequencerState {
|
||||
soloed: std::collections::HashSet<(usize, usize)>,
|
||||
last_tempo: f64,
|
||||
last_beat: f64,
|
||||
script_text: String,
|
||||
script_speed: crate::model::PatternSpeed,
|
||||
script_length: usize,
|
||||
script_frontier: f64,
|
||||
script_step: usize,
|
||||
script_trace: Option<ExecutionTrace>,
|
||||
}
|
||||
|
||||
impl SequencerState {
|
||||
@@ -586,6 +605,12 @@ impl SequencerState {
|
||||
soloed: std::collections::HashSet::new(),
|
||||
last_tempo: 0.0,
|
||||
last_beat: 0.0,
|
||||
script_text: String::new(),
|
||||
script_speed: crate::model::PatternSpeed::default(),
|
||||
script_length: 16,
|
||||
script_frontier: -1.0,
|
||||
script_step: 0,
|
||||
script_trace: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +695,11 @@ impl SequencerState {
|
||||
self.audio_state.flush_midi_notes = true;
|
||||
}
|
||||
}
|
||||
SeqCommand::ScriptUpdate { script, speed, length } => {
|
||||
self.script_text = script;
|
||||
self.script_speed = speed;
|
||||
self.script_length = length;
|
||||
}
|
||||
SeqCommand::StopAll => {
|
||||
// Flush pending updates so cache stays current for future launches
|
||||
for ((bank, pattern), snapshot) in self.pending_updates.drain() {
|
||||
@@ -728,6 +758,20 @@ impl SequencerState {
|
||||
input.mouse_down,
|
||||
);
|
||||
|
||||
self.execute_periodic_script(
|
||||
input.beat,
|
||||
frontier,
|
||||
lookahead_end,
|
||||
input.tempo,
|
||||
input.quantum,
|
||||
input.fill,
|
||||
input.nudge_secs,
|
||||
input.engine_time,
|
||||
input.mouse_x,
|
||||
input.mouse_y,
|
||||
input.mouse_down,
|
||||
);
|
||||
|
||||
let new_tempo = self.read_tempo_variable(steps.any_step_fired);
|
||||
self.apply_follow_ups();
|
||||
|
||||
@@ -754,6 +798,9 @@ impl SequencerState {
|
||||
}
|
||||
}
|
||||
self.audio_state.prev_beat = -1.0;
|
||||
self.script_frontier = -1.0;
|
||||
self.script_step = 0;
|
||||
self.script_trace = None;
|
||||
self.buf_audio_commands.clear();
|
||||
let flush = std::mem::take(&mut self.audio_state.flush_midi_notes);
|
||||
TickOutput {
|
||||
@@ -985,6 +1032,87 @@ impl SequencerState {
|
||||
result
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn execute_periodic_script(
|
||||
&mut self,
|
||||
beat: f64,
|
||||
frontier: f64,
|
||||
lookahead_end: f64,
|
||||
tempo: f64,
|
||||
quantum: f64,
|
||||
fill: bool,
|
||||
nudge_secs: f64,
|
||||
engine_time: f64,
|
||||
mouse_x: f64,
|
||||
mouse_y: f64,
|
||||
mouse_down: f64,
|
||||
) {
|
||||
if self.script_text.trim().is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let script_frontier = if self.script_frontier < 0.0 {
|
||||
frontier.max(0.0)
|
||||
} else {
|
||||
self.script_frontier
|
||||
};
|
||||
|
||||
let speed_mult = self.script_speed.multiplier();
|
||||
let fire_beats = substeps_in_window(script_frontier, lookahead_end, speed_mult);
|
||||
|
||||
for step_beat in fire_beats {
|
||||
let beat_delta = step_beat - beat;
|
||||
let time_delta = if tempo > 0.0 {
|
||||
(beat_delta / tempo) * 60.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let event_time = Some(engine_time + time_delta);
|
||||
|
||||
let step_in_cycle = self.script_step % self.script_length;
|
||||
|
||||
if step_in_cycle == 0 {
|
||||
let ctx = StepContext {
|
||||
step: 0,
|
||||
beat: step_beat,
|
||||
bank: 0,
|
||||
pattern: 0,
|
||||
tempo,
|
||||
phase: step_beat % quantum,
|
||||
slot: 0,
|
||||
runs: self.script_step / self.script_length,
|
||||
iter: self.script_step / self.script_length,
|
||||
speed: speed_mult,
|
||||
fill,
|
||||
nudge_secs,
|
||||
cc_access: self.cc_access.as_deref(),
|
||||
speed_key: "",
|
||||
mouse_x,
|
||||
mouse_y,
|
||||
mouse_down,
|
||||
};
|
||||
|
||||
let mut trace = ExecutionTrace::default();
|
||||
if let Ok(cmds) =
|
||||
self.script_engine
|
||||
.evaluate_with_trace(&self.script_text, &ctx, &mut trace)
|
||||
{
|
||||
for cmd in cmds {
|
||||
self.event_count += 1;
|
||||
self.buf_audio_commands.push(TimestampedCommand {
|
||||
cmd,
|
||||
time: event_time,
|
||||
});
|
||||
}
|
||||
}
|
||||
self.script_trace = Some(trace);
|
||||
}
|
||||
self.script_step += 1;
|
||||
}
|
||||
|
||||
self.script_frontier = lookahead_end;
|
||||
}
|
||||
|
||||
fn read_tempo_variable(&self, any_step_fired: bool) -> Option<f64> {
|
||||
if !any_step_fired {
|
||||
return None;
|
||||
@@ -1056,6 +1184,7 @@ impl SequencerState {
|
||||
event_count: self.event_count,
|
||||
tempo: self.last_tempo,
|
||||
beat: self.last_beat,
|
||||
script_trace: self.script_trace.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user