Feat: UI/UX and ducking compressor
Some checks failed
Deploy Website / deploy (push) Failing after 4m52s
Some checks failed
Deploy Website / deploy (push) Failing after 4m52s
This commit is contained in:
@@ -163,6 +163,15 @@ fn render_visualizers(frame: &mut Frame, app: &App, area: Rect) {
|
||||
render_spectrum(frame, app, spectrum_area);
|
||||
}
|
||||
|
||||
fn viz_gain(data: &[f32], config: &crate::state::audio::AudioConfig) -> f32 {
|
||||
if config.normalize_viz {
|
||||
let peak = data.iter().fold(0.0_f32, |m, s| m.max(s.abs()));
|
||||
if peak > 0.0001 { 1.0 / peak } else { 1.0 }
|
||||
} else {
|
||||
config.gain_boost
|
||||
}
|
||||
}
|
||||
|
||||
fn render_scope(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
@@ -173,9 +182,11 @@ fn render_scope(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let gain = viz_gain(&app.metrics.scope, &app.audio.config);
|
||||
let scope = Scope::new(&app.metrics.scope)
|
||||
.orientation(Orientation::Horizontal)
|
||||
.color(theme.meter.low);
|
||||
.color(theme.meter.low)
|
||||
.gain(gain);
|
||||
frame.render_widget(scope, inner);
|
||||
}
|
||||
|
||||
@@ -189,8 +200,16 @@ fn render_lissajous(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let peak = app.metrics.scope.iter().chain(app.metrics.scope_right.iter())
|
||||
.fold(0.0_f32, |m, s| m.max(s.abs()));
|
||||
let gain = if app.audio.config.normalize_viz {
|
||||
if peak > 0.0001 { 1.0 / peak } else { 1.0 }
|
||||
} else {
|
||||
app.audio.config.gain_boost
|
||||
};
|
||||
let lissajous = Lissajous::new(&app.metrics.scope, &app.metrics.scope_right)
|
||||
.color(theme.meter.low);
|
||||
.color(theme.meter.low)
|
||||
.gain(gain);
|
||||
frame.render_widget(lissajous, inner);
|
||||
}
|
||||
|
||||
@@ -204,7 +223,13 @@ fn render_spectrum(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let spectrum = Spectrum::new(&app.metrics.spectrum);
|
||||
let gain = if app.audio.config.normalize_viz {
|
||||
viz_gain(&app.metrics.spectrum, &app.audio.config)
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let spectrum = Spectrum::new(&app.metrics.spectrum)
|
||||
.gain(gain);
|
||||
frame.render_widget(spectrum, inner);
|
||||
}
|
||||
|
||||
|
||||
@@ -482,6 +482,15 @@ fn render_tile(
|
||||
}
|
||||
}
|
||||
|
||||
fn viz_gain(data: &[f32], config: &crate::state::audio::AudioConfig) -> f32 {
|
||||
if config.normalize_viz {
|
||||
let peak = data.iter().fold(0.0_f32, |m, s| m.max(s.abs()));
|
||||
if peak > 0.0001 { 1.0 / peak } else { 1.0 }
|
||||
} else {
|
||||
config.gain_boost
|
||||
}
|
||||
}
|
||||
|
||||
fn render_scope(frame: &mut Frame, app: &App, area: Rect, orientation: Orientation) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
@@ -490,9 +499,11 @@ fn render_scope(frame: &mut Frame, app: &App, area: Rect, orientation: Orientati
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let gain = viz_gain(&app.metrics.scope, &app.audio.config);
|
||||
let scope = Scope::new(&app.metrics.scope)
|
||||
.orientation(orientation)
|
||||
.color(theme.meter.low);
|
||||
.color(theme.meter.low)
|
||||
.gain(gain);
|
||||
frame.render_widget(scope, inner);
|
||||
}
|
||||
|
||||
@@ -504,7 +515,13 @@ fn render_spectrum(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let spectrum = Spectrum::new(&app.metrics.spectrum);
|
||||
let gain = if app.audio.config.normalize_viz {
|
||||
viz_gain(&app.metrics.spectrum, &app.audio.config)
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
let spectrum = Spectrum::new(&app.metrics.spectrum)
|
||||
.gain(gain);
|
||||
frame.render_widget(spectrum, inner);
|
||||
}
|
||||
|
||||
@@ -516,8 +533,16 @@ fn render_lissajous(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let peak = app.metrics.scope.iter().chain(app.metrics.scope_right.iter())
|
||||
.fold(0.0_f32, |m, s| m.max(s.abs()));
|
||||
let gain = if app.audio.config.normalize_viz {
|
||||
if peak > 0.0001 { 1.0 / peak } else { 1.0 }
|
||||
} else {
|
||||
app.audio.config.gain_boost
|
||||
};
|
||||
let lissajous = Lissajous::new(&app.metrics.scope, &app.metrics.scope_right)
|
||||
.color(theme.meter.low);
|
||||
.color(theme.meter.low)
|
||||
.gain(gain);
|
||||
frame.render_widget(lissajous, inner);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,18 @@ pub fn render(frame: &mut Frame, app: &App, link: &LinkState, area: Rect) {
|
||||
focus == OptionsFocus::ShowLissajous,
|
||||
&theme,
|
||||
),
|
||||
render_option_line(
|
||||
"Gain boost",
|
||||
&gain_boost_label(app.audio.config.gain_boost),
|
||||
focus == OptionsFocus::GainBoost,
|
||||
&theme,
|
||||
),
|
||||
render_option_line(
|
||||
"Normalize",
|
||||
if app.audio.config.normalize_viz { "On" } else { "Off" },
|
||||
focus == OptionsFocus::NormalizeViz,
|
||||
&theme,
|
||||
),
|
||||
render_option_line(
|
||||
"Completion",
|
||||
if app.ui.show_completion { "On" } else { "Off" },
|
||||
@@ -354,9 +366,11 @@ fn option_description(focus: OptionsFocus) -> Option<&'static str> {
|
||||
OptionsFocus::HueRotation => Some("Shift all theme colors by a hue angle"),
|
||||
OptionsFocus::RefreshRate => Some("Lower values reduce CPU usage"),
|
||||
OptionsFocus::RuntimeHighlight => Some("Highlight executed code spans during playback"),
|
||||
OptionsFocus::ShowScope => Some("Oscilloscope on the engine page"),
|
||||
OptionsFocus::ShowSpectrum => Some("Spectrum analyzer on the engine page"),
|
||||
OptionsFocus::ShowScope => Some("Oscilloscope on the main view"),
|
||||
OptionsFocus::ShowSpectrum => Some("Spectrum analyzer on the main view"),
|
||||
OptionsFocus::ShowLissajous => Some("XY stereo phase scope (left vs right)"),
|
||||
OptionsFocus::GainBoost => Some("Amplify scope and lissajous waveforms"),
|
||||
OptionsFocus::NormalizeViz => Some("Auto-scale visualizations to fill the display"),
|
||||
OptionsFocus::ShowCompletion => Some("Word completion popup in the editor"),
|
||||
OptionsFocus::ShowPreview => Some("Step script preview on the sequencer grid"),
|
||||
OptionsFocus::PerformanceMode => Some("Hide header and footer bars"),
|
||||
@@ -386,6 +400,10 @@ fn render_description_line(desc: &str, theme: &ThemeColors) -> Line<'static> {
|
||||
))
|
||||
}
|
||||
|
||||
fn gain_boost_label(gain: f32) -> String {
|
||||
format!("{:.0}x", gain)
|
||||
}
|
||||
|
||||
fn render_readonly_line(label: &str, value: &str, value_style: Style, theme: &theme::ThemeColors) -> Line<'static> {
|
||||
let label_style = Style::new().fg(theme.ui.text_muted);
|
||||
let label_width = 20;
|
||||
|
||||
Reference in New Issue
Block a user