fcb_looper/audio_engine/src/track_matrix.rs
2025-08-05 12:03:26 +02:00

98 lines
3.1 KiB
Rust

use crate::*;
pub struct TrackMatrix<F: ChunkFactory, const COLS: usize, const ROWS: usize> {
chunk_factory: F,
columns: [Column<ROWS>; COLS],
scratch_pad: Box<[f32]>,
}
impl<F: ChunkFactory, const COLS: usize, const ROWS: usize> TrackMatrix<F, COLS, ROWS> {
pub fn new(client: &jack::Client, chunk_factory: F, state: &State) -> Result<Self> {
let columns = std::array::from_fn(|_| Column::new(state.metronome.frames_per_beat));
Ok(Self {
chunk_factory,
columns,
scratch_pad: vec![0.0; client.buffer_size() as usize].into_boxed_slice(),
})
}
pub fn handle_record_button(
&mut self,
last_volume_setting: f32,
controllers: &TrackControllers,
) -> Result<()> {
self.columns[controllers.column()].handle_record_button(last_volume_setting, controllers)
}
pub fn handle_play_button(&mut self, controllers: &TrackControllers) -> Result<()> {
self.columns[controllers.column()].handle_play_button(controllers)
}
pub fn handle_clear_button(&mut self, controllers: &TrackControllers) -> Result<()> {
self.columns[controllers.column()].handle_clear_button(controllers)
}
pub fn handle_volume_update(
&mut self,
new_volume: f32,
controllers: &TrackControllers,
) -> Result<()> {
self.columns[controllers.column()].handle_volume_update(new_volume, controllers)
}
pub fn is_all_tracks_cleared(&self) -> bool {
self.columns
.iter()
.all(|column| column.is_all_tracks_cleared())
}
pub fn set_frames_per_beat(&mut self, new_frames_per_beat: usize) {
for column in &mut self.columns {
column.set_frames_per_beat(new_frames_per_beat);
}
}
pub fn process(
&mut self,
ps: &jack::ProcessScope,
ports: &mut JackPorts,
timing: &BufferTiming,
controllers: &MatrixControllers,
) -> Result<()> {
// Check for consolidation response
if let Some(response) = controllers.try_recv_post_record_response() {
self.columns[response.column]
.set_consolidated_buffer(response.row, response.consolidated_buffer)?;
}
// Handle xruns
if timing.missed_frames > 0 {
for (i, column) in &mut self.columns.iter_mut().enumerate() {
let controllers = controllers.to_column_controllers(i);
column.handle_xrun(&timing, &mut self.chunk_factory, &controllers)?;
}
}
// Process audio
let input_buffer = ports.audio_in.as_slice(ps);
let output_buffer = ports.audio_out.as_mut_slice(ps);
output_buffer.fill(0.0);
for (i, column) in &mut self.columns.iter_mut().enumerate() {
let controllers = controllers.to_column_controllers(i);
column.process(
&timing,
input_buffer,
output_buffer,
&mut self.scratch_pad,
&mut self.chunk_factory,
&controllers,
)?;
}
Ok(())
}
}