audio-oxide/au-o2-gui/src/editor/export.rs

145 lines
5.5 KiB
Rust

use iced::widget::{button, column, container, pick_list, row, text, text_input, checkbox, Space};
use iced::{Alignment, Background, Color, Element, Length, Theme};
use super::{Editor, Message, ModalState};
use crate::export::{self, ExportConfig, ExportFormat};
use crate::gui::theme as ui_theme;
impl Editor {
pub(crate) fn handle_export(&mut self, message: Message) {
match message {
Message::ShowExportDialog => {
self.modal_state = Some(ModalState::ExportDialog(ExportConfig {
sample_rate: self.project_config.sample_rate,
..ExportConfig::default()
}));
}
Message::ExportFormatSelected(fmt) => {
if let Some(ModalState::ExportDialog(ref mut cfg)) = self.modal_state {
cfg.format = fmt;
}
}
Message::ExportBitDepthSelected(bd) => {
if let Some(ModalState::ExportDialog(ref mut cfg)) = self.modal_state {
cfg.bit_depth = bd;
}
}
Message::ExportNormalizeToggled => {
if let Some(ModalState::ExportDialog(ref mut cfg)) = self.modal_state {
cfg.normalize = !cfg.normalize;
}
}
Message::ExportFilenameChanged(name) => {
if let Some(ModalState::ExportDialog(ref mut cfg)) = self.modal_state {
cfg.filename = name;
}
}
Message::ExportConfirm => {
if let Some(ModalState::ExportDialog(ref cfg)) = self.modal_state {
self.perform_export(cfg.clone());
}
self.modal_state = None;
}
_ => {}
}
}
pub(crate) fn perform_export(&self, config: ExportConfig) {
let bounced = export::bounce_offline(
&self.tracks,
&self.project_path,
self.tempo,
self.project_config.sample_rate,
self.time_signature_numerator as u32,
);
let (mut mix_l, mut mix_r) = match bounced {
Some(data) => data,
None => {
debug_log!("nothing to export");
return;
}
};
if config.normalize {
export::normalize(&mut mix_l, &mut mix_r);
}
let export_dir = self.project_path.join("exports");
let _ = std::fs::create_dir_all(&export_dir);
let filename = format!("{}.{}", config.filename, config.format.extension());
let path = export_dir.join(&filename);
let result = match config.format {
ExportFormat::Wav => export::export_wav(
&path, &mix_l, &mix_r, config.sample_rate, config.bit_depth,
),
ExportFormat::Flac => export::export_flac(
&path, &mix_l, &mix_r, config.sample_rate, config.bit_depth,
),
ExportFormat::Xtc => export::export_xtc(
&path, &mix_l, &mix_r, config.sample_rate, config.bit_depth,
self.analysis_fft_size as u32,
),
};
match result {
Ok(()) => debug_log!("[export] wrote {}", path.display()),
Err(_e) => debug_log!("[export] failed: {}", _e),
}
}
pub(crate) fn export_dialog_view(&self, config: &ExportConfig) -> Element<'_, Message> {
let format_picker = pick_list(
ExportFormat::ALL.as_slice(),
Some(config.format),
Message::ExportFormatSelected,
);
let bit_depths: Vec<u16> = vec![16, 24, 32];
let bit_depth_picker = pick_list(
bit_depths,
Some(config.bit_depth),
Message::ExportBitDepthSelected,
);
let normalize_check = checkbox("Normalize", config.normalize)
.on_toggle(|_| Message::ExportNormalizeToggled);
let filename_input = text_input("filename", &config.filename)
.on_input(Message::ExportFilenameChanged)
.width(200);
let export_btn = button(text("Export").size(ui_theme::TS_MD))
.on_press(Message::ExportConfirm);
let cancel_btn = button(text("Cancel").size(ui_theme::TS_MD))
.on_press(Message::CloseModal);
container(
column![
text("Export / Bounce").size(ui_theme::TS_XL),
Space::new(0, ui_theme::SP_LG),
row![text("Format:").size(ui_theme::TS_MD).width(80), format_picker].spacing(ui_theme::SP_MD).align_y(Alignment::Center),
row![text("Bit Depth:").size(ui_theme::TS_MD).width(80), bit_depth_picker].spacing(ui_theme::SP_MD).align_y(Alignment::Center),
row![text("Filename:").size(ui_theme::TS_MD).width(80), filename_input].spacing(ui_theme::SP_MD).align_y(Alignment::Center),
normalize_check,
Space::new(0, ui_theme::SP_LG),
row![cancel_btn, Space::new(Length::Fill, 0), export_btn].spacing(ui_theme::SP_MD),
]
.spacing(ui_theme::SP_MD)
.padding(ui_theme::SP_XXL)
.width(400),
)
.style(|_theme: &Theme| container::Style {
background: Some(Background::Color(Color::from_rgb8(0x38, 0x31, 0x2A))),
border: iced::Border {
color: Color::from_rgb8(0x58, 0x4E, 0x44),
width: 1.0,
radius: 10.0.into(),
},
..container::Style::default()
})
.into()
}
}