use crossterm::event::{KeyCode, KeyEvent}; use std::sync::atomic::Ordering; use super::{InputContext, InputResult}; use crate::commands::AppCommand; use crate::engine::{AudioCommand, SeqCommand}; use crate::state::{ConfirmAction, DeviceKind, EngineSection, Modal, SettingKind}; pub(crate) fn cycle_engine_setting(ctx: &mut InputContext, right: bool) { let sign = if right { 1 } else { -1 }; match ctx.app.audio.setting_kind { SettingKind::Channels => ctx.dispatch(AppCommand::AdjustAudioSetting { setting: SettingKind::Channels, delta: sign, }), SettingKind::BufferSize => ctx.dispatch(AppCommand::AdjustAudioSetting { setting: SettingKind::BufferSize, delta: sign * 64, }), SettingKind::Polyphony => ctx.dispatch(AppCommand::AdjustAudioSetting { setting: SettingKind::Polyphony, delta: sign, }), SettingKind::Nudge => { let prev = ctx.nudge_us.load(Ordering::Relaxed); let new_val = prev + sign as i64 * 1000; ctx.nudge_us .store(new_val.clamp(-100_000, 100_000), Ordering::Relaxed); } } ctx.app.save_settings(ctx.link); } pub(super) fn handle_engine_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult { match key.code { KeyCode::Char('q') => { ctx.dispatch(AppCommand::OpenModal(Modal::Confirm { action: ConfirmAction::Quit, selected: false, })); } KeyCode::Tab => ctx.dispatch(AppCommand::AudioNextSection), KeyCode::BackTab => ctx.dispatch(AppCommand::AudioPrevSection), KeyCode::Up => match ctx.app.audio.section { EngineSection::Devices => match ctx.app.audio.device_kind { DeviceKind::Output => ctx.dispatch(AppCommand::AudioOutputListUp), DeviceKind::Input => ctx.dispatch(AppCommand::AudioInputListUp), }, EngineSection::Settings => { ctx.dispatch(AppCommand::AudioSettingPrev); } EngineSection::Samples => {} }, KeyCode::Down => match ctx.app.audio.section { EngineSection::Devices => match ctx.app.audio.device_kind { DeviceKind::Output => { let count = ctx.app.audio.output_devices.len(); ctx.dispatch(AppCommand::AudioOutputListDown(count)); } DeviceKind::Input => { let count = ctx.app.audio.input_devices.len(); ctx.dispatch(AppCommand::AudioInputListDown(count)); } }, EngineSection::Settings => { ctx.dispatch(AppCommand::AudioSettingNext); } EngineSection::Samples => {} }, KeyCode::PageUp => { if ctx.app.audio.section == EngineSection::Devices { match ctx.app.audio.device_kind { DeviceKind::Output => ctx.dispatch(AppCommand::AudioOutputPageUp), DeviceKind::Input => ctx.app.audio.input_list.page_up(), } } } KeyCode::PageDown => { if ctx.app.audio.section == EngineSection::Devices { match ctx.app.audio.device_kind { DeviceKind::Output => { let count = ctx.app.audio.output_devices.len(); ctx.dispatch(AppCommand::AudioOutputPageDown(count)); } DeviceKind::Input => { let count = ctx.app.audio.input_devices.len(); ctx.dispatch(AppCommand::AudioInputPageDown(count)); } } } } KeyCode::Enter => { if ctx.app.audio.section == EngineSection::Devices { match ctx.app.audio.device_kind { DeviceKind::Output => { let cursor = ctx.app.audio.output_list.cursor; if cursor < ctx.app.audio.output_devices.len() { let name = ctx.app.audio.output_devices[cursor].name.clone(); ctx.dispatch(AppCommand::SetOutputDevice(name)); ctx.app.save_settings(ctx.link); } } DeviceKind::Input => { let cursor = ctx.app.audio.input_list.cursor; if cursor < ctx.app.audio.input_devices.len() { let name = ctx.app.audio.input_devices[cursor].name.clone(); ctx.dispatch(AppCommand::SetInputDevice(name)); ctx.app.save_settings(ctx.link); } } } } } KeyCode::Left => match ctx.app.audio.section { EngineSection::Devices => { ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Output)); } EngineSection::Settings => cycle_engine_setting(ctx, false), EngineSection::Samples => {} }, KeyCode::Right => match ctx.app.audio.section { EngineSection::Devices => { ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Input)); } EngineSection::Settings => cycle_engine_setting(ctx, true), EngineSection::Samples => {} }, KeyCode::Char('R') => ctx.dispatch(AppCommand::AudioTriggerRestart), KeyCode::Char('A') => { use crate::state::file_browser::FileBrowserState; let state = FileBrowserState::new_load(String::new()); ctx.dispatch(AppCommand::OpenModal(Modal::AddSamplePath(Box::new(state)))); } KeyCode::Char('D') => { if ctx.app.audio.section == EngineSection::Samples { ctx.dispatch(AppCommand::RemoveLastSamplePath); } else { ctx.dispatch(AppCommand::AudioRefreshDevices); let out_count = ctx.app.audio.output_devices.len(); let in_count = ctx.app.audio.input_devices.len(); ctx.dispatch(AppCommand::SetStatus(format!( "Found {out_count} output, {in_count} input devices" ))); } } KeyCode::Char('h') => { let _ = ctx.audio_tx.load().send(AudioCommand::Hush); let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll); } KeyCode::Char('p') => { let _ = ctx.audio_tx.load().send(AudioCommand::Panic); let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll); } KeyCode::Char('r') => ctx.dispatch(AppCommand::ResetPeakVoices), KeyCode::Char('t') => { let _ = ctx.audio_tx.load().send(AudioCommand::Evaluate { cmd: "/sound/sine/dur/0.5/decay/0.2".into(), time: None, }); } KeyCode::Char('s') => super::open_save(ctx), KeyCode::Char('l') => super::open_load(ctx), KeyCode::Char('?') => { ctx.dispatch(AppCommand::OpenModal(Modal::KeybindingsHelp { scroll: 0 })); } KeyCode::Char(' ') => { ctx.dispatch(AppCommand::TogglePlaying); ctx.playing .store(ctx.app.playback.playing, Ordering::Relaxed); } _ => {} } InputResult::Continue }