145 lines
5.5 KiB
Rust
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()
|
|
}
|
|
}
|