Feat: extend CI to cover desktop
This commit is contained in:
@@ -41,6 +41,7 @@ pub type Variables = Arc<Mutex<HashMap<String, Value>>>;
|
||||
pub type Dictionary = Arc<Mutex<HashMap<String, Vec<Op>>>>;
|
||||
pub type Rng = Arc<Mutex<StdRng>>;
|
||||
pub type Stack = Arc<Mutex<Vec<Value>>>;
|
||||
pub(super) type CmdSnapshot<'a> = (Option<&'a Value>, &'a [(String, Value)]);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Value {
|
||||
@@ -140,8 +141,12 @@ impl CmdRegister {
|
||||
&self.deltas
|
||||
}
|
||||
|
||||
pub(super) fn snapshot(&self) -> Option<(&Value, &[(String, Value)])> {
|
||||
self.sound.as_ref().map(|s| (s, self.params.as_slice()))
|
||||
pub(super) fn snapshot(&self) -> Option<CmdSnapshot<'_>> {
|
||||
if self.sound.is_some() || !self.params.is_empty() {
|
||||
Some((self.sound.as_ref(), self.params.as_slice()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn clear(&mut self) {
|
||||
|
||||
@@ -147,9 +147,12 @@ impl Forth {
|
||||
};
|
||||
|
||||
let emit_with_cycling = |cmd: &CmdRegister, emit_idx: usize, delta_secs: f64, outputs: &mut Vec<String>| -> Result<Option<Value>, String> {
|
||||
let (sound_val, params) = cmd.snapshot().ok_or("no sound set")?;
|
||||
let resolved_sound_val = resolve_cycling(sound_val, emit_idx);
|
||||
let sound = resolved_sound_val.as_str()?.to_string();
|
||||
let (sound_opt, params) = cmd.snapshot().ok_or("nothing to emit")?;
|
||||
let resolved_sound_val = sound_opt.map(|sv| resolve_cycling(sv, emit_idx));
|
||||
let sound_str = match &resolved_sound_val {
|
||||
Some(v) => Some(v.as_str()?.to_string()),
|
||||
None => None,
|
||||
};
|
||||
let resolved_params: Vec<(String, String)> =
|
||||
params.iter().map(|(k, v)| {
|
||||
let resolved = resolve_cycling(v, emit_idx);
|
||||
@@ -162,8 +165,8 @@ impl Forth {
|
||||
}
|
||||
(k.clone(), resolved.to_param_string())
|
||||
}).collect();
|
||||
emit_output(&sound, &resolved_params, ctx.step_duration(), delta_secs, outputs);
|
||||
Ok(Some(resolved_sound_val.into_owned()))
|
||||
emit_output(sound_str.as_deref(), &resolved_params, ctx.step_duration(), delta_secs, outputs);
|
||||
Ok(resolved_sound_val.map(|v| v.into_owned()))
|
||||
};
|
||||
|
||||
while pc < ops.len() {
|
||||
@@ -796,26 +799,34 @@ fn is_tempo_scaled_param(name: &str) -> bool {
|
||||
}
|
||||
|
||||
fn emit_output(
|
||||
sound: &str,
|
||||
sound: Option<&str>,
|
||||
params: &[(String, String)],
|
||||
step_duration: f64,
|
||||
nudge_secs: f64,
|
||||
outputs: &mut Vec<String>,
|
||||
) {
|
||||
let mut pairs = vec![("sound".into(), sound.to_string())];
|
||||
let mut pairs: Vec<(String, String)> = if let Some(s) = sound {
|
||||
vec![("sound".into(), s.to_string())]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
pairs.extend(params.iter().cloned());
|
||||
if nudge_secs > 0.0 {
|
||||
pairs.push(("delta".into(), nudge_secs.to_string()));
|
||||
}
|
||||
if !pairs.iter().any(|(k, _)| k == "dur") {
|
||||
// Only add default dur if there's a sound (new voice)
|
||||
if sound.is_some() && !pairs.iter().any(|(k, _)| k == "dur") {
|
||||
pairs.push(("dur".into(), step_duration.to_string()));
|
||||
}
|
||||
// Only add default delaytime if there's a sound (new voice)
|
||||
if sound.is_some() {
|
||||
if let Some(idx) = pairs.iter().position(|(k, _)| k == "delaytime") {
|
||||
let ratio: f64 = pairs[idx].1.parse().unwrap_or(1.0);
|
||||
pairs[idx].1 = (ratio * step_duration).to_string();
|
||||
} else {
|
||||
pairs.push(("delaytime".into(), step_duration.to_string()));
|
||||
}
|
||||
}
|
||||
for pair in &mut pairs {
|
||||
if is_tempo_scaled_param(&pair.0) {
|
||||
if let Ok(val) = pair.1.parse::<f64>() {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Welcome to Cagire
|
||||
|
||||
Cagire is a terminal-based step sequencer for live coding music. Each step in a pattern contains a **Forth** script that produces sound and create events. It is made by BuboBubo (Raphaël Maurice Forment): [https://raphaelforment.fr](https://raphaelforment.fr). Cagire is open-source (AGPL-3.0 licensed) and available on GitHub : [https://github.com/BuboBubo/cagire](https://github.com/BuboBubo/cagire). This help view will teach you everything you need to know to start using Cagire and and to live code with it.
|
||||
Cagire is a terminal-based step sequencer for live coding music. Each step in a pattern contains a **Forth** script that produces sound and create events. It is made by BuboBubo (Raphaël Maurice Forment): [https://raphaelforment.fr](https://raphaelforment.fr). Cagire is open-source (AGPL-3.0 licensed) and available on GitHub : [https://github.com/BuboBubo/cagire](https://github.com/BuboBubo/cagire). This help view will teach you everything you need to know to start using Cagire and and to live code with it. To use Cagire, you will need to understand two things:
|
||||
|
||||
1) How the sequencer works: dealing with steps, patterns and banks.
|
||||
2) How to write a script: how to make sound using code.
|
||||
|
||||
## Pages
|
||||
|
||||
|
||||
@@ -245,6 +245,7 @@ fn preprocess_underscores(md: &str) -> String {
|
||||
|
||||
fn parse_markdown(md: &str) -> Vec<RLine<'static>> {
|
||||
let processed = preprocess_underscores(md);
|
||||
eprintln!("DEBUG parse_markdown: processed={:?}", &processed[..100.min(processed.len())]);
|
||||
let text = minimad::Text::from(processed.as_str());
|
||||
let mut lines = Vec::new();
|
||||
|
||||
@@ -315,6 +316,11 @@ fn compound_to_spans(compound: Compound, base: Style, out: &mut Vec<Span<'static
|
||||
let theme = theme::get();
|
||||
let mut style = base;
|
||||
|
||||
// DEBUG: Check if bold flag is being set
|
||||
if compound.bold || compound.src.contains("**") {
|
||||
eprintln!("compound: bold={} src={:?}", compound.bold, compound.src);
|
||||
}
|
||||
|
||||
if compound.bold {
|
||||
style = style.add_modifier(Modifier::BOLD);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ fn auto_delaytime() {
|
||||
|
||||
#[test]
|
||||
fn emit_no_sound() {
|
||||
expect_error(".", "no sound set");
|
||||
expect_error(".", "nothing to emit");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -87,3 +87,22 @@ fn bank_param() {
|
||||
assert!(outputs[0].contains("sound/loop"));
|
||||
assert!(outputs[0].contains("bank/a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn param_only_emit() {
|
||||
let outputs = expect_outputs(r#"0 voice 880 freq ."#, 1);
|
||||
assert!(outputs[0].contains("voice/0"));
|
||||
assert!(outputs[0].contains("freq/880"));
|
||||
assert!(!outputs[0].contains("sound/"));
|
||||
assert!(!outputs[0].contains("dur/"));
|
||||
assert!(!outputs[0].contains("delaytime/"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn param_only_multiple_params() {
|
||||
let outputs = expect_outputs(r#"0 voice 440 freq 0.5 gain ."#, 1);
|
||||
assert!(outputs[0].contains("voice/0"));
|
||||
assert!(outputs[0].contains("freq/440"));
|
||||
assert!(outputs[0].contains("gain/0.5"));
|
||||
assert!(!outputs[0].contains("sound/"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user