1#![cfg_attr(
19 not(bela_device),
20 allow(
21 dead_code,
22 reason = "only the fallback main is reachable off-device; the application code should still compile and lint"
23 )
24)]
25
26use core::sync::atomic::{AtomicU64, Ordering};
27#[cfg(not(bela_device))]
28use std::process::ExitCode;
29use std::sync::Arc;
30
31use bela::{
32 AuxiliaryTask, BelaApplication, BlockContext, CleanupContext, Priority, RenderContext,
33 SetupContext, ThreadInfo, rt_println,
34};
35
36const TASK_PRIORITY: Priority = Priority::new(75).expect("75 is within Bela's priority range");
39
40struct Report {
41 task: Option<AuxiliaryTask>,
42 blocks: Arc<AtomicU64>,
45 interval: u64,
47 runs: Arc<AtomicU64>,
51 requests: u64,
54}
55
56impl Report {
57 fn new() -> Self {
58 Self {
59 task: None,
60 blocks: Arc::new(AtomicU64::new(0)),
61 interval: 1,
62 runs: Arc::new(AtomicU64::new(0)),
63 requests: 0,
64 }
65 }
66}
67
68impl BelaApplication for Report {
69 type RenderState = ();
70
71 fn setup(&mut self, context: &SetupContext) -> bool {
72 #[allow(
73 clippy::cast_possible_truncation,
74 clippy::cast_sign_loss,
75 reason = "the sample rate is a small positive number"
76 )]
77 let sample_rate_hz = context.audio_sample_rate() as u64;
78 self.interval = (sample_rate_hz / context.audio_frames().max(1) as u64).max(1);
79
80 let blocks = Arc::clone(&self.blocks);
84 let runs = Arc::clone(&self.runs);
85 let task = AuxiliaryTask::new("bela-rs-report", TASK_PRIORITY, move || {
86 runs.fetch_add(1, Ordering::Relaxed);
87 let count = blocks.load(Ordering::Relaxed);
88 let bar = "#".repeat((count / 10_000) as usize + 1);
91 rt_println!("task: {count} blocks {bar}");
92 });
93
94 match task {
95 Ok(task) => {
96 self.task = Some(task);
97 rt_println!("setup: reporting every {} blocks", self.interval);
98 true
99 }
100 Err(error) => {
101 rt_println!("setup: could not create the task: {error}");
102 false
103 }
104 }
105 }
106
107 fn create_render_state(&mut self, _thread: ThreadInfo, _context: &SetupContext) {}
108
109 fn render(&self, _state: &mut (), _context: &mut RenderContext) {}
110
111 fn render_post(&mut self, _states: &mut [()], context: &mut BlockContext) {
114 let blocks = self.blocks.fetch_add(1, Ordering::Relaxed) + 1;
115 if blocks % self.interval != 0 {
116 return;
117 }
118 if let Some(task) = &self.task {
119 task.schedule(context);
120 self.requests += 1;
121 }
122 }
123
124 fn cleanup(&mut self, _states: &mut [()], _context: &CleanupContext) {
125 rt_println!(
126 "cleanup: {} blocks, {} requests, {} task runs",
127 self.blocks.load(Ordering::Relaxed),
128 self.requests,
129 self.runs.load(Ordering::Relaxed)
130 );
131 }
132}
133
134#[cfg(bela_device)]
135fn main() -> Result<(), bela::Error> {
136 bela::Bela::run(Report::new(), &bela::Settings::new())
137}
138
139#[cfg(not(bela_device))]
140fn main() -> ExitCode {
141 eprintln!("This example must be cross-compiled for Bela Gem (aarch64-unknown-linux-gnu).");
142 ExitCode::FAILURE
143}