#![cfg_attr(
not(bela_device),
allow(
dead_code,
reason = "only the fallback main is reachable off-device; the application code should still compile and lint"
)
)]
use core::num::NonZeroU32;
use core::sync::atomic::{AtomicBool, Ordering};
use std::process::ExitCode;
use std::sync::Arc;
use bela::{BelaApplication, Context};
const MEASUREMENTS_PER_CYCLE: u32 = 2000;
const fn cycle() -> NonZeroU32 {
NonZeroU32::new(MEASUREMENTS_PER_CYCLE).expect("the cycle length is a non-zero constant")
}
struct Observe {
monitored: Arc<AtomicBool>,
}
unsafe impl BelaApplication for Observe {
fn setup(&mut self, context: &mut Context) -> bool {
self.monitored
.store(context.cpu_usage().is_some(), Ordering::Relaxed);
false
}
fn render(&mut self, _context: &mut Context) {}
}
struct Abort;
unsafe impl BelaApplication for Abort {
fn setup(&mut self, _context: &mut Context) -> bool {
false
}
fn render(&mut self, _context: &mut Context) {}
}
struct Idle;
unsafe impl BelaApplication for Idle {
fn render(&mut self, _context: &mut Context) {}
}
#[cfg(bela_device)]
mod checks {
use core::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use bela::{Bela, Error, Settings};
use super::{Abort, Idle, Observe, cycle};
pub fn fifo_probe(period_size: u32) {
let settings = Settings::new().period_size(period_size).verbose(true);
drop(Bela::new(Abort, &settings));
}
pub fn second_new() {
let outcome = match Bela::new(Idle, &Settings::new()) {
Err(error) => format!("first-new-failed-{error}"),
Ok(first) => {
let second = match Bela::new(Idle, &Settings::new()) {
Err(Error::AudioSystemExists) => "refused",
Err(_) => "failed-otherwise",
Ok(_) => "created",
};
drop(first);
second.to_owned()
}
};
println!("rules: second-new={outcome}");
}
pub fn monitoring(requested: bool) {
let settings = if requested {
Settings::new().cpu_monitoring(cycle())
} else {
Settings::new()
};
let monitored = Arc::new(AtomicBool::new(false));
let app = Observe {
monitored: Arc::clone(&monitored),
};
let observed = match Bela::new(app, &settings) {
Err(Error::Init(_)) => true,
Err(_) => false,
Ok(bela) => {
drop(bela);
true
}
};
let seen = if !observed {
"setup-not-reached"
} else if monitored.load(Ordering::Relaxed) {
"some"
} else {
"none"
};
println!("rules: monitoring={seen}");
}
}
#[cfg(bela_device)]
fn main() -> ExitCode {
use std::env::args;
let arguments: Vec<String> = args().skip(1).collect();
let check: Vec<&str> = arguments.iter().map(String::as_str).collect();
match check.as_slice() {
["fifo-probe", frames] => {
let Ok(frames) = frames.parse() else {
eprintln!("fifo-probe takes a period size in frames, not {frames:?}");
return ExitCode::FAILURE;
};
checks::fifo_probe(frames);
}
["second-new"] => checks::second_new(),
["monitoring", "on"] => checks::monitoring(true),
["monitoring", "off"] => checks::monitoring(false),
_ => {
eprintln!(
"usage: monitoring_rules (fifo-probe <frames> | second-new | monitoring on|off)\n\
one check per run: this board does not survive several audio systems in one process"
);
return ExitCode::FAILURE;
}
}
ExitCode::SUCCESS
}
#[cfg(not(bela_device))]
fn main() -> ExitCode {
eprintln!("This example must be cross-compiled for Bela Gem (aarch64-unknown-linux-gnu).");
ExitCode::FAILURE
}