#![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::sync::atomic::{AtomicU64, Ordering};
#[cfg(not(bela_device))]
use std::process::ExitCode;
use std::sync::Arc;
use bela::{
AUDIO_PRIORITY, AuxiliaryTask, BelaApplication, BlockContext, CleanupContext, RenderContext,
SetupContext, ThreadInfo, rt_println,
};
const TASK_PRIORITY: i32 = AUDIO_PRIORITY - 20;
struct Report {
task: Option<AuxiliaryTask>,
blocks: Arc<AtomicU64>,
interval: u64,
runs: Arc<AtomicU64>,
requests: u64,
}
impl Report {
fn new() -> Self {
Self {
task: None,
blocks: Arc::new(AtomicU64::new(0)),
interval: 1,
runs: Arc::new(AtomicU64::new(0)),
requests: 0,
}
}
}
impl BelaApplication for Report {
type RenderState = ();
fn setup(&mut self, context: &SetupContext) -> bool {
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
reason = "the sample rate is a small positive number"
)]
let sample_rate_hz = context.audio_sample_rate() as u64;
self.interval = (sample_rate_hz / context.audio_frames().max(1) as u64).max(1);
let blocks = Arc::clone(&self.blocks);
let runs = Arc::clone(&self.runs);
let task = AuxiliaryTask::new("bela-rs-report", TASK_PRIORITY, move || {
runs.fetch_add(1, Ordering::Relaxed);
let count = blocks.load(Ordering::Relaxed);
let bar = "#".repeat((count / 10_000) as usize + 1);
rt_println!("task: {count} blocks {bar}");
});
match task {
Ok(task) => {
self.task = Some(task);
rt_println!("setup: reporting every {} blocks", self.interval);
true
}
Err(error) => {
rt_println!("setup: could not create the task: {error}");
false
}
}
}
fn create_render_state(&mut self, _thread: ThreadInfo, _context: &SetupContext) {}
fn render(&self, _state: &mut (), _context: &mut RenderContext) {}
fn render_post(&mut self, _states: &mut [()], context: &mut BlockContext) {
let blocks = self.blocks.fetch_add(1, Ordering::Relaxed) + 1;
if blocks % self.interval != 0 {
return;
}
if let Some(task) = &self.task {
task.schedule(context);
self.requests += 1;
}
}
fn cleanup(&mut self, _states: &mut [()], _context: &CleanupContext) {
rt_println!(
"cleanup: {} blocks, {} requests, {} task runs",
self.blocks.load(Ordering::Relaxed),
self.requests,
self.runs.load(Ordering::Relaxed)
);
}
}
#[cfg(bela_device)]
fn main() -> Result<(), bela::Error> {
bela::Bela::run(Report::new(), &bela::Settings::new())
}
#[cfg(not(bela_device))]
fn main() -> ExitCode {
eprintln!("This example must be cross-compiled for Bela Gem (aarch64-unknown-linux-gnu).");
ExitCode::FAILURE
}