WIP: optimizations for linux
This commit is contained in:
@@ -494,7 +494,6 @@ pub(crate) struct TickOutput {
|
||||
}
|
||||
|
||||
struct StepResult {
|
||||
completed_iterations: Vec<PatternId>,
|
||||
any_step_fired: bool,
|
||||
}
|
||||
|
||||
@@ -557,6 +556,7 @@ pub(crate) struct SequencerState {
|
||||
buf_audio_commands: Vec<TimestampedCommand>,
|
||||
buf_activated: Vec<PatternId>,
|
||||
buf_stopped: Vec<PatternId>,
|
||||
buf_completed_iterations: Vec<PatternId>,
|
||||
cc_access: Option<Arc<dyn CcAccess>>,
|
||||
active_notes: HashMap<(u8, u8, u8), ActiveNote>,
|
||||
muted: std::collections::HashSet<(usize, usize)>,
|
||||
@@ -580,11 +580,12 @@ impl SequencerState {
|
||||
dropped_events: 0,
|
||||
script_engine,
|
||||
variables,
|
||||
speed_overrides: HashMap::new(),
|
||||
speed_overrides: HashMap::with_capacity(MAX_PATTERNS),
|
||||
key_cache: KeyCache::new(),
|
||||
buf_audio_commands: Vec::with_capacity(32),
|
||||
buf_activated: Vec::with_capacity(16),
|
||||
buf_stopped: Vec::with_capacity(16),
|
||||
buf_completed_iterations: Vec::with_capacity(16),
|
||||
cc_access,
|
||||
active_notes: HashMap::new(),
|
||||
muted: std::collections::HashSet::new(),
|
||||
@@ -710,7 +711,7 @@ impl SequencerState {
|
||||
input.mouse_down,
|
||||
);
|
||||
|
||||
let vars = self.read_variables(&steps.completed_iterations, steps.any_step_fired);
|
||||
let vars = self.read_variables(&self.buf_completed_iterations, steps.any_step_fired);
|
||||
self.apply_chain_transitions(vars.chain_transitions);
|
||||
|
||||
self.audio_state.prev_beat = beat;
|
||||
@@ -813,14 +814,14 @@ impl SequencerState {
|
||||
#[cfg(feature = "desktop")] mouse_down: f64,
|
||||
) -> StepResult {
|
||||
self.buf_audio_commands.clear();
|
||||
self.buf_completed_iterations.clear();
|
||||
let mut result = StepResult {
|
||||
completed_iterations: Vec::new(),
|
||||
any_step_fired: false,
|
||||
};
|
||||
|
||||
self.speed_overrides.clear();
|
||||
{
|
||||
let vars = self.variables.lock().unwrap();
|
||||
let vars = self.variables.lock();
|
||||
for id in self.audio_state.active_patterns.keys() {
|
||||
let key = self.key_cache.speed_key(id.bank, id.pattern);
|
||||
if let Some(v) = vars.get(key).and_then(|v| v.as_float().ok()) {
|
||||
@@ -921,7 +922,7 @@ impl SequencerState {
|
||||
let next_step = active.step_index + 1;
|
||||
if next_step >= pattern.length {
|
||||
active.iter += 1;
|
||||
result.completed_iterations.push(PatternId {
|
||||
self.buf_completed_iterations.push(PatternId {
|
||||
bank: active.bank,
|
||||
pattern: active.pattern,
|
||||
});
|
||||
@@ -947,7 +948,7 @@ impl SequencerState {
|
||||
};
|
||||
}
|
||||
|
||||
let mut vars = self.variables.lock().unwrap();
|
||||
let mut vars = self.variables.lock();
|
||||
let new_tempo = vars.remove("__tempo__").and_then(|v| v.as_float().ok());
|
||||
|
||||
let mut chain_transitions = Vec::new();
|
||||
@@ -1073,7 +1074,7 @@ fn sequencer_loop(
|
||||
let mut seq_state = SequencerState::new(variables, dict, rng, cc_access);
|
||||
|
||||
loop {
|
||||
let mut commands = Vec::new();
|
||||
let mut commands = Vec::with_capacity(8);
|
||||
while let Ok(cmd) = cmd_rx.try_recv() {
|
||||
if matches!(cmd, SeqCommand::Shutdown) {
|
||||
return;
|
||||
@@ -1205,7 +1206,16 @@ fn sequencer_loop(
|
||||
|
||||
shared_state.store(Arc::new(output.shared_state));
|
||||
|
||||
thread::sleep(Duration::from_micros(200));
|
||||
// Adaptive sleep: calculate time until next substep boundary
|
||||
// At max speed (8x), substeps occur every beat/32
|
||||
// Sleep for most of that time, leaving 500μs margin for processing
|
||||
let beats_per_sec = tempo / 60.0;
|
||||
let max_speed = 8.0; // Maximum speed multiplier from speed.clamp()
|
||||
let secs_per_substep = 1.0 / (beats_per_sec * 4.0 * max_speed);
|
||||
let substep_us = (secs_per_substep * 1_000_000.0) as u64;
|
||||
// Sleep for most of the substep duration, clamped to reasonable bounds
|
||||
let sleep_us = substep_us.saturating_sub(500).clamp(50, 2000);
|
||||
thread::sleep(Duration::from_micros(sleep_us));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1317,7 +1327,7 @@ fn parse_midi_command(cmd: &str) -> Option<(MidiCommand, Option<f64>)> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::Mutex;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
fn make_state() -> SequencerState {
|
||||
let variables: Variables = Arc::new(Mutex::new(HashMap::new()));
|
||||
@@ -1497,7 +1507,7 @@ mod tests {
|
||||
|
||||
// Set chain variable
|
||||
{
|
||||
let mut vars = state.variables.lock().unwrap();
|
||||
let mut vars = state.variables.lock();
|
||||
vars.insert(
|
||||
"__chain_0_0__".to_string(),
|
||||
Value::Str(std::sync::Arc::from("0:1"), None),
|
||||
@@ -1736,7 +1746,7 @@ mod tests {
|
||||
|
||||
// Set chain: 0:0 -> 0:1
|
||||
{
|
||||
let mut vars = state.variables.lock().unwrap();
|
||||
let mut vars = state.variables.lock();
|
||||
vars.insert(
|
||||
"__chain_0_0__".to_string(),
|
||||
Value::Str(std::sync::Arc::from("0:1"), None),
|
||||
@@ -1979,7 +1989,7 @@ mod tests {
|
||||
|
||||
// Script fires at beat 1.0 (step 0). Set __tempo__ as if the script did.
|
||||
{
|
||||
let mut vars = state.variables.lock().unwrap();
|
||||
let mut vars = state.variables.lock();
|
||||
vars.insert("__tempo__".to_string(), Value::Float(140.0, None));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user