wip
This commit is contained in:
203
seq/src/app.rs
203
seq/src/app.rs
@@ -1,3 +1,4 @@
|
||||
use doux::audio::AudioDeviceInfo;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use std::collections::HashMap;
|
||||
@@ -20,6 +21,12 @@ pub enum Focus {
|
||||
Editor,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PatternField {
|
||||
Length,
|
||||
Speed,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum Modal {
|
||||
None,
|
||||
@@ -28,6 +35,8 @@ pub enum Modal {
|
||||
LoadFrom(String),
|
||||
RenameBank { bank: usize, name: String },
|
||||
RenamePattern { bank: usize, pattern: usize, name: String },
|
||||
SetPattern { field: PatternField, input: String },
|
||||
AddSamplePath(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
@@ -37,6 +46,41 @@ pub enum PatternsViewLevel {
|
||||
Patterns { bank: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AudioConfig {
|
||||
pub output_device: Option<String>,
|
||||
pub input_device: Option<String>,
|
||||
pub channels: u16,
|
||||
pub buffer_size: u32,
|
||||
pub sample_rate: f32,
|
||||
pub sample_paths: Vec<PathBuf>,
|
||||
pub sample_count: usize,
|
||||
}
|
||||
|
||||
impl Default for AudioConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
output_device: None,
|
||||
input_device: None,
|
||||
channels: 2,
|
||||
buffer_size: 512,
|
||||
sample_rate: 44100.0,
|
||||
sample_paths: Vec::new(),
|
||||
sample_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum AudioFocus {
|
||||
#[default]
|
||||
OutputDevice,
|
||||
InputDevice,
|
||||
Channels,
|
||||
BufferSize,
|
||||
SamplePaths,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub tempo: f64,
|
||||
pub beat: f64,
|
||||
@@ -80,6 +124,12 @@ pub struct App {
|
||||
pub clipboard: Option<arboard::Clipboard>,
|
||||
pub doc_topic: usize,
|
||||
pub doc_scroll: usize,
|
||||
|
||||
pub audio_config: AudioConfig,
|
||||
pub audio_focus: AudioFocus,
|
||||
pub available_output_devices: Vec<AudioDeviceInfo>,
|
||||
pub available_input_devices: Vec<AudioDeviceInfo>,
|
||||
pub restart_pending: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -125,6 +175,12 @@ impl App {
|
||||
clipboard: arboard::Clipboard::new().ok(),
|
||||
doc_topic: 0,
|
||||
doc_scroll: 0,
|
||||
|
||||
audio_config: AudioConfig::default(),
|
||||
audio_focus: AudioFocus::default(),
|
||||
available_output_devices: doux::audio::list_output_devices(),
|
||||
available_input_devices: doux::audio::list_input_devices(),
|
||||
restart_pending: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,4 +547,151 @@ impl App {
|
||||
self.compile_current_step();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_pattern_modal(&mut self, field: PatternField) {
|
||||
let current = match field {
|
||||
PatternField::Length => self.current_edit_pattern().length.to_string(),
|
||||
PatternField::Speed => self.current_edit_pattern().speed.label().to_string(),
|
||||
};
|
||||
self.modal = Modal::SetPattern { field, input: current };
|
||||
}
|
||||
|
||||
pub fn refresh_audio_devices(&mut self) {
|
||||
self.available_output_devices = doux::audio::list_output_devices();
|
||||
self.available_input_devices = doux::audio::list_input_devices();
|
||||
}
|
||||
|
||||
pub fn next_audio_focus(&mut self) {
|
||||
self.audio_focus = match self.audio_focus {
|
||||
AudioFocus::OutputDevice => AudioFocus::InputDevice,
|
||||
AudioFocus::InputDevice => AudioFocus::Channels,
|
||||
AudioFocus::Channels => AudioFocus::BufferSize,
|
||||
AudioFocus::BufferSize => AudioFocus::SamplePaths,
|
||||
AudioFocus::SamplePaths => AudioFocus::OutputDevice,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prev_audio_focus(&mut self) {
|
||||
self.audio_focus = match self.audio_focus {
|
||||
AudioFocus::OutputDevice => AudioFocus::SamplePaths,
|
||||
AudioFocus::InputDevice => AudioFocus::OutputDevice,
|
||||
AudioFocus::Channels => AudioFocus::InputDevice,
|
||||
AudioFocus::BufferSize => AudioFocus::Channels,
|
||||
AudioFocus::SamplePaths => AudioFocus::BufferSize,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next_output_device(&mut self) {
|
||||
if self.available_output_devices.is_empty() {
|
||||
return;
|
||||
}
|
||||
let current_idx = self.current_output_device_index();
|
||||
let next_idx = (current_idx + 1) % self.available_output_devices.len();
|
||||
self.audio_config.output_device = Some(self.available_output_devices[next_idx].name.clone());
|
||||
}
|
||||
|
||||
pub fn prev_output_device(&mut self) {
|
||||
if self.available_output_devices.is_empty() {
|
||||
return;
|
||||
}
|
||||
let current_idx = self.current_output_device_index();
|
||||
let prev_idx = (current_idx + self.available_output_devices.len() - 1) % self.available_output_devices.len();
|
||||
self.audio_config.output_device = Some(self.available_output_devices[prev_idx].name.clone());
|
||||
}
|
||||
|
||||
fn current_output_device_index(&self) -> usize {
|
||||
match &self.audio_config.output_device {
|
||||
Some(name) => self
|
||||
.available_output_devices
|
||||
.iter()
|
||||
.position(|d| &d.name == name)
|
||||
.unwrap_or(0),
|
||||
None => self
|
||||
.available_output_devices
|
||||
.iter()
|
||||
.position(|d| d.is_default)
|
||||
.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_input_device(&mut self) {
|
||||
if self.available_input_devices.is_empty() {
|
||||
return;
|
||||
}
|
||||
let current_idx = self.current_input_device_index();
|
||||
let next_idx = (current_idx + 1) % self.available_input_devices.len();
|
||||
self.audio_config.input_device = Some(self.available_input_devices[next_idx].name.clone());
|
||||
}
|
||||
|
||||
pub fn prev_input_device(&mut self) {
|
||||
if self.available_input_devices.is_empty() {
|
||||
return;
|
||||
}
|
||||
let current_idx = self.current_input_device_index();
|
||||
let prev_idx = (current_idx + self.available_input_devices.len() - 1) % self.available_input_devices.len();
|
||||
self.audio_config.input_device = Some(self.available_input_devices[prev_idx].name.clone());
|
||||
}
|
||||
|
||||
fn current_input_device_index(&self) -> usize {
|
||||
match &self.audio_config.input_device {
|
||||
Some(name) => self
|
||||
.available_input_devices
|
||||
.iter()
|
||||
.position(|d| &d.name == name)
|
||||
.unwrap_or(0),
|
||||
None => self
|
||||
.available_input_devices
|
||||
.iter()
|
||||
.position(|d| d.is_default)
|
||||
.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_channels(&mut self, delta: i16) {
|
||||
let new_val = (self.audio_config.channels as i16 + delta).clamp(1, 64) as u16;
|
||||
self.audio_config.channels = new_val;
|
||||
}
|
||||
|
||||
pub fn adjust_buffer_size(&mut self, delta: i32) {
|
||||
let new_val = (self.audio_config.buffer_size as i32 + delta).clamp(64, 4096) as u32;
|
||||
self.audio_config.buffer_size = new_val;
|
||||
}
|
||||
|
||||
pub fn trigger_restart(&mut self) {
|
||||
self.restart_pending = true;
|
||||
}
|
||||
|
||||
pub fn current_output_device_name(&self) -> &str {
|
||||
match &self.audio_config.output_device {
|
||||
Some(name) => name,
|
||||
None => self
|
||||
.available_output_devices
|
||||
.iter()
|
||||
.find(|d| d.is_default)
|
||||
.map(|d| d.name.as_str())
|
||||
.unwrap_or("Default"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_input_device_name(&self) -> &str {
|
||||
match &self.audio_config.input_device {
|
||||
Some(name) => name,
|
||||
None => self
|
||||
.available_input_devices
|
||||
.iter()
|
||||
.find(|d| d.is_default)
|
||||
.map(|d| d.name.as_str())
|
||||
.unwrap_or("None"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sample_path(&mut self, path: PathBuf) {
|
||||
if !self.audio_config.sample_paths.contains(&path) {
|
||||
self.audio_config.sample_paths.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_last_sample_path(&mut self) {
|
||||
self.audio_config.sample_paths.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user