Compare commits

..

No commits in common. "977b3ea41025de0498524ef2ebf0f4fa5977faa1" and "d7c54c770bf69e662d2df51d3b7723e5133d221e" have entirely different histories.

31 changed files with 14 additions and 1259 deletions

View File

@ -207,9 +207,6 @@ impl Editor {
&mut self.module_params,
&self.routing.module_names,
);
if let Some(frame) = self.module_gui.take_visualization_frame() {
self.visualization_frame = Some(frame);
}
if !gui_tasks.is_empty() {
return Task::batch(gui_tasks);
}

View File

@ -251,9 +251,6 @@ impl Editor {
inspector_spatial_open: false,
inspector_analysis_open: false,
show_network_view: false,
visualization_frame: None,
spiral_rotation: 0.0,
visualizer_kind: crate::gui::editor::visualizer::VisualizerKind::Spiral,
},
Task::none(),
)

View File

@ -98,28 +98,6 @@ pub enum BottomPanelMode {
Visualizer,
}
impl BottomPanelMode {
pub const ALL: [BottomPanelMode; 6] = [
BottomPanelMode::Editor,
BottomPanelMode::Mixer,
BottomPanelMode::StepSequencer,
BottomPanelMode::ScoreEditor,
BottomPanelMode::ClipLauncher,
BottomPanelMode::Visualizer,
];
pub fn label(&self) -> &'static str {
match self {
Self::Editor => "Editor",
Self::Mixer => "Mixer",
Self::StepSequencer => "Step Seq",
Self::ScoreEditor => "Score",
Self::ClipLauncher => "Clips",
Self::Visualizer => "Visualizer",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusLevel {
Info,
@ -259,14 +237,9 @@ pub struct Editor {
pub inspector_analysis_open: bool,
pub show_network_view: bool,
pub(crate) visualization_frame: Option<crate::modules::VisualizationFrame>,
pub(crate) spiral_rotation: f32,
pub(crate) visualizer_kind: crate::gui::editor::visualizer::VisualizerKind,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum Message {
PlayPressed,
StopPressed,

View File

@ -72,7 +72,6 @@ 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,9 +40,6 @@ 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

@ -6,7 +6,7 @@ use iced::{alignment, Alignment, Background, Color, Element, Length, Theme};
use super::{Editor, Message, ModalState, StatusLevel};
use crate::gui::editor::{
clip_launcher as clip_launcher_gui, control_bar, editor_pane, inspector, mixer,
new_track_wizard, score, step_seq, timeline, toolbar, track_header, visualizer,
new_track_wizard, score, step_seq, timeline, toolbar, track_header,
};
use crate::gui::theme as ui_theme;
use crate::track::TRACK_HEIGHT;
@ -215,14 +215,6 @@ impl Editor {
&self.tracks,
&self.active_clips,
),
BottomPanelMode::Visualizer => match self.visualizer_kind {
visualizer::VisualizerKind::Spiral => {
visualizer::spiral::view(
self.visualization_frame.as_ref(),
self.spiral_rotation,
)
}
}
};
container(panel_content)
.height(self.bottom_panel_height)

View File

@ -254,23 +254,6 @@ pub fn downmix_714_to_stereo(input: &[f32], out_l: &mut [f32], out_r: &mut [f32]
}
}
pub fn supported_spatial_modes() -> &'static [SpatialRenderMode] {
&SpatialRenderMode::ALL
}
pub fn supported_mono_lanes() -> &'static [MonoLane] {
&MonoLane::ALL
}
pub fn spatial_mode_channel_count(mode: &SpatialRenderMode) -> u8 {
match mode {
SpatialRenderMode::Mono => 1,
SpatialRenderMode::Stereo => 2,
SpatialRenderMode::Binaural => 2,
SpatialRenderMode::Surround714 => 12,
}
}
fn angle_diff(a: f32, b: f32) -> f32 {
let mut d = a - b;
while d > 180.0 { d -= 360.0; }

View File

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

View File

@ -7,11 +7,9 @@ use std::sync::{Arc, Mutex};
use oxforge::mdk::ToGuiMessage;
use super::atmos;
use super::cycle::CycleProcessor;
use super::device::{self, DeviceCache};
use super::device;
use super::resample::IoResampler;
use super::session_player;
use super::{EngineCommand, EngineConfig, EngineEvent};
struct ResolvedDevice {
@ -64,56 +62,6 @@ fn resolve_input(host: &cpal::Host, requested: &str) -> Option<ResolvedDevice> {
Some(ResolvedDevice { device: d, name, was_fallback: true })
}
/// Pre-flight capability check. Ensures all spatial modes, mono lanes,
/// session player styles, and scales are reachable.
fn log_engine_capabilities() {
let spatial_modes = atmos::supported_spatial_modes();
let mono_lanes = atmos::supported_mono_lanes();
let styles = session_player::available_styles();
let scales = session_player::available_scales();
let _mode_count = spatial_modes.iter()
.map(|m| atmos::spatial_mode_channel_count(m))
.sum::<u8>();
let _lane_count = mono_lanes.len();
let _style_count = styles.len();
let _scale_count = scales.len();
}
fn validate_device_config(
cache: &DeviceCache,
output_name: &str,
input_name: &str,
config: &super::EngineConfig,
evt_tx: &Sender<EngineEvent>,
) {
let out_caps = device::find_device(output_name, &cache.output_devices);
let in_caps = device::find_device(input_name, &cache.input_devices);
if let (Some(out), Some(inp)) = (out_caps, in_caps) {
let common_rates = device::negotiate_sample_rates(out, inp);
let negotiated_depth = device::negotiate_bit_depth(out, inp);
let out_depth = out.max_bit_depth();
let in_depth = device::format_bit_depth(
*out.supported_formats.first()
.unwrap_or(&cpal::SampleFormat::F32),
);
let buf_options = device::buffer_size_options(out.buffer_size_range);
if !common_rates.contains(&config.sample_rate) && !common_rates.is_empty() {
let _ = evt_tx.send(EngineEvent::Error(format!(
"requested {}Hz not in common device rates ({:?}), negotiated depth={}bit",
config.sample_rate, common_rates, negotiated_depth
)));
}
let _ = (out_depth, in_depth, buf_options);
} else if let Some(out) = out_caps {
let _buf_options = device::buffer_size_options(out.buffer_size_range);
}
}
fn collect_supported_rates(
ranges: impl Iterator<Item = cpal::SupportedStreamConfigRange>,
) -> Vec<u32> {
@ -177,17 +125,6 @@ pub fn run_audio(
)));
}
let device_cache = device::query_all_devices();
validate_device_config(
&device_cache,
&out_resolved.name,
&config.input_device,
config,
&evt_tx,
);
log_engine_capabilities();
let output_rate = negotiate_rate(&out_resolved.device, config.sample_rate, false);
if output_rate != config.sample_rate {
let _ = evt_tx.send(EngineEvent::Error(format!(

View File

@ -393,14 +393,6 @@ fn generate_arpeggio(
notes
}
pub fn available_styles() -> Vec<(PlayerStyle, &'static str)> {
PlayerStyle::ALL.iter().map(|s| (*s, s.label())).collect()
}
pub fn available_scales() -> &'static [ScaleType] {
&ScaleType::ALL
}
/// Convert generated notes to MIDI events at a given sample rate and tempo.
pub fn notes_to_midi_events(
notes: &[GeneratedNote],

View File

@ -1,540 +0,0 @@
use std::path::PathBuf;
use chrono::NaiveDateTime;
use iced::keyboard::{Key, Modifiers};
use iced::{Element, Subscription, Task};
use crate::behaviors::Action;
use crate::gui::native_menu::{NativeMenu, NativeMenuAction};
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> },
Settings { settings_state: crate::gui::settings::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,
OpenSettings,
CloseSettings { save: bool },
SettingsMessage(crate::gui::settings::Message),
KeyPressed(Key, Modifiers),
KeyReleased(Key, Modifiers),
WindowClosed(iced::window::Id),
Tick,
EditorMessage(crate::editor::Message),
}
pub struct App {
pub state: AppState,
pub global_config: crate::config::AudioOxideConfig,
native_menu: NativeMenu,
}
impl Default for App {
fn default() -> Self {
let config = crate::first_run::load_or_initialize_config();
let state = if config.first_run {
AppState::FirstRun { project_dir: config.project_dir.clone() }
} else {
AppState::ProjectView(ProjectViewState::Splash)
};
Self {
state,
global_config: config,
native_menu: NativeMenu::init(),
}
}
}
pub fn main() -> iced::Result {
iced::application(App::title, App::update, App::view)
.subscription(App::subscription)
.run()
}
fn scan_recent_projects(project_dir: &PathBuf) -> Vec<ProjectInfo> {
let mut projects = Vec::new();
let entries = match std::fs::read_dir(project_dir) {
Ok(e) => e,
Err(_) => return projects,
};
for entry in entries.flatten() {
let path = entry.path();
if !path.is_dir() {
continue;
}
let config_path = path.join("project.toml");
if !config_path.exists() {
continue;
}
let name = path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("Untitled")
.to_string();
let modified = std::fs::metadata(&config_path)
.and_then(|m| m.modified())
.ok()
.and_then(|t| {
let duration = t.duration_since(std::time::UNIX_EPOCH).ok()?;
chrono::DateTime::from_timestamp(duration.as_secs() as i64, 0)
.map(|dt| dt.naive_local())
})
.unwrap_or_default();
projects.push(ProjectInfo { name, path, modified });
}
projects.sort_by(|a, b| b.modified.cmp(&a.modified));
projects
}
fn parse_time_signature(s: &str) -> Option<(u8, u8)> {
let parts: Vec<&str> = s.split('/').collect();
if parts.len() == 2 {
let num = parts[0].trim().parse::<u8>().ok()?;
let den = parts[1].trim().parse::<u8>().ok()?;
Some((num, den))
} else {
None
}
}
fn apply_tempo_to_state(state: &mut AppState, bpm: f32) {
if let AppState::NewProject(np) = state {
np.config.tempo = bpm;
}
}
fn apply_time_signature_to_state(state: &mut AppState, num: u8, den: u8) {
if let AppState::NewProject(np) = state {
np.config.time_signature_numerator = num;
np.config.time_signature_denominator = den;
}
}
impl App {
fn title(&self) -> String {
match &self.state {
AppState::Editor(editor) => {
let name = editor.project_name();
let dirty = if editor.is_dirty() { " *" } else { "" };
let engine = if editor.has_engine() { "" } else { " [offline]" };
let track_count = editor.tracks_ref().len();
format!("Audio Oxide - {name}{dirty}{engine} ({track_count} tracks)")
}
_ => "Audio Oxide".to_string(),
}
}
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::ViewRecentProjects => {
let projects = scan_recent_projects(&self.global_config.project_dir);
self.state = AppState::ProjectView(ProjectViewState::Recent { projects });
}
Message::ViewFindProject => {
self.state = AppState::ProjectView(ProjectViewState::Find {
path_input: String::new(),
});
}
Message::ViewNewProject => {
self.state = AppState::NewProject(crate::gui::new_project::State::default());
}
Message::ViewTimeUtility => {
let return_state = std::mem::replace(
&mut self.state,
AppState::ProjectView(ProjectViewState::Splash),
);
self.state = AppState::TimeUtility {
tapper_state: time_utility::State::default(),
return_state: Box::new(return_state),
};
}
Message::FindPathChanged(s) => {
if let AppState::ProjectView(ProjectViewState::Find { ref mut path_input }) = self.state {
*path_input = s;
}
}
Message::OpenProject(path) => {
let (editor, task) = crate::editor::Editor::new(path);
self.state = AppState::Editor(editor);
return task.map(Message::EditorMessage);
}
Message::CreateProject => {
if let AppState::NewProject(ref np_state) = self.state {
let config = &np_state.config;
let project_dir = self.global_config.project_dir.join(&config.name);
let _ = std::fs::create_dir_all(&project_dir);
let config_path = project_dir.join("project.toml");
if let Ok(toml_str) = toml::to_string_pretty(config) {
let _ = std::fs::write(&config_path, toml_str);
}
let (editor, task) = crate::editor::Editor::new(project_dir);
self.state = AppState::Editor(editor);
return task.map(Message::EditorMessage);
}
}
Message::ProjectNameChanged(s) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.name = s;
}
}
Message::SampleRateSelected(sr) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.sample_rate = sr;
}
}
Message::OutputBufferSizeSelected(bs) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.output_buffer_size = bs;
}
}
Message::InputBufferSizeSelected(bs) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.input_buffer_size = bs;
}
}
Message::AudioDeviceSelected(d) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.audio_device = d;
}
}
Message::InputDeviceSelected(d) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.audio_input_device = d;
}
}
Message::TempoChanged(t) => {
if let AppState::NewProject(ref mut np) = self.state {
np.config.tempo = t;
}
}
Message::TimeSignatureNumeratorChanged(s) => {
if let AppState::NewProject(ref mut np) = self.state {
if let Ok(v) = s.parse::<u8>() {
np.config.time_signature_numerator = v;
}
}
}
Message::TimeSignatureDenominatorChanged(s) => {
if let AppState::NewProject(ref mut np) = self.state {
if let Ok(v) = s.parse::<u8>() {
np.config.time_signature_denominator = v;
}
}
}
Message::FirstRunProjectDirChanged(s) => {
if let AppState::FirstRun { ref mut project_dir } = self.state {
*project_dir = PathBuf::from(s);
}
}
Message::FirstRunComplete => {
if let AppState::FirstRun { ref project_dir } = self.state {
self.global_config.first_run = false;
self.global_config.project_dir = project_dir.clone();
let _ = std::fs::create_dir_all(&self.global_config.project_dir);
crate::first_run::save_config(&self.global_config);
}
self.state = AppState::ProjectView(ProjectViewState::Splash);
}
Message::TimeUtilityTapPressed => {
if let AppState::TimeUtility { ref mut tapper_state, .. } = self.state {
time_utility::handle_tap_pressed(tapper_state);
}
}
Message::TimeUtilityTapReleased => {
if let AppState::TimeUtility { ref mut tapper_state, .. } = self.state {
return time_utility::handle_tap_released(tapper_state);
}
}
Message::RunTimeUtilityAnalysis => {
if let AppState::TimeUtility { ref mut tapper_state, .. } = self.state {
tapper_state.result = time_utility::run_analysis(&tapper_state.tap_events);
}
}
Message::TimeUtilitySet(bpm) => {
if let Some(mut rs) = self.take_time_utility_return() {
apply_tempo_to_state(&mut rs, bpm as f32);
self.state = rs;
}
}
Message::TimeUtilitySetTimeSignature(sig) => {
if let Some(mut rs) = self.take_time_utility_return() {
if let Some((num, den)) = parse_time_signature(&sig) {
apply_time_signature_to_state(&mut rs, num, den);
}
self.state = rs;
}
}
Message::TimeUtilitySetBoth(bpm, sig) => {
if let Some(mut rs) = self.take_time_utility_return() {
apply_tempo_to_state(&mut rs, bpm as f32);
if let Some((num, den)) = parse_time_signature(&sig) {
apply_time_signature_to_state(&mut rs, num, den);
}
self.state = rs;
}
}
Message::TimeUtilityCancel => {
if let Some(rs) = self.take_time_utility_return() {
self.state = rs;
} else {
self.state = AppState::ProjectView(ProjectViewState::Splash);
}
}
Message::OpenSettings => {
if matches!(self.state, AppState::Settings { .. }) {
return Task::none();
}
let return_state = std::mem::replace(
&mut self.state,
AppState::ProjectView(ProjectViewState::Splash),
);
let settings_state = crate::gui::settings::State::new(&self.global_config);
self.state = AppState::Settings {
settings_state,
return_state: Box::new(return_state),
};
}
Message::CloseSettings { save } => {
if save {
if let AppState::Settings { ref settings_state, .. } = self.state {
self.global_config = settings_state.config.clone();
crate::first_run::save_config(&self.global_config);
}
}
if let Some(rs) = self.take_settings_return() {
self.state = rs;
} else {
self.state = AppState::ProjectView(ProjectViewState::Splash);
}
}
Message::SettingsMessage(settings_msg) => {
if let AppState::Settings { ref mut settings_state, .. } = self.state {
let is_save = matches!(settings_msg, crate::gui::settings::Message::Save);
let is_cancel = matches!(settings_msg, crate::gui::settings::Message::Cancel);
let done = crate::gui::settings::handle_message(settings_state, settings_msg);
if done {
return self.update(Message::CloseSettings { save: is_save && !is_cancel });
}
}
}
Message::KeyPressed(key, modifiers) => {
if let Some(action) = crate::triggers::map_key_press_to_action(&self.state, key, modifiers) {
return self.dispatch_action(action);
}
}
Message::KeyReleased(key, modifiers) => {
if let Some(action) = crate::triggers::map_key_release_to_action(&self.state, key, modifiers) {
return self.dispatch_action(action);
}
}
Message::Tick => {
let menu_actions = self.native_menu.poll_events();
if let Some(first) = menu_actions.into_iter().next() {
match first {
NativeMenuAction::Action(action) => {
return self.dispatch_action(action);
}
NativeMenuAction::ShowNewTrackWizard => {
return self.update(Message::EditorMessage(crate::editor::Message::ShowNewTrackWizard));
}
}
}
}
Message::WindowClosed(window_id) => {
if let AppState::Editor(ref mut editor) = self.state {
if editor.module_for_window(window_id).is_some() {
let title = editor.module_window_title(window_id);
let _had_view = editor.module_window_view(window_id).is_some();
debug_log!("module window closed: {:?} (had_view={})", title, _had_view);
drop(title);
return editor.close_module_window_by_id(window_id).map(Message::EditorMessage);
}
}
}
Message::EditorMessage(editor_msg) => {
if let AppState::Editor(ref mut editor) = self.state {
return editor.update(editor_msg).map(Message::EditorMessage);
}
}
}
Task::none()
}
fn view(&self) -> Element<'_, Message> {
match &self.state {
AppState::ProjectView(ProjectViewState::Splash) => {
crate::gui::splash::view()
}
AppState::ProjectView(pv_state) => {
crate::gui::project_viewer::view(pv_state)
}
AppState::FirstRun { project_dir } => {
crate::gui::first_run_wizard::view(project_dir)
}
AppState::NewProject(np_state) => {
crate::gui::new_project::view(np_state)
}
AppState::TimeUtility { tapper_state, .. } => {
time_utility::view(tapper_state)
}
AppState::Settings { settings_state, .. } => {
crate::gui::settings::view(settings_state)
.map(Message::SettingsMessage)
}
AppState::Editor(editor) => {
editor.view().map(Message::EditorMessage)
}
}
}
fn subscription(&self) -> Subscription<Message> {
use iced::keyboard;
Subscription::batch([
keyboard::on_key_press(|key, modifiers| Some(Message::KeyPressed(key, modifiers))),
keyboard::on_key_release(|key, modifiers| Some(Message::KeyReleased(key, modifiers))),
iced::window::close_events().map(Message::WindowClosed),
iced::time::every(std::time::Duration::from_millis(100)).map(|_| Message::Tick),
])
}
fn dispatch_action(&mut self, action: Action) -> Task<Message> {
match action {
Action::TimeUtilityTapPressed => self.update(Message::TimeUtilityTapPressed),
Action::TimeUtilityTapReleased => self.update(Message::TimeUtilityTapReleased),
Action::OpenSettings => self.update(Message::OpenSettings),
Action::NewProject => self.update(Message::ViewNewProject),
Action::EditorTogglePlayback => {
self.update(Message::EditorMessage(crate::editor::Message::PlayPressed))
}
Action::EditorStop => {
self.update(Message::EditorMessage(crate::editor::Message::StopPressed))
}
Action::EditorToggleRecord => {
self.update(Message::EditorMessage(crate::editor::Message::RecordPressed))
}
Action::EditorRewind => {
self.update(Message::EditorMessage(crate::editor::Message::RewindPressed))
}
Action::EditorPlayFromBeginning => {
self.update(Message::EditorMessage(crate::editor::Message::RewindPressed))
}
Action::EditorToggleInspector => {
self.update(Message::EditorMessage(crate::editor::Message::ToggleInspector))
}
Action::EditorToggleBottomPanel => {
self.update(Message::EditorMessage(crate::editor::Message::ToggleBottomPanel))
}
Action::EditorToggleMixer => {
self.update(Message::EditorMessage(crate::editor::Message::SetBottomPanelMode(
crate::editor::BottomPanelMode::Mixer,
)))
}
Action::EditorToggleCycle => {
self.update(Message::EditorMessage(crate::editor::Message::CycleToggled))
}
Action::EditorToggleMetronome => {
self.update(Message::EditorMessage(crate::editor::Message::MetronomeToggled))
}
Action::EditorToggleToolbar => {
Task::none()
}
Action::ZoomInH => {
self.update(Message::EditorMessage(crate::editor::Message::ZoomH(1.25)))
}
Action::ZoomOutH => {
self.update(Message::EditorMessage(crate::editor::Message::ZoomH(0.8)))
}
Action::ZoomInV => {
self.update(Message::EditorMessage(crate::editor::Message::ZoomV(1.25)))
}
Action::ZoomOutV => {
self.update(Message::EditorMessage(crate::editor::Message::ZoomV(0.8)))
}
action => {
self.update(Message::EditorMessage(crate::editor::Message::EditAction(action)))
}
}
}
fn take_time_utility_return(&mut self) -> Option<AppState> {
let placeholder = AppState::ProjectView(ProjectViewState::Splash);
let old = std::mem::replace(&mut self.state, placeholder);
if let AppState::TimeUtility { return_state, .. } = old {
Some(*return_state)
} else {
self.state = old;
None
}
}
fn take_settings_return(&mut self) -> Option<AppState> {
let placeholder = AppState::ProjectView(ProjectViewState::Splash);
let old = std::mem::replace(&mut self.state, placeholder);
if let AppState::Settings { return_state, .. } = old {
Some(*return_state)
} else {
self.state = old;
None
}
}
}

View File

@ -1,26 +0,0 @@
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

@ -3,7 +3,7 @@ use crate::engine::TransportState;
use crate::gui::icon_button::{button_group, IconButton};
use crate::gui::icons::{Icon, IconSet};
use crate::timing::MusicalTime;
use iced::widget::{button, container, row, text, Space};
use iced::widget::{container, row, text, Space};
use iced::{Alignment, Background, Color, Element, Length, Theme};
pub fn view<'a>(
@ -15,17 +15,11 @@ 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;
@ -142,35 +136,11 @@ pub fn view<'a>(
.into(),
]);
let mut mode_row = row![].spacing(2);
for mode in BottomPanelMode::ALL {
let active = show_bottom_panel && *bottom_panel_mode == mode;
let label = mode.label();
let btn = button(text(label).size(10))
.on_press(Message::SetBottomPanelMode(mode))
.padding([2, 6])
.style(move |_theme: &Theme, _status| {
let bg = if active {
Color::from_rgb8(0x44, 0x66, 0x88)
} else {
Color::from_rgb8(0x38, 0x3A, 0x3C)
};
button::Style {
background: Some(Background::Color(bg)),
text_color: Color::from_rgb8(0xDD, 0xDD, 0xDD),
border: iced::Border { radius: 3.0.into(), ..iced::Border::default() },
..button::Style::default()
}
});
mode_row = mode_row.push(btn);
}
let left = Space::new(Length::Fill, 0);
let right = Space::new(Length::Fill, 0);
let bar = row![
view_toggles,
mode_row,
left,
lcd,
transport_controls,

View File

@ -3,14 +3,7 @@ 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>,
_selected_index: Option<usize>,
_h_zoom: f32,
_tempo: f32,
_time_sig_num: u8,
_wf_peaks: Option<&'a crate::waveform::WaveformPeaks>,
) -> Element<'a, Message> {
pub fn view<'a>(selected_track: Option<&'a Track>) -> 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

@ -1,8 +1,7 @@
use crate::automation::AutomationMode;
use crate::config::ProjectConfig;
use crate::editor::Message;
use crate::modules::registry::BUILTIN_MODULES;
use crate::track::{MonitorMode, Track};
use crate::track::Track;
use iced::widget::{
button, column, container, horizontal_rule, pick_list, row, text, vertical_rule, Column,
};
@ -23,16 +22,8 @@ pub fn view<'a>(
module_names: &'a HashMap<u32, String>,
track_index: Option<usize>,
hilbert_fft_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],
visualizer_buffer_size: usize,
) -> 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 {
@ -75,9 +66,8 @@ pub fn view<'a>(
let mut add_col = Column::new().spacing(2);
if let Some(idx) = track_index {
for desc in BUILTIN_MODULES.iter().filter(|d| !d.system) {
let label = format!("{} - {}", desc.display_name, desc.description);
add_col = add_col.push(
button(text(label).size(10))
button(text(desc.display_name).size(10))
.on_press(Message::AddModuleToTrack(idx, desc.type_name.to_string()))
.padding([2, 6])
.style(|_theme: &Theme, status| {
@ -150,102 +140,6 @@ pub fn view<'a>(
);
}
if sections.signal {
col = col.push(horizontal_rule(1));
col = col.push(
button(text("Signal").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)))
.on_press(Message::ToggleInspectorSignal)
.padding([2, 0])
.style(|_: &Theme, _| button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}),
);
col = col.push(text(format!("Vol: {:.0}% Pan: {:+.0}", track.volume * 100.0, track.pan * 100.0)).size(10));
let track_idx = track_index.unwrap_or(0);
let monitor_picker = pick_list(
MonitorMode::ALL.as_slice(),
Some(track.monitor_mode),
move |m| Message::SetMonitorMode(track_idx, m),
).width(80);
col = col.push(
row![text("Monitor").size(10).width(60), monitor_picker]
.spacing(4).align_y(iced::Alignment::Center),
);
}
if sections.sends {
col = col.push(
button(text("Sends").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)))
.on_press(Message::ToggleInspectorSends)
.padding([2, 0])
.style(|_: &Theme, _| button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}),
);
col = col.push(text(format!("{} sends", track.sends.len())).size(10));
}
if sections.automation {
col = col.push(
button(text("Automation").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)))
.on_press(Message::ToggleInspectorAutomation)
.padding([2, 0])
.style(|_: &Theme, _| button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}),
);
let track_idx = track_index.unwrap_or(0);
let auto_mode_picker = pick_list(
AutomationMode::ALL.as_slice(),
Some(track.automation_mode),
move |m| Message::SetTrackAutomationMode(track_idx, m),
).width(80);
col = col.push(
row![text("Mode").size(10).width(60), auto_mode_picker]
.spacing(4).align_y(iced::Alignment::Center),
);
col = col.push(text(format!("{} lanes", track.automation_lanes.len())).size(10));
for lane in &track.automation_lanes {
let (min, max) = lane.value_range();
col = col.push(text(format!("{} [{:.1}..{:.1}]", lane.target, min, max)).size(9));
}
}
if sections.spatial {
col = col.push(
button(text("Spatial").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)))
.on_press(Message::ToggleInspectorSpatial)
.padding([2, 0])
.style(|_: &Theme, _| button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}),
);
col = col.push(text(format!("x:{:.1} y:{:.1} z:{:.1}", track.spatial_x, track.spatial_y, track.spatial_z)).size(10));
}
if sections.analysis {
col = col.push(
button(text("Analysis").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)))
.on_press(Message::ToggleInspectorAnalysis)
.padding([2, 0])
.style(|_: &Theme, _| button::Style {
background: Some(Background::Color(Color::TRANSPARENT)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}),
);
}
col = col.push(horizontal_rule(1));
col = col.push(text("Bus").size(10).color(Color::from_rgb8(0x99, 0x99, 0x99)));
col = col.push(text(&track.bus_name).size(10));

View File

@ -25,31 +25,9 @@ fn pan_label(pan: f32) -> String {
}
}
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 plugin_count = discovered_plugins.len();
let plugin_hint = if plugin_count > 0 {
let paths: Vec<_> = discovered_plugins.iter().map(|p| p.path.display().to_string()).collect();
format!("Mixer ({} plugins: {})", plugin_count, paths.join(", "))
} else {
"Mixer".to_string()
};
pub fn view<'a>(tracks: &'a [Track], icons: &'a IconSet) -> Element<'a, Message> {
let header = container(
text(plugin_hint).size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
text("Mixer").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
)
.padding([4, 8]);

View File

@ -1,11 +1,8 @@
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

@ -1,81 +0,0 @@
use crate::editor::Message;
use crate::track::Track;
use iced::widget::{column, container, pick_list, row, text};
use iced::{Background, Color, Element, Length, Theme};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScoreNoteDuration {
Whole,
Half,
Quarter,
Eighth,
Sixteenth,
}
impl ScoreNoteDuration {
pub const ALL: [ScoreNoteDuration; 5] = [
ScoreNoteDuration::Whole,
ScoreNoteDuration::Half,
ScoreNoteDuration::Quarter,
ScoreNoteDuration::Eighth,
ScoreNoteDuration::Sixteenth,
];
}
impl std::fmt::Display for ScoreNoteDuration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Whole => write!(f, "1"),
Self::Half => write!(f, "1/2"),
Self::Quarter => write!(f, "1/4"),
Self::Eighth => write!(f, "1/8"),
Self::Sixteenth => write!(f, "1/16"),
}
}
}
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 duration_picker = pick_list(
ScoreNoteDuration::ALL.as_slice(),
Some(note_duration),
|d| Message::SetScoreNoteDuration(d),
).width(70);
let content = if let Some(track) = selected_track {
column![
row![
text("Score Editor").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
duration_picker,
].spacing(8),
text(format!("{} - Score View", track.name)).size(12),
]
.spacing(4)
.padding(8)
} else {
column![
row![
text("Score Editor").size(14).color(Color::from_rgb8(0xAA, 0xAA, 0xAA)),
duration_picker,
].spacing(8),
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

@ -1,20 +0,0 @@
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

@ -31,7 +31,6 @@ fn bar_groupings(num: u8, den: u8) -> (u32, u32) {
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum Message {
ZoomChanged(f32, f32),
PlayheadMoved(MusicalTime),
@ -77,12 +76,6 @@ 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;
@ -330,7 +323,6 @@ impl<'a> Timeline<'a> {
(total_beats as f64 * samples_per_beat) as u64
}
#[allow(dead_code)]
fn sample_to_x(&self, sample: u64) -> f32 {
let beats_per_second = self.config.tempo / 60.0;
let total_beats = sample as f32 / self.config.sample_rate as f32 * beats_per_second;
@ -570,6 +562,7 @@ impl<'a> Timeline<'a> {
}
fn draw_regions(&self, frame: &mut canvas::Frame, _bounds: Rectangle) {
let th = self.effective_track_height();
for (i, track) in self.tracks.iter().enumerate() {
let region_color = Color::from_rgba8(
track.color.r,

View File

@ -58,26 +58,7 @@ pub fn view<'a>(track: &'a Track, icons: &'a IconSet, height: f32) -> Element<'a
.hint("Record Arm")
.into();
let freeze_btn: Element<'a, Message> = button(
text(if track.frozen { "F*" } else { "F" }).size(10)
)
.on_press(Message::FreezeToggled)
.padding([2, 5])
.style(move |_theme: &Theme, _status| {
let bg = if track.frozen {
Color::from_rgb8(0x33, 0x77, 0xBB)
} else {
Color::TRANSPARENT
};
button::Style {
background: Some(Background::Color(bg)),
text_color: Color::from_rgb8(0x99, 0x99, 0x99),
..button::Style::default()
}
})
.into();
let controls = row![mute_btn, solo_btn, rec_btn, freeze_btn].spacing(2);
let controls = row![mute_btn, solo_btn, rec_btn].spacing(2);
let volume_slider = slider(0.0..=1.0, track.volume, Message::VolumeChanged)
.step(0.01)

View File

@ -2,12 +2,10 @@ 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

@ -1,110 +0,0 @@
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,9 +44,6 @@ 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

@ -1,37 +0,0 @@
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

@ -2,7 +2,7 @@ use std::collections::HashMap;
use iced::window;
use iced::{Element, Task};
use oxforge::mdk::{ModuleGuiDescriptor, ToGuiMessage, VisualizationFrame};
use oxforge::mdk::{ModuleGuiDescriptor, ToGuiMessage};
use crate::editor::{Message, ModuleParamState};
use crate::engine::{EngineCommand, EngineHandle};
@ -15,7 +15,6 @@ pub struct ModuleGuiManager {
module_window_manager: ModuleWindowManager,
pending_gui_opens: std::collections::HashSet<u32>,
pending_bridges: HashMap<u32, FramebufferGuiBridge>,
latest_vis_frame: Option<VisualizationFrame>,
}
impl ModuleGuiManager {
@ -26,7 +25,6 @@ impl ModuleGuiManager {
module_window_manager: ModuleWindowManager::new(),
pending_gui_opens: std::collections::HashSet::new(),
pending_bridges: HashMap::new(),
latest_vis_frame: None,
}
}
@ -102,9 +100,6 @@ impl ModuleGuiManager {
for (module_id, msg) in engine.poll_gui_messages() {
match msg {
ToGuiMessage::VisualizationData { data } => {
if let Some(frame) = VisualizationFrame::deserialize(&data) {
self.latest_vis_frame = Some(frame);
}
self.module_window_manager.receive_visualization(module_id, data);
}
ToGuiMessage::Log(_) => {}
@ -229,8 +224,4 @@ impl ModuleGuiManager {
}
Task::none()
}
pub fn take_visualization_frame(&mut self) -> Option<VisualizationFrame> {
self.latest_vis_frame.take()
}
}

View File

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

View File

@ -1,80 +0,0 @@
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,7 +86,6 @@ 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 {
@ -94,7 +93,6 @@ impl Default for TrackConfig {
Self {
name: "New Track".to_string(),
track_type: TrackType::Audio,
input_buffer_size: 512,
}
}
}

View File

@ -42,7 +42,6 @@ pub fn map_key_press_to_action(
"x" => Some(Action::EditorToggleMixer),
"c" => Some(Action::EditorToggleCycle),
"k" => Some(Action::EditorToggleMetronome),
"t" => Some(Action::EditorToggleToolbar),
"q" => Some(Action::Quantize),
"," => Some(Action::EditorRewind),
_ => None,

View File

@ -7,12 +7,6 @@ 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 {