98 lines
3.1 KiB
Rust
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(())
|
|
}
|
|
}
|