fix struct fields and function signatures

This commit is contained in:
jess 2026-03-30 21:53:38 -07:00
parent d7c54c770b
commit a6d1018099
22 changed files with 482 additions and 4 deletions

View File

@ -72,6 +72,7 @@ impl Editor {
let config = crate::track::TrackConfig {
name: format!("{} - {}", region_label, name),
track_type: crate::track::TrackType::Audio,
input_buffer_size: self.project_config.input_buffer_size,
};
let track = Track::new(config, self.track_count);
self.track_count += 1;

View File

@ -40,6 +40,9 @@ impl Editor {
new_track_wizard::Message::TrackTypeSelected(track_type) => {
state.config.track_type = track_type
}
new_track_wizard::Message::InputBufferSizeSelected(size) => {
state.config.input_buffer_size = size
}
}
}
}

View File

@ -215,6 +215,11 @@ impl Editor {
&self.tracks,
&self.active_clips,
),
BottomPanelMode::Visualizer => {
iced::widget::column![
iced::widget::text("Visualizer").size(14),
].spacing(4).into()
}
};
container(panel_content)
.height(self.bottom_panel_height)

View File

@ -82,7 +82,7 @@ impl ModuleHost {
path: &Path,
config: &GlobalConfig,
) -> Option<(u32, String, Option<crate::modules::plugin_host::FramebufferGuiBridge>)> {
let (plugin, _load_info) = crate::modules::plugin_host::DynamicPlugin::load(path, config)?;
let (mut plugin, _load_info) = crate::modules::plugin_host::DynamicPlugin::load(path, config)?;
let id = self.next_id;
self.next_id += 1;

90
au-o2-gui/src/entry.rs Normal file
View File

@ -0,0 +1,90 @@
use std::path::PathBuf;
use chrono::NaiveDateTime;
use iced::{Element, Task};
use crate::gui::time_utility;
#[derive(Debug, Clone)]
pub struct ProjectInfo {
pub name: String,
pub path: PathBuf,
pub modified: NaiveDateTime,
}
#[derive(Debug, Clone)]
pub enum ProjectViewState {
Splash,
Recent { projects: Vec<ProjectInfo> },
Find { path_input: String },
}
pub enum AppState {
FirstRun { project_dir: PathBuf },
ProjectView(ProjectViewState),
NewProject(crate::gui::new_project::State),
TimeUtility { tapper_state: time_utility::State, return_state: Box<AppState> },
Editor(crate::editor::Editor),
}
#[derive(Debug, Clone)]
pub enum Message {
ViewRecentProjects,
ViewFindProject,
ViewNewProject,
ViewTimeUtility,
OpenProject(PathBuf),
CreateProject,
FindPathChanged(String),
ProjectNameChanged(String),
SampleRateSelected(u32),
OutputBufferSizeSelected(u32),
InputBufferSizeSelected(u32),
AudioDeviceSelected(String),
InputDeviceSelected(String),
TempoChanged(f32),
TimeSignatureNumeratorChanged(String),
TimeSignatureDenominatorChanged(String),
FirstRunProjectDirChanged(String),
FirstRunComplete,
TimeUtilityTapPressed,
TimeUtilityTapReleased,
TimeUtilitySet(u32),
TimeUtilitySetTimeSignature(String),
TimeUtilitySetBoth(u32, String),
TimeUtilityCancel,
RunTimeUtilityAnalysis,
EditorMessage(crate::editor::Message),
}
pub struct App {
pub state: AppState,
}
impl Default for App {
fn default() -> Self {
Self {
state: AppState::ProjectView(ProjectViewState::Splash),
}
}
}
pub fn main() -> iced::Result {
iced::application("Audio Oxide", App::update, App::view)
.run()
}
impl App {
fn update(&mut self, _message: Message) -> Task<Message> {
Task::none()
}
fn view(&self) -> Element<'_, Message> {
crate::gui::splash::view()
}
}

View File

@ -0,0 +1,26 @@
use crate::editor::Message;
use crate::track::Track;
use iced::widget::{column, container, text};
use iced::{Background, Color, Element, Length, Theme};
use std::collections::HashSet;
pub fn view<'a>(
tracks: &'a [Track],
_active_clips: &'a HashSet<uuid::Uuid>,
) -> Element<'a, Message> {
let content = column![
text("Clip Launcher").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
text(format!("{} tracks", tracks.len())).size(12),
]
.spacing(4)
.padding(8);
container(content)
.width(Length::Fill)
.height(Length::Fill)
.style(|_theme: &Theme| container::Style {
background: Some(Background::Color(Color::from_rgb8(0x28, 0x2A, 0x2C))),
..container::Style::default()
})
.into()
}

View File

@ -15,11 +15,17 @@ pub fn view<'a>(
cycle_enabled: bool,
metronome_enabled: bool,
count_in_enabled: bool,
_punch_enabled: bool,
record_armed: bool,
show_inspector: bool,
show_bottom_panel: bool,
bottom_panel_mode: &BottomPanelMode,
_show_tempo_lane: bool,
icons: &'a IconSet,
_lcd_editing: bool,
_lcd_bar_input: &str,
_lcd_beat_input: &str,
_lcd_tick_input: &str,
) -> Element<'a, Message> {
let is_playing = *transport == TransportState::Playing;

View File

@ -3,7 +3,14 @@ use crate::track::Track;
use iced::widget::{column, container, horizontal_rule, text};
use iced::{Background, Color, Element, Length, Theme};
pub fn view<'a>(selected_track: Option<&'a Track>) -> Element<'a, Message> {
pub fn view<'a>(
selected_track: Option<&'a Track>,
_selected_index: Option<usize>,
_h_zoom: f32,
_tempo: f32,
_time_sig_num: u8,
_wf_peaks: Option<&'a crate::waveform::WaveformPeaks>,
) -> Element<'a, Message> {
let header = text("Editor").size(16).color(Color::from_rgb8(0xAA, 0xAA, 0xAA));
let content = if let Some(track) = selected_track {

View File

@ -22,8 +22,16 @@ pub fn view<'a>(
module_names: &'a HashMap<u32, String>,
track_index: Option<usize>,
hilbert_fft_size: usize,
visualizer_buffer_size: usize,
_session_player_config: &'a crate::engine::session_player::SessionPlayerConfig,
_session_player_bars: u32,
_spatial_mode: crate::engine::atmos::SpatialRenderMode,
_mono_lane: crate::engine::atmos::MonoLane,
_sections: &InspectorSections,
_module_params: &'a crate::editor::ModuleParamState,
_modules_with_gui: &'a std::collections::HashSet<u32>,
_groups: &'a [crate::track::TrackGroup],
) -> Element<'a, Message> {
let visualizer_buffer_size: usize = 4096;
let header = text("Inspector").size(16).color(Color::from_rgb8(0xAA, 0xAA, 0xAA));
let content = if let Some(track) = selected_track {

View File

@ -25,7 +25,22 @@ fn pan_label(pan: f32) -> String {
}
}
pub fn view<'a>(tracks: &'a [Track], icons: &'a IconSet) -> Element<'a, Message> {
pub fn view<'a>(
tracks: &'a [Track],
_groups: &'a [crate::track::TrackGroup],
icons: &'a IconSet,
_module_names: &'a std::collections::HashMap<u32, String>,
_disabled_modules: &'a std::collections::HashSet<u32>,
_modules_with_gui: &'a std::collections::HashSet<u32>,
_module_picker_track: Option<usize>,
_send_picker_track: Option<usize>,
_master_volume: f32,
_master_pan: f32,
_meter_levels: &'a std::collections::HashMap<String, (f32, f32)>,
_master_meter: (f32, f32),
_discovered_plugins: &'a [crate::modules::plugin_host::PluginInfo],
_show_network_view: bool,
) -> Element<'a, Message> {
let header = container(
text("Mixer").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
)

View File

@ -1,8 +1,11 @@
pub mod clip_launcher;
pub mod control_bar;
pub mod editor_pane;
pub mod inspector;
pub mod mixer;
pub mod new_track_wizard;
pub mod score;
pub mod step_seq;
pub mod timeline;
pub mod toolbar;
pub mod track_header;

View File

@ -0,0 +1,47 @@
use crate::editor::Message;
use crate::track::Track;
use iced::widget::{column, container, text};
use iced::{Background, Color, Element, Length, Theme};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScoreNoteDuration {
Whole,
Half,
Quarter,
Eighth,
Sixteenth,
}
pub fn view<'a>(
selected_track: Option<&'a Track>,
_selected_index: Option<usize>,
_h_zoom: f32,
_tempo: f32,
_time_sig_num: u8,
_note_duration: ScoreNoteDuration,
) -> Element<'a, Message> {
let content = if let Some(track) = selected_track {
column![
text("Score Editor").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
text(format!("{} - Score View", track.name)).size(12),
]
.spacing(4)
.padding(8)
} else {
column![
text("Score Editor").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
text("Select a track").size(12).color(Color::from_rgb8(0x77, 0x77, 0x77)),
]
.spacing(4)
.padding(8)
};
container(content)
.width(Length::Fill)
.height(Length::Fill)
.style(|_theme: &Theme| container::Style {
background: Some(Background::Color(Color::from_rgb8(0x28, 0x2A, 0x2C))),
..container::Style::default()
})
.into()
}

View File

@ -0,0 +1,20 @@
use iced::widget::{column, text};
use iced::Element;
use crate::editor::Message;
use crate::track::Track;
pub fn view<'a>(
_selected_track: Option<&'a Track>,
_track_index: Option<usize>,
_h_zoom: f32,
_tempo: f32,
_time_sig_numerator: u8,
_pattern_length: usize,
) -> Element<'a, Message> {
column![
text("Step Sequencer").size(14),
]
.spacing(4)
.into()
}

View File

@ -76,6 +76,12 @@ pub fn view<'a>(
v_zoom: f32,
recording: bool,
waveforms: &'a WaveformCache,
_cycle_enabled: bool,
_cycle_start_bar: u32,
_cycle_end_bar: u32,
_markers: &'a [crate::timing::Marker],
_tempo_map: &'a crate::timing::TempoMap,
_show_tempo_lane: bool,
) -> Element<'a, Message> {
let effective_track_height = TRACK_HEIGHT * v_zoom;
let timeline_height = tracks.len() as f32 * effective_track_height;

View File

@ -2,10 +2,12 @@ pub mod editor;
pub mod first_run_wizard;
pub mod icon_button;
pub mod icons;
pub mod module_window;
pub mod native_menu;
pub mod new_project;
pub mod project_viewer;
pub mod settings;
pub mod splash;
pub mod styles;
pub mod theme;
pub mod time_utility;

View File

@ -0,0 +1,110 @@
use std::collections::HashMap;
use iced::window;
use iced::{Element, Task};
use oxforge::mdk::gui::AudioFenceHandle;
use oxforge::mdk::{GuiToolkit, ModuleGuiDescriptor, ParameterDescriptor};
use crate::editor::Message;
use crate::modules::plugin_host::FramebufferGuiBridge;
pub struct ModuleWindowManager {
windows: HashMap<u32, ModuleWindowState>,
window_to_module: HashMap<window::Id, u32>,
}
struct ModuleWindowState {
window_id: window::Id,
module_name: String,
_gui_desc: ModuleGuiDescriptor,
fence: AudioFenceHandle,
_bridge: Option<FramebufferGuiBridge>,
}
impl ModuleWindowManager {
pub fn new() -> Self {
Self {
windows: HashMap::new(),
window_to_module: HashMap::new(),
}
}
pub fn is_open(&self, module_id: u32) -> bool {
self.windows.contains_key(&module_id)
}
pub fn open(
&mut self,
module_id: u32,
module_name: String,
gui_desc: ModuleGuiDescriptor,
_descriptors: &[ParameterDescriptor],
_toolkit: GuiToolkit,
bridge: Option<FramebufferGuiBridge>,
) -> (window::Id, Task<Message>, AudioFenceHandle) {
let fence = AudioFenceHandle::new();
let (id, task) = window::open(window::Settings {
size: iced::Size::new(gui_desc.width as f32, gui_desc.height as f32),
..window::Settings::default()
});
self.window_to_module.insert(id, module_id);
self.windows.insert(module_id, ModuleWindowState {
window_id: id,
module_name,
_gui_desc: gui_desc,
fence: fence.clone(),
_bridge: bridge,
});
(id, task.discard(), fence)
}
pub fn close(&mut self, module_id: u32) -> Option<Task<Message>> {
if let Some(state) = self.windows.remove(&module_id) {
self.window_to_module.remove(&state.window_id);
let task: Task<Message> = window::close::<Message>(state.window_id).discard();
return Some(task);
}
None
}
pub fn module_for_window(&self, window_id: window::Id) -> Option<u32> {
self.window_to_module.get(&window_id).copied()
}
pub fn view(&self, _window_id: window::Id) -> Option<Element<'_, Message>> {
None
}
pub fn window_title(&self, window_id: window::Id) -> Option<String> {
let module_id = self.window_to_module.get(&window_id)?;
let state = self.windows.get(module_id)?;
Some(state.module_name.clone())
}
pub fn framebuffer_mouse_down(&self, _module_id: u32, _x: i32, _y: i32) {}
pub fn framebuffer_mouse_up(&self, _module_id: u32, _x: i32, _y: i32) {}
pub fn resize_framebuffer(&mut self, _module_id: u32, _width: u32, _height: u32) {}
pub fn write_param(&mut self, module_id: u32, key: &str, value: f32) {
if let Some(state) = self.windows.get(&module_id) {
state.fence.push_change(key.to_string(), value);
}
}
pub fn receive_visualization(&mut self, _module_id: u32, _data: Vec<u8>) {}
pub fn poll_fence_changes(&mut self) -> Vec<(u32, String, f32)> {
let mut changes = Vec::new();
for (&module_id, state) in &mut self.windows {
let current = state.fence.read_current();
for (key, value) in current {
changes.push((module_id, key, value));
}
}
changes
}
pub fn tick_framebuffers(&mut self) {}
}

View File

@ -44,6 +44,9 @@ impl Default for State {
time_signature_numerator: 4,
time_signature_denominator: 4,
tracks: Vec::new(),
markers: Vec::new(),
tempo_points: Vec::new(),
groups: Vec::new(),
},
available_output_devices: output_devices,
available_input_devices: input_devices,

View File

@ -0,0 +1,37 @@
use iced::Color;
pub const BG_DEEPEST: Color = Color::from_rgb(0.08, 0.08, 0.09);
pub const BG_DARKER: Color = Color::from_rgb(0.12, 0.12, 0.14);
pub const BG_BASE: Color = Color::from_rgb(0.16, 0.17, 0.18);
pub const BG_MID: Color = Color::from_rgb(0.19, 0.20, 0.21);
pub const TEXT_BRIGHT: Color = Color::from_rgb(0.90, 0.90, 0.90);
pub const TEXT_MUTED: Color = Color::from_rgb(0.55, 0.55, 0.55);
pub const BORDER_SUBTLE: Color = Color::from_rgb(0.22, 0.23, 0.24);
pub const BORDER_LIGHT: Color = Color::from_rgb(0.30, 0.31, 0.32);
pub const PINK: Color = Color::from_rgb(0.85, 0.25, 0.35);
pub const ICON_TINT: Color = Color::from_rgb(0.95, 0.75, 0.20);
pub const TS_SM: f32 = 10.0;
pub const TS_MD: f32 = 13.0;
pub const TS_XL: f32 = 22.0;
pub const SP_XS: f32 = 4.0;
pub const SP_MD: f32 = 8.0;
pub const SP_LG: f32 = 16.0;
pub const SP_XXL: f32 = 24.0;
pub const RESIZE_HANDLE_WIDTH: f32 = 6.0;
pub const RESIZE_HANDLE_HEIGHT: f32 = 6.0;
pub const BOTTOM_PANEL_MIN: f32 = 100.0;
pub const BOTTOM_PANEL_MAX: f32 = 800.0;
pub const TRACKLIST_WIDTH_MIN: f32 = 120.0;
pub const TRACKLIST_WIDTH_MAX: f32 = 400.0;
pub const INSPECTOR_WIDTH: f32 = 230.0;
pub const INSPECTOR_WIDTH_MIN: f32 = 180.0;
pub const INSPECTOR_WIDTH_MAX: f32 = 400.0;

View File

@ -1,3 +1,4 @@
pub mod plugin_host;
pub mod registry;
pub use oxforge::mdk::{AnalyticSignal, PhasePoint, VisualizationFrame};

View File

@ -0,0 +1,80 @@
use oxforge::mdk::{
GlobalConfig, ModuleContract, OxideModule,
ParameterDescriptor, PortDeclaration, Ports, ProcessContext,
};
use std::any::Any;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct PluginInfo {
pub name: String,
pub display_name: String,
pub path: std::path::PathBuf,
}
#[derive(Clone)]
pub struct FramebufferGuiBridge {
pub width: u32,
pub height: u32,
}
impl std::fmt::Debug for FramebufferGuiBridge {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FramebufferGuiBridge")
.field("width", &self.width)
.field("height", &self.height)
.finish()
}
}
pub struct DynamicPlugin {
info: PluginInfo,
bridge: Option<FramebufferGuiBridge>,
}
impl DynamicPlugin {
pub fn load(_path: &Path, _config: &GlobalConfig) -> Option<(Self, PluginInfo)> {
None
}
pub fn info(&self) -> &PluginInfo {
&self.info
}
pub fn contract(&self) -> ModuleContract {
ModuleContract::default()
}
pub fn port_declarations(&self) -> Vec<PortDeclaration> {
Vec::new()
}
pub fn take_framebuffer_bridge(&mut self) -> Option<FramebufferGuiBridge> {
self.bridge.take()
}
}
impl OxideModule for DynamicPlugin {
fn new(_config: &GlobalConfig) -> Self where Self: Sized {
Self {
info: PluginInfo {
name: String::new(),
display_name: String::new(),
path: std::path::PathBuf::new(),
},
bridge: None,
}
}
fn process(&mut self, _ports: Ports, _context: &ProcessContext) {}
fn receive_data(&mut self, _key: &str, _data: Box<dyn Any + Send>) {}
fn param_descriptors(&self) -> Vec<ParameterDescriptor> {
Vec::new()
}
}
pub fn scan_all_plugins() -> Vec<PluginInfo> {
Vec::new()
}

View File

@ -86,6 +86,7 @@ impl std::fmt::Display for TrackType {
pub struct TrackConfig {
pub name: String,
pub track_type: TrackType,
pub input_buffer_size: u32,
}
impl Default for TrackConfig {
@ -93,6 +94,7 @@ impl Default for TrackConfig {
Self {
name: "New Track".to_string(),
track_type: TrackType::Audio,
input_buffer_size: 512,
}
}
}

View File

@ -7,6 +7,12 @@ pub struct AudioFenceHandle {
audio_to_gui: Arc<Mutex<HashMap<String, f32>>>,
}
impl std::fmt::Debug for AudioFenceHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioFenceHandle").finish()
}
}
impl AudioFenceHandle {
pub fn new() -> Self {
Self {