ui: the node editor offers the de-noise node and persists its window
The form gains a `median samples` row, shown only for `DeNoise`; the corner row widens to anything that reads `fc` (`math_op_uses_fc()`) while `q` stays band-pass-only, and the wiring row keeps its place at the end so the form's order is unchanged for every existing op. The session format gains a thirteenth field, `med_n`, after `y`. A twelve-field node -- a file written before this node existed -- still loads, with `med_n` left at the struct's default, which is what such a file meant; the reader's `return number(...) && ...` chain had to become a guarded sequence so the thirteenth field could be read conditionally. The math probe enables the channel it builds its graphs from, the same self-sufficiency rule the noise and measurement probes already follow: `enable_all_probe` ends by switching one signal off, and with `sine` gone the graphs landed on `square`, changing a documented line for reasons unrelated to the math. Readings: `[math-probe] 2 math channels on 'sine' and 'noise'`, `pane add: 'math3' sources 'sine'`, `graph edit: stored_slots 31000 -> 32000`, `dialog build: nodes=2, output after add=1` and the rest of the suite unchanged; no `Gtk-CRITICAL`.
This commit is contained in:
1 parent
1bde8809dd
commit
5c2c221777
5 files changed
+41
-7
No files matched your search
+14
-4
@@ -366,7 +366,7 @@ std::string math_node_text(const MathNode& node) {
|
|||||||
std::ostringstream o;
|
std::ostringstream o;
|
||||||
o << kind << '|' << node.source << '|' << node.in_a << '|' << node.in_b << '|' << node.gain << '|'
|
o << kind << '|' << node.source << '|' << node.in_a << '|' << node.in_b << '|' << node.gain << '|'
|
||||||
<< node.offset << '|' << node.fc << '|' << node.q << '|' << node.lo << '|' << node.hi << '|'
|
<< node.offset << '|' << node.fc << '|' << node.q << '|' << node.lo << '|' << node.hi << '|'
|
||||||
<< node.x << '|' << node.y;
|
<< node.x << '|' << node.y << '|' << node.med_n;
|
||||||
return o.str();
|
return o.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +382,9 @@ bool math_node_from_text(const std::string& text, MathNode& out) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.push_back(cur);
|
f.push_back(cur);
|
||||||
if (f.size() != 12u) return false;
|
// Twelve fields is a session file written before the de-noise node existed; its `med_n` stays at the
|
||||||
|
// struct's default, which is what that file meant.
|
||||||
|
if (f.size() != 12u && f.size() != 13u) return false;
|
||||||
const auto number = [&](std::size_t i, double& v) {
|
const auto number = [&](std::size_t i, double& v) {
|
||||||
try {
|
try {
|
||||||
v = std::stod(f[i]);
|
v = std::stod(f[i]);
|
||||||
@@ -402,8 +404,16 @@ bool math_node_from_text(const std::string& text, MathNode& out) {
|
|||||||
out.source = f[1];
|
out.source = f[1];
|
||||||
out.in_a = static_cast<int>(in_a);
|
out.in_a = static_cast<int>(in_a);
|
||||||
out.in_b = static_cast<int>(in_b);
|
out.in_b = static_cast<int>(in_b);
|
||||||
return number(4, out.gain) && number(5, out.offset) && number(6, out.fc) && number(7, out.q) &&
|
if (!(number(4, out.gain) && number(5, out.offset) && number(6, out.fc) && number(7, out.q) &&
|
||||||
number(8, out.lo) && number(9, out.hi) && number(10, out.x) && number(11, out.y);
|
number(8, out.lo) && number(9, out.hi) && number(10, out.x) && number(11, out.y))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (f.size() == 13u) {
|
||||||
|
double med = 0.0;
|
||||||
|
if (!number(12, med)) return false;
|
||||||
|
out.med_n = static_cast<int>(med);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_layout(const std::string& path, LayoutState& out) {
|
bool load_layout(const std::string& path, LayoutState& out) {
|
||||||
|
|||||||
+9
-1
@@ -2140,6 +2140,14 @@ void open_math_dialog(App& app, int edit) {
|
|||||||
gtk_box_append(GTK_BOX(form), clamp_rows);
|
gtk_box_append(GTK_BOX(form), clamp_rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Odd, 3..9. The engine rounds up to odd anyway, but a step of 2 means the widget never offers an even
|
||||||
|
// one.
|
||||||
|
d->med = gtk_spin_button_new_with_range(3.0, 9.0, 2.0);
|
||||||
|
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->med), 0);
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->med), 5.0);
|
||||||
|
g_signal_connect(d->med, "value-changed", G_CALLBACK(on_math_param_changed), d);
|
||||||
|
gtk_box_append(GTK_BOX(form), math_row("median samples", d->med, &d->rows[6]));
|
||||||
|
|
||||||
d->inputs = gtk_label_new("");
|
d->inputs = gtk_label_new("");
|
||||||
gtk_label_set_wrap(GTK_LABEL(d->inputs), true);
|
gtk_label_set_wrap(GTK_LABEL(d->inputs), true);
|
||||||
gtk_widget_add_css_class(d->inputs, "dim-label");
|
gtk_widget_add_css_class(d->inputs, "dim-label");
|
||||||
@@ -2159,7 +2167,7 @@ void open_math_dialog(App& app, int edit) {
|
|||||||
gtk_widget_set_visible(d->problem, FALSE);
|
gtk_widget_set_visible(d->problem, FALSE);
|
||||||
gtk_box_append(GTK_BOX(form), d->problem);
|
gtk_box_append(GTK_BOX(form), d->problem);
|
||||||
|
|
||||||
// A menu of the twelve ops rather than one button that always makes a gain: building anything
|
// A menu of the thirteen ops rather than one button that always makes a gain: building anything
|
||||||
// else was add-then-change-the-dropdown, which is two steps for the common case.
|
// else was add-then-change-the-dropdown, which is two steps for the common case.
|
||||||
GtkWidget* add = gtk_menu_button_new();
|
GtkWidget* add = gtk_menu_button_new();
|
||||||
gtk_menu_button_set_label(GTK_MENU_BUTTON(add), "add node");
|
gtk_menu_button_set_label(GTK_MENU_BUTTON(add), "add node");
|
||||||
|
|||||||
+2
-1
@@ -978,9 +978,10 @@ struct MathDialog {
|
|||||||
GtkWidget* offset = nullptr;
|
GtkWidget* offset = nullptr;
|
||||||
GtkWidget* fc = nullptr;
|
GtkWidget* fc = nullptr;
|
||||||
GtkWidget* q = nullptr;
|
GtkWidget* q = nullptr;
|
||||||
|
GtkWidget* med = nullptr; ///< MathNode::med_n
|
||||||
GtkWidget* lo = nullptr;
|
GtkWidget* lo = nullptr;
|
||||||
GtkWidget* hi = nullptr;
|
GtkWidget* hi = nullptr;
|
||||||
GtkWidget* rows[6] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
|
GtkWidget* rows[7] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||||
GtkWidget* inputs = nullptr;
|
GtkWidget* inputs = nullptr;
|
||||||
/// The validation line and the button it governs. Both are set from `math_dialog_sync()` and from
|
/// The validation line and the button it governs. Both are set from `math_dialog_sync()` and from
|
||||||
/// nowhere else, so what the line says and what the button allows cannot disagree.
|
/// nowhere else, so what the line says and what the button allows cannot disagree.
|
||||||
|
|||||||
+6
-1
@@ -835,6 +835,7 @@ void on_math_param_changed(GtkWidget*, gpointer user) {
|
|||||||
n.offset = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->offset));
|
n.offset = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->offset));
|
||||||
n.fc = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->fc));
|
n.fc = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->fc));
|
||||||
n.q = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->q));
|
n.q = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->q));
|
||||||
|
n.med_n = static_cast<int>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->med)));
|
||||||
n.lo = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->lo));
|
n.lo = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->lo));
|
||||||
n.hi = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->hi));
|
n.hi = gtk_spin_button_get_value(GTK_SPIN_BUTTON(d->hi));
|
||||||
if (d->source_drop != nullptr) {
|
if (d->source_drop != nullptr) {
|
||||||
@@ -930,14 +931,18 @@ void math_dialog_sync_form(MathDialog* d) {
|
|||||||
const bool source = op == MathOp::Source;
|
const bool source = op == MathOp::Source;
|
||||||
gtk_widget_set_visible(d->rows[0], source); // the source channel
|
gtk_widget_set_visible(d->rows[0], source); // the source channel
|
||||||
gtk_widget_set_visible(d->rows[1], gain);
|
gtk_widget_set_visible(d->rows[1], gain);
|
||||||
gtk_widget_set_visible(d->rows[2], filter);
|
// The corner row is shown for anything that reads `fc`, which is now the three biquads *and* the
|
||||||
|
// de-noise node; `q` stays a band-pass-only row.
|
||||||
|
gtk_widget_set_visible(d->rows[2], math_op_uses_fc(op));
|
||||||
gtk_widget_set_visible(d->rows[3], filter && op == MathOp::BandPass);
|
gtk_widget_set_visible(d->rows[3], filter && op == MathOp::BandPass);
|
||||||
gtk_widget_set_visible(d->rows[4], clamp);
|
gtk_widget_set_visible(d->rows[4], clamp);
|
||||||
gtk_widget_set_visible(d->rows[5], true); // the inputs, always: they say what is wired
|
gtk_widget_set_visible(d->rows[5], true); // the inputs, always: they say what is wired
|
||||||
|
gtk_widget_set_visible(d->rows[6], math_op_uses_median(op));
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->gain), n.gain);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->gain), n.gain);
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->offset), n.offset);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->offset), n.offset);
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->fc), n.fc);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->fc), n.fc);
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->q), n.q);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->q), n.q);
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->med), static_cast<double>(n.med_n));
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->lo), n.lo);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->lo), n.lo);
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->hi), n.hi);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->hi), n.hi);
|
||||||
if (d->source_drop != nullptr) {
|
if (d->source_drop != nullptr) {
|
||||||
|
|||||||
@@ -281,6 +281,16 @@ gboolean eventzoom_probe(gpointer user) {
|
|||||||
gboolean math_probe(gpointer user) {
|
gboolean math_probe(gpointer user) {
|
||||||
App* a = static_cast<App*>(user);
|
App* a = static_cast<App*>(user);
|
||||||
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
||||||
|
// The channel the graphs are built from is enabled *here*, for the reason the noise and measurement
|
||||||
|
// probes give: `enable_all_probe` finishes by switching one signal off, and with `sine` gone the graphs
|
||||||
|
// land on `square`, which turns the documented "2 math channels on 'sine' and 'noise'" into a different
|
||||||
|
// line for reasons that have nothing to do with the math.
|
||||||
|
{
|
||||||
|
const std::vector<SignalInfo>& signals = a->model->signals();
|
||||||
|
for (std::size_t i = 0; i < signals.size(); ++i) {
|
||||||
|
if (signals[i].name == "sine") a->model->set_signal_enabled(i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string late_name;
|
std::string late_name;
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user