use crate::*; pub struct ProcessHandler { post_record_controller: PostRecordController, osc: OscController, persistence: PersistenceManagerController, ports: JackPorts, metronome: Metronome, track_matrix: TrackMatrix, selected_row: usize, selected_column: usize, last_volume_setting: f32, sample_rate: usize, tap_tempo: TapTempo, } impl ProcessHandler { pub fn new( client: &jack::Client, ports: JackPorts, chunk_factory: F, beep_samples: Arc, state: &State, post_record_controller: PostRecordController, osc: OscController, persistence: PersistenceManagerController, ) -> Result { let track_matrix = TrackMatrix::new(client, chunk_factory, state)?; Ok(Self { post_record_controller, osc, persistence, ports, metronome: Metronome::new(beep_samples, state), track_matrix, selected_row: 0, selected_column: 0, last_volume_setting: 1.0, sample_rate: client.sample_rate(), tap_tempo: TapTempo::new(client.sample_rate()), }) } pub fn ports(&self) -> &JackPorts { &self.ports } pub fn handle_pedal_a(&mut self, value: u8) -> Result<()> { self.last_volume_setting = (value as f32) / 127.0; let controllers = TrackControllers::new( &self.post_record_controller, &self.osc, &self.persistence, self.sample_rate, self.selected_column, self.selected_row, ); self.track_matrix .handle_volume_update(self.last_volume_setting, &controllers) } pub fn handle_pedal_b(&mut self, value: u8) -> Result<()> { self.metronome .set_click_volume(value as f32 / 127.0, &mut self.persistence) } pub fn handle_button_1(&mut self) -> Result<()> { let controllers = TrackControllers::new( &self.post_record_controller, &self.osc, &self.persistence, self.sample_rate, self.selected_column, self.selected_row, ); self.track_matrix .handle_record_button(self.last_volume_setting, &controllers) } pub fn handle_button_2(&mut self) -> Result<()> { let controllers = TrackControllers::new( &self.post_record_controller, &self.osc, &self.persistence, self.sample_rate, self.selected_column, self.selected_row, ); self.track_matrix.handle_play_button(&controllers) } pub fn handle_button_3(&mut self) -> Result<()> { Ok(()) } pub fn handle_button_4(&mut self) -> Result<()> { let controllers = TrackControllers::new( &self.post_record_controller, &self.osc, &self.persistence, self.sample_rate, self.selected_column, self.selected_row, ); self.track_matrix.handle_clear_button(&controllers) } pub fn handle_button_5(&mut self, ps: &jack::ProcessScope) -> Result<()> { if !self.track_matrix.is_all_tracks_cleared() { // Ignore tap if not all tracks are clear return Ok(()); } let current_frame_time = ps.last_frame_time(); let tempo_updated = self.tap_tempo.handle_tap(current_frame_time); if let Some(frames_per_beat) = tempo_updated { // If tempo was updated, we need to update all columns with new frames_per_beat self.metronome.set_frames_per_beat(frames_per_beat); self.persistence .update_metronome_frames_per_beat(frames_per_beat)?; self.track_matrix.set_frames_per_beat(frames_per_beat); } Ok(()) } pub fn handle_button_6(&mut self) -> Result<()> { self.selected_column = 0; self.osc.selected_column_changed(self.selected_column)?; Ok(()) } pub fn handle_button_7(&mut self) -> Result<()> { self.selected_column = 1; self.osc.selected_column_changed(self.selected_column)?; Ok(()) } pub fn handle_button_8(&mut self) -> Result<()> { self.selected_column = 2; self.osc.selected_column_changed(self.selected_column)?; Ok(()) } pub fn handle_button_9(&mut self) -> Result<()> { self.selected_column = 3; self.osc.selected_column_changed(self.selected_column)?; Ok(()) } pub fn handle_button_10(&mut self) -> Result<()> { self.selected_column = 4; self.osc.selected_column_changed(self.selected_column)?; Ok(()) } pub fn handle_button_up(&mut self) -> Result<()> { if self.selected_row == 0 { self.selected_row = ROWS - 1; } else { self.selected_row -= 1; } self.osc.selected_row_changed(self.selected_row)?; Ok(()) } pub fn handle_button_down(&mut self) -> Result<()> { self.selected_row = (self.selected_row + 1) % ROWS; self.osc.selected_row_changed(self.selected_row)?; Ok(()) } } impl jack::ProcessHandler for ProcessHandler { fn process(&mut self, _client: &jack::Client, ps: &jack::ProcessScope) -> jack::Control { if let Err(e) = self.process_with_error_handling(ps) { log::error!("Error processing audio: {}", e); jack::Control::Quit } else { jack::Control::Continue } } } impl ProcessHandler { fn process_with_error_handling(&mut self, ps: &jack::ProcessScope) -> Result<()> { // Process metronome and get beat timing information let timing = self.metronome.process(ps, &mut self.ports, &self.osc)?; // Process MIDI midi::process_events(self, ps)?; // Process audio let controllers = MatrixControllers::new( &self.post_record_controller, &self.osc, &self.persistence, self.sample_rate, ); self.track_matrix .process(ps, &mut self.ports, &timing, &controllers)?; Ok(()) } }