From 7841bfea74da67318ab43eb81e1ffcf6392d3e28 Mon Sep 17 00:00:00 2001 From: Jamie Vital Date: Sun, 21 Jul 2024 14:58:03 -0400 Subject: [PATCH] A bunch of pipeline work --- src-cli/autotrack/autotrack.cpp | 4 +- src-cli/autotrack/autotrack.h | 6 +-- src-cli/autotrack/autotrack_proc.cpp | 10 ++-- src-cli/autotrack/autotrack_vfo.cpp | 18 +++---- src-cli/autotrack/autotrack_web.cpp | 2 +- src-core/common/image/io/tiffio.cpp | 2 +- src-core/common/projection/reprojector.cpp | 8 +-- .../common/projection/sat_proj/sat_proj.cpp | 2 +- .../common/tracking/scheduler/scheduler.h | 28 +++++++++- .../tracking/scheduler/scheduler_ui.cpp | 36 ++++++++----- src-core/common/widgets/pipeline_selector.cpp | 51 +++++++++---------- src-core/common/widgets/pipeline_selector.h | 7 ++- src-core/core/pipeline.h | 2 +- src-interface/offline.cpp | 4 +- src-interface/processing.cpp | 44 +++++++++------- src-interface/processing.h | 7 +++ src-interface/recorder/recorder.cpp | 20 ++++---- src-interface/recorder/recorder.h | 4 +- src-interface/recorder/recorder_proc.cpp | 13 ++--- src-interface/recorder/recorder_vfo.cpp | 16 +++--- 20 files changed, 165 insertions(+), 119 deletions(-) diff --git a/src-cli/autotrack/autotrack.cpp b/src-cli/autotrack/autotrack.cpp index 32e57c985..60b853bb0 100644 --- a/src-cli/autotrack/autotrack.cpp +++ b/src-cli/autotrack/autotrack.cpp @@ -249,7 +249,7 @@ void AutoTrackApp::setup_schedular_callbacks() if (satdump::general_tle_registry.get_from_norad(obj.norad).has_value()) name = satdump::general_tle_registry.get_from_norad(obj.norad)->name; name += " - " + format_notated(dl.frequency, "Hz"); - add_vfo_live(id, name, dl.frequency, dl.pipeline_selector->pipeline_id, dl.pipeline_selector->getParameters()); + add_vfo_live(id, name, dl.frequency, dl.pipeline_selector->selected_pipeline, dl.pipeline_selector->getParameters()); } if (dl.record) @@ -289,7 +289,7 @@ void AutoTrackApp::setup_schedular_callbacks() if (obj.downlinks[0].live) { pipeline_params = obj.downlinks[0].pipeline_selector->getParameters(); - pipeline_id = obj.downlinks[0].pipeline_selector->pipeline_id; + selected_pipeline = obj.downlinks[0].pipeline_selector->selected_pipeline; start_processing(); } diff --git a/src-cli/autotrack/autotrack.h b/src-cli/autotrack/autotrack.h index 995c5f40b..7bc406aa6 100644 --- a/src-cli/autotrack/autotrack.h +++ b/src-cli/autotrack/autotrack.h @@ -69,7 +69,7 @@ private: private: std::mutex live_pipeline_mtx; std::unique_ptr live_pipeline; - int pipeline_id = 0; + satdump::Pipeline selected_pipeline; nlohmann::json pipeline_params; std::string pipeline_output_dir; @@ -97,7 +97,7 @@ private: // VFO Stuff double freq; //// Live - int pipeline_id = -1; + satdump::Pipeline selected_pipeline; nlohmann::json pipeline_params; std::string output_dir; std::shared_ptr lpool; @@ -111,7 +111,7 @@ private: // VFO Stuff std::mutex vfos_mtx; std::vector vfo_list; - void add_vfo_live(std::string id, std::string name, double freq, int vpipeline_id, nlohmann::json vpipeline_params); + void add_vfo_live(std::string id, std::string name, double freq, satdump::Pipeline vpipeline, nlohmann::json vpipeline_params); void add_vfo_reco(std::string id, std::string name, double freq, dsp::BasebandType type, int decimation = -1); void del_vfo(std::string id); diff --git a/src-cli/autotrack/autotrack_proc.cpp b/src-cli/autotrack/autotrack_proc.cpp index 2e0e02f2b..9591dd978 100644 --- a/src-cli/autotrack/autotrack_proc.cpp +++ b/src-cli/autotrack/autotrack_proc.cpp @@ -15,11 +15,11 @@ void AutoTrackApp::start_processing() pipeline_params["buffer_size"] = dsp::STREAM_BUFFER_SIZE; // This is required, as we WILL go over the (usually) default 8192 size pipeline_params["start_timestamp"] = (double)time(0); // Some pipelines need this - pipeline_output_dir = prepareAutomatedPipelineFolder(time(0), source_ptr->d_frequency, satdump::pipelines[pipeline_id].name, d_output_folder); + pipeline_output_dir = prepareAutomatedPipelineFolder(time(0), source_ptr->d_frequency, selected_pipeline.name, d_output_folder); try { - live_pipeline = std::make_unique(satdump::pipelines[pipeline_id], pipeline_params, pipeline_output_dir); + live_pipeline = std::make_unique(selected_pipeline, pipeline_params, pipeline_output_dir); splitter->reset_output("live"); live_pipeline->start(splitter->get_output("live"), main_thread_pool); splitter->set_enabled("live", true); @@ -47,13 +47,13 @@ void AutoTrackApp::stop_processing() if (d_settings.contains("finish_processing") && d_settings["finish_processing"].get() && live_pipeline->getOutputFiles().size() > 0) { std::string input_file = live_pipeline->getOutputFiles()[0]; - int pipeline_id_ = pipeline_id; + satdump::Pipeline selected_pipeline_ = selected_pipeline; std::string pipeline_output_dir_ = pipeline_output_dir; nlohmann::json pipeline_params_ = pipeline_params; - auto fun = [pipeline_id_, pipeline_output_dir_, input_file, pipeline_params_](int) + auto fun = [selected_pipeline_, pipeline_output_dir_, input_file, pipeline_params_](int) { setLowestThreadPriority(); - satdump::Pipeline pipeline = satdump::pipelines[pipeline_id_]; + satdump::Pipeline pipeline = selected_pipeline_; int start_level = pipeline.live_cfg.normal_live[pipeline.live_cfg.normal_live.size() - 1].first; std::string input_level = pipeline.steps[start_level].level_name; pipeline.run(input_file, pipeline_output_dir_, pipeline_params_, input_level); diff --git a/src-cli/autotrack/autotrack_vfo.cpp b/src-cli/autotrack/autotrack_vfo.cpp index c3337687a..74a7ea71a 100644 --- a/src-cli/autotrack/autotrack_vfo.cpp +++ b/src-cli/autotrack/autotrack_vfo.cpp @@ -2,7 +2,7 @@ #include "logger.h" #include "common/utils.h" -void AutoTrackApp::add_vfo_live(std::string id, std::string name, double freq, int vpipeline_id, nlohmann::json vpipeline_params) +void AutoTrackApp::add_vfo_live(std::string id, std::string name, double freq, satdump::Pipeline vpipeline, nlohmann::json vpipeline_params) { vfos_mtx.lock(); @@ -12,7 +12,7 @@ void AutoTrackApp::add_vfo_live(std::string id, std::string name, double freq, i wipInfo.id = id; wipInfo.name = name; wipInfo.freq = freq; - wipInfo.pipeline_id = vpipeline_id; + wipInfo.selected_pipeline = vpipeline; wipInfo.pipeline_params = vpipeline_params; wipInfo.lpool = std::make_shared(8); @@ -21,11 +21,11 @@ void AutoTrackApp::add_vfo_live(std::string id, std::string name, double freq, i vpipeline_params["buffer_size"] = dsp::STREAM_BUFFER_SIZE; // This is required, as we WILL go over the (usually) default 8192 size vpipeline_params["start_timestamp"] = (double)time(0); // Some pipelines need this - std::string output_dir = prepareAutomatedPipelineFolder(time(0), freq, satdump::pipelines[vpipeline_id].name, d_output_folder); + std::string output_dir = prepareAutomatedPipelineFolder(time(0), freq, vpipeline.name, d_output_folder); wipInfo.output_dir = output_dir; - wipInfo.live_pipeline = std::make_shared(satdump::pipelines[vpipeline_id], vpipeline_params, output_dir); + wipInfo.live_pipeline = std::make_shared(vpipeline, vpipeline_params, output_dir); splitter->add_vfo(id, get_samplerate(), frequency_hz - freq); wipInfo.live_pipeline->start(splitter->get_vfo_output(id), *wipInfo.lpool.get()); splitter->set_vfo_enabled(id, true); @@ -103,7 +103,7 @@ void AutoTrackApp::del_vfo(std::string id) splitter->set_vfo_enabled(it->id, false); - if (it->pipeline_id != -1) + if (it->selected_pipeline.name != "") it->live_pipeline->stop(); if (it->file_sink) @@ -115,17 +115,17 @@ void AutoTrackApp::del_vfo(std::string id) splitter->del_vfo(it->id); - if (it->pipeline_id != -1) + if (it->selected_pipeline.name != "") { if (d_settings.contains("finish_processing") && d_settings["finish_processing"].get() && it->live_pipeline->getOutputFiles().size() > 0) { std::string input_file = it->live_pipeline->getOutputFiles()[0]; - int pipeline_id_ = it->pipeline_id; + satdump::Pipeline selected_pipeline_ = it->selected_pipeline; std::string pipeline_output_dir_ = it->output_dir; nlohmann::json pipeline_params_ = it->pipeline_params; - auto fun = [pipeline_id_, pipeline_output_dir_, input_file, pipeline_params_](int) + auto fun = [selected_pipeline_, pipeline_output_dir_, input_file, pipeline_params_](int) { - satdump::Pipeline pipeline = satdump::pipelines[pipeline_id_]; + satdump::Pipeline pipeline = selected_pipeline_; int start_level = pipeline.live_cfg.normal_live[pipeline.live_cfg.normal_live.size() - 1].first; std::string input_level = pipeline.steps[start_level].level_name; pipeline.run(input_file, pipeline_output_dir_, pipeline_params_, input_level); diff --git a/src-cli/autotrack/autotrack_web.cpp b/src-cli/autotrack/autotrack_web.cpp index 0fd0b094c..48a9d9720 100644 --- a/src-cli/autotrack/autotrack_web.cpp +++ b/src-cli/autotrack/autotrack_web.cpp @@ -33,7 +33,7 @@ void AutoTrackApp::setup_webserver() { auto &pos = p["vfos"][vfo.id]; pos["frequency"] = vfo.freq; - if (vfo.pipeline_id != -1) + if (vfo.selected_pipeline.name != "") { vfo.live_pipeline->updateModuleStats(); pos["live_pipeline"] = vfo.live_pipeline->stats; diff --git a/src-core/common/image/io/tiffio.cpp b/src-core/common/image/io/tiffio.cpp index 3cdb768b2..ca5e2791c 100644 --- a/src-core/common/image/io/tiffio.cpp +++ b/src-core/common/image/io/tiffio.cpp @@ -85,7 +85,7 @@ namespace image proj::projection_t proj = meta["proj_cfg"]; geotiff::try_write_geotiff(tif, &proj); } - catch (std::exception &e) + catch (std::exception &) { } } diff --git a/src-core/common/projection/reprojector.cpp b/src-core/common/projection/reprojector.cpp index 7c188d164..456f75ce4 100644 --- a/src-core/common/projection/reprojector.cpp +++ b/src-core/common/projection/reprojector.cpp @@ -88,7 +88,7 @@ namespace satdump { trg_proj = op.target_prj_info; } - catch (std::exception &e) + catch (std::exception &) { trg_proj_err = true; } @@ -106,7 +106,7 @@ namespace satdump { src_proj = image::get_metadata_proj_cfg(op.img); } - catch (std::exception &e) + catch (std::exception &) { src_proj_err = true; } @@ -295,7 +295,7 @@ namespace satdump { *proj = params; } - catch (std::exception &e) + catch (std::exception &) { proj_err = true; } @@ -387,7 +387,7 @@ namespace satdump { proj = params; } - catch (std::exception &e) + catch (std::exception &) { proj_err = true; } diff --git a/src-core/common/projection/sat_proj/sat_proj.cpp b/src-core/common/projection/sat_proj/sat_proj.cpp index 478865107..f64ad7e51 100644 --- a/src-core/common/projection/sat_proj/sat_proj.cpp +++ b/src-core/common/projection/sat_proj/sat_proj.cpp @@ -43,7 +43,7 @@ namespace satdump { p = cfg; } - catch (std::exception &e) + catch (std::exception &) { proj_err = true; } diff --git a/src-core/common/tracking/scheduler/scheduler.h b/src-core/common/tracking/scheduler/scheduler.h index 8c6c0a326..5f7d755d2 100644 --- a/src-core/common/tracking/scheduler/scheduler.h +++ b/src-core/common/tracking/scheduler/scheduler.h @@ -4,6 +4,7 @@ #include "passes.h" #include #include "common/image/image.h" +#include "nlohmann/json_utils.h" namespace satdump { @@ -59,10 +60,28 @@ namespace satdump j["downlinks"][i]["frequency"] = v.downlinks[i].frequency; j["downlinks"][i]["record"] = v.downlinks[i].record; j["downlinks"][i]["live"] = v.downlinks[i].live; - j["downlinks"][i]["pipeline_name"] = pipelines[v.downlinks[i].pipeline_selector->pipeline_id].name; + j["downlinks"][i]["pipeline_name"] = v.downlinks[i].pipeline_selector->selected_pipeline.name; j["downlinks"][i]["pipeline_params"] = v.downlinks[i].pipeline_selector->getParameters(); j["downlinks"][i]["baseband_format"] = v.downlinks[i].baseband_format; j["downlinks"][i]["baseband_decimation"] = v.downlinks[i].baseband_decimation; + + nlohmann::ordered_json work_params = nlohmann::ordered_json::object(); + for (auto &step : v.downlinks[i].pipeline_selector->selected_pipeline.steps) + { + nlohmann::ordered_json step_params = nlohmann::ordered_json::object(); + for (auto& this_module : step.modules) + { + nlohmann::ordered_json module_diff = + perform_json_diff(pipelines_json[v.downlinks[i].pipeline_selector->selected_pipeline.name]["work"][step.level_name][this_module.module_name], + this_module.parameters); + if (!module_diff.is_null()) + step_params[this_module.module_name] = module_diff; + } + if (step_params.size() > 0) + work_params[step.level_name] = step_params; + } + if (work_params.size() > 0) + j["downlinks"][i]["work_params"] = work_params; } } @@ -103,6 +122,13 @@ namespace satdump v.downlinks[i].baseband_format = j["downlinks"][i]["baseband_format"]; if (j["downlinks"][i].contains("baseband_decimation")) v.downlinks[i].baseband_decimation = j["downlinks"][i]["baseband_decimation"]; + if (j["downlinks"][i].contains("work_params")) + for (auto& step : v.downlinks[i].pipeline_selector->selected_pipeline.steps) + if(j["downlinks"][i]["work_params"].contains(step.level_name)) + for (auto& this_module : step.modules) + if(j["downlinks"][i]["work_params"][step.level_name].contains(this_module.module_name)) + this_module.parameters = merge_json_diffs(this_module.parameters, + j["downlinks"][i]["work_params"][step.level_name][this_module.module_name]); } } } diff --git a/src-core/common/tracking/scheduler/scheduler_ui.cpp b/src-core/common/tracking/scheduler/scheduler_ui.cpp index f6ff12509..fdd29d396 100644 --- a/src-core/common/tracking/scheduler/scheduler_ui.cpp +++ b/src-core/common/tracking/scheduler/scheduler_ui.cpp @@ -5,6 +5,7 @@ #include "imgui/imgui_stdlib.h" #include "core/style.h" #include "common/utils.h" +#include "common/dsp_source_sink/format_notated.h" #include "common/widgets/frequency_input.h" #include "resources.h" #include "common/image/text.h" @@ -21,6 +22,7 @@ namespace satdump if (autotrack_engaged) style::beginDisabled(); + ImGuiStyle &imgui_style = ImGui::GetStyle(); float curpos = ImGui::GetCursorPosY(); ImGui::SetCursorPosX(ImGui::GetWindowWidth() / 2 - 220 * ui_scale); ImGui::SetNextItemWidth(200 * ui_scale); @@ -207,7 +209,7 @@ namespace satdump if (cpass_xs > d_pplot_size) cpass_xs = d_pplot_size; - auto color = ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[ImGuiCol_Text]); + auto color = ImGui::ColorConvertFloat4ToU32(imgui_style.Colors[ImGuiCol_Text]); draw_list->AddRect(ImVec2(ImGui::GetCursorScreenPos().x + cpass_xs, ImGui::GetCursorScreenPos().y + thsat_ys), ImVec2(ImGui::GetCursorScreenPos().x + cpass_xe, ImGui::GetCursorScreenPos().y + thsat_ye), color, 3, 0, 2 * ui_scale); @@ -226,24 +228,22 @@ namespace satdump { int sat_row = 0, new_hovered = -1; bool is_hovered = false; - ImVec2 min_el_size(ImGui::CalcTextSize("Min El.").x + ImGui::GetStyle().ItemInnerSpacing.x + (60.0f * ui_scale), 0.0f); + ImVec2 min_el_size(ImGui::CalcTextSize("Min El.").x + imgui_style.ItemInnerSpacing.x + (60.0f * ui_scale), 0.0f); for (auto &cpass : enabled_satellites) { int dl_pos = 0; + std::optional thisTLE = general_tle_registry.get_from_norad(cpass.norad); + std::string object_name = (thisTLE.has_value() ? thisTLE->name : "NORAD #" + std::to_string(cpass.norad)); for (auto &downlink : cpass.downlinks) { std::string idpart = std::to_string(cpass.norad) + "_" + std::to_string((size_t)&downlink); - auto color = ImColor::HSV(fmod(cpass.norad, 10) / 10.0, 1, 1); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); if (&downlink == &cpass.downlinks[0]) { ImGui::SetNextItemWidth(100 * ui_scale); - std::optional thisTLE = general_tle_registry.get_from_norad(cpass.norad); - ImGui::TextColored(color, "%s", thisTLE.has_value() ? thisTLE->name.c_str() : - std::string("NORAD #" + std::to_string(cpass.norad)).c_str()); - + ImGui::TextColored(color, "%s", object_name.c_str()); if (ImGui::Button(((std::string) "+##objadddownlink" + std::to_string(cpass.norad)).c_str())) { cpass.downlinks.push_back(satdump::TrackedObject::Downlink()); @@ -276,6 +276,9 @@ namespace satdump else ImGui::Dummy(min_el_size); + std::string modal_title = "Configure " + object_name + " - " + downlink.pipeline_selector->selected_pipeline.readable_name + + " - " + format_notated(downlink.frequency, "Hz"); + ImGui::TableSetColumnIndex(1); widgets::FrequencyInput(((std::string) "Hz##objcfgfreq1" + idpart).c_str(), &downlink.frequency, 0.75f, false); ImGui::TableSetColumnIndex(2); @@ -286,21 +289,28 @@ namespace satdump ImGui::TableSetColumnIndex(3); ImGui::SetNextItemWidth(300 * ui_scale); ImGui::PushID(cpass.norad); - if (ImGui::BeginCombo(((std::string) "##pipelinesel" + idpart).c_str(), downlink.pipeline_selector->get_name(downlink.pipeline_selector->pipeline_id).c_str(), ImGuiComboFlags_HeightLarge)) + if (ImGui::BeginCombo(((std::string) "##pipelinesel" + idpart).c_str(), + downlink.pipeline_selector->selected_pipeline.readable_name.c_str(), ImGuiComboFlags_HeightLarge)) { downlink.pipeline_selector->renderSelectionBox(300 * ui_scale); ImGui::EndCombo(); } - if (ImGui::BeginCombo(((std::string) "##params" + idpart).c_str(), "Configure...")) - { - downlink.pipeline_selector->renderParamTable(); - ImGui::EndCombo(); - } + if (ImGui::Button(((std::string)"Configure...##" + idpart).c_str())) + ImGui::OpenPopup(modal_title.c_str()); if (downlink.record) { ImGui::SetNextItemWidth(100 * ui_scale); ImGui::InputInt(((std::string) "IQ Decimation##recorddecim" + idpart).c_str(), &downlink.baseband_decimation); } + if(ImGui::BeginPopupModal(modal_title.c_str())) + { + downlink.pipeline_selector->renderParamTable(); + ImGui::SetCursorPosX((ImGui::GetContentRegionMax().x / 2) - + (ImGui::CalcTextSize("Save").x + imgui_style.FramePadding.x * 2) / 2); + if (ImGui::Button("Save")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } ImGui::PopID(); // ImGui::InputText(((std::string) "Pipeline##objcfgfreq4" + std::to_string(cpass.norad)).c_str(), &cpass.pipeline_name); diff --git a/src-core/common/widgets/pipeline_selector.cpp b/src-core/common/widgets/pipeline_selector.cpp index b2a28cf0d..e52a551ef 100644 --- a/src-core/common/widgets/pipeline_selector.cpp +++ b/src-core/common/widgets/pipeline_selector.cpp @@ -15,7 +15,7 @@ namespace satdump PipelineUISelector::PipelineUISelector(bool live_mode) : live_mode(live_mode) { nlohmann::ordered_json params = satdump::config::main_cfg["user_interface"]["default_offline_parameters"]; - advanced_mode = satdump::config::main_cfg["user_interface"]["advanced_mode"]["value"]; + advanced_mode = satdump::config::main_cfg["user_interface"]["advanced_mode"]["value"].get_ptr(); for (nlohmann::detail::iteration_proxy_value> cfg : params.items()) if (!cfg.value().contains("no_live") || !live_mode) @@ -39,6 +39,9 @@ namespace satdump } } } + + selected_pipeline = pipelines[pipelines_levels_select_id]; + updateSelectedPipeline(); } bool PipelineUISelector::contains(std::vector tm, int n) @@ -78,8 +81,7 @@ namespace satdump void PipelineUISelector::updateSelectedPipeline() { parameters_ui_pipeline.clear(); - advanced_mode = satdump::config::main_cfg["user_interface"]["advanced_mode"]["value"]; - for (nlohmann::detail::iteration_proxy_value> cfg : pipelines[pipeline_id].editable_parameters.items()) + for (nlohmann::detail::iteration_proxy_value> cfg : selected_pipeline.editable_parameters.items()) { auto it = std::find_if(parameters_ui.begin(), parameters_ui.end(), @@ -107,14 +109,11 @@ namespace satdump if (!live_mode) { pipeline_levels_str = ""; - if (pipeline_id != -1) - for (int i = 0; i < (int)pipelines[pipeline_id].steps.size() - 1; i++) - pipeline_levels_str += pipelines[pipeline_id].steps[i].level_name + '\0'; + if (selected_pipeline.name != "") + for (int i = 0; i < (int)selected_pipeline.steps.size() - 1; i++) + pipeline_levels_str += selected_pipeline.steps[i].level_name + '\0'; - if (pipelines_levels_select_id == -1) - pipelines_levels_select_id = 0; - - if (pipelines[pipeline_id].editable_parameters.size() != 0) + if (selected_pipeline.editable_parameters.size() != 0) getParamsFromInput(); } } @@ -173,7 +172,7 @@ namespace satdump if (show && (!live_mode || pipelines[n].live)) { - bool is_selected = (pipeline_id == n); + bool is_selected = (selected_pipeline.name == pipelines[n].name); ImGui::Selectable((pipelines[n].readable_name + "##fav").c_str(), &is_selected); if (ImGui::IsItemHovered()) { @@ -181,7 +180,7 @@ namespace satdump ImGui::SameLine(pos); ImGui::TextColored({0, 0, 0, 0}, "%s", text.c_str()); - if (is_selected != (pipeline_id == n) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped)) + if (is_selected != (selected_pipeline.name == pipelines[n].name) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped)) { favourite.erase(favourite.begin() + k); config::main_cfg["user"]["favourite_pipelines"].erase(k); @@ -192,15 +191,15 @@ namespace satdump text = u8"\uf005"; ImGui::TextColored(color, "%s", text.c_str()); text = u8"\uf006"; - if (is_selected != (pipeline_id == n)) + if (is_selected != (selected_pipeline.name == pipelines[n].name)) { - pipeline_id = n; + selected_pipeline = pipelines[n]; updateSelectedPipeline(); } } if (is_selected) { - // pipeline_id = n; + // selected_pipeline = pipelines[n]; // updateSelectedPipeline(); ImGui::SetItemDefaultFocus(); } @@ -221,7 +220,7 @@ namespace satdump if (show && (!live_mode || pipelines[n].live)) { - bool is_selected = (pipeline_id == n); + bool is_selected = (selected_pipeline.name == pipelines[n].name); bool isfav = contains(favourite, n); ImGui::Selectable(pipelines[n].readable_name.c_str(), &is_selected); if (ImGui::IsItemHovered() || isfav) @@ -230,7 +229,8 @@ namespace satdump ImGui::SameLine(pos); ImGui::TextColored({0, 0, 0, 0}, "%s", text.c_str()); - if (is_selected != (pipeline_id == n) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped)) + if (is_selected != (selected_pipeline.name == pipelines[n].name) && + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped)) { if (isfav) { @@ -260,9 +260,9 @@ namespace satdump text = u8"\uf005"; ImGui::TextColored(color, "%s", text.c_str()); text = u8"\uf006"; - if (is_selected != (pipeline_id == n)) + if (is_selected != (selected_pipeline.name == pipelines[n].name)) { - pipeline_id = n; + selected_pipeline = pipelines[n]; updateSelectedPipeline(); } } @@ -328,16 +328,16 @@ namespace satdump ImGui::EndTable(); } - if (advanced_mode) + if (*advanced_mode) { ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5 * ui_scale); ImGui::SeparatorText("Advanced Parameters"); ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 5 * ui_scale); pipeline_mtx.lock(); - for (auto& step : pipelines[pipeline_id].steps) + for (auto& step : selected_pipeline.steps) for (auto& this_module : step.modules) if (widgets::JSONTableEditor(this_module.parameters, this_module.module_name.c_str())) - this_module.parameters = pipelines_json[pipelines[pipeline_id].name]["work"][step.level_name][this_module.module_name]; + this_module.parameters = pipelines_json[selected_pipeline.name]["work"][step.level_name][this_module.module_name]; pipeline_mtx.unlock(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5 * ui_scale); @@ -370,7 +370,7 @@ namespace satdump { if (id == pipelines[n].name) { - pipeline_id = n; + selected_pipeline = pipelines[n]; found = true; } } @@ -380,9 +380,4 @@ namespace satdump logger->error("Could not find pipeline %s!", id.c_str()); pipeline_mtx.unlock(); } - - std::string PipelineUISelector::get_name(int index) - { - return pipelines[index].readable_name; - } } \ No newline at end of file diff --git a/src-core/common/widgets/pipeline_selector.h b/src-core/common/widgets/pipeline_selector.h index d61e6b4b7..0603836b9 100644 --- a/src-core/common/widgets/pipeline_selector.h +++ b/src-core/common/widgets/pipeline_selector.h @@ -18,19 +18,18 @@ namespace satdump nlohmann::json getParameters(); void setParameters(nlohmann::json params); void select_pipeline(std::string id); - std::string get_name(int index); FileSelectWidget inputfileselect = FileSelectWidget("Input File", "Select Input File"); FileSelectWidget outputdirselect = FileSelectWidget("Output Directory", "Select Output Directory", true); - int pipeline_id = 0; - int pipelines_levels_select_id = -1; + Pipeline selected_pipeline; + int pipelines_levels_select_id = 0; private: bool contains(std::vector tm, int n); void getParamsFromInput(); void try_set_param(std::string name, nlohmann::json v); - bool live_mode, advanced_mode; + bool live_mode, *advanced_mode; std::string text = u8"\uf006"; std::vector favourite; std::mutex pipeline_mtx; diff --git a/src-core/core/pipeline.h b/src-core/core/pipeline.h index 3beb41d1b..b954a7da9 100644 --- a/src-core/core/pipeline.h +++ b/src-core/core/pipeline.h @@ -42,7 +42,7 @@ namespace satdump std::vector modules; }; - std::string name; + std::string name = ""; std::string readable_name; PipelinePreset preset; diff --git a/src-interface/offline.cpp b/src-interface/offline.cpp index dc24a019d..43a9c653f 100644 --- a/src-interface/offline.cpp +++ b/src-interface/offline.cpp @@ -47,8 +47,8 @@ namespace satdump error_message.set_message(style::theme.red, "Output folder is invalid!"); else ui_thread_pool.push([&, params2](int) - { processing::process(pipelines[pipeline_selector->pipeline_id].name, - pipelines[pipeline_selector->pipeline_id].steps[pipeline_selector->pipelines_levels_select_id].level_name, + { processing::process(pipeline_selector->selected_pipeline, + pipeline_selector->selected_pipeline.steps[pipeline_selector->pipelines_levels_select_id].level_name, pipeline_selector->inputfileselect.getPath(), pipeline_selector->outputdirselect.getPath(), params2); }); diff --git a/src-interface/processing.cpp b/src-interface/processing.cpp index 3fc042b24..db06a8565 100644 --- a/src-interface/processing.cpp +++ b/src-interface/processing.cpp @@ -22,40 +22,48 @@ namespace satdump std::string input_file, std::string output_file, nlohmann::json parameters) + { + // Get pipeline + std::optional pipeline = getPipelineFromName(downlink_pipeline); + if (!pipeline.has_value()) + { + logger->critical("Pipeline " + downlink_pipeline + " does not exist!"); + return; + } + + process(pipeline.value(), input_level, input_file, output_file, parameters); + } + void process(Pipeline downlink_pipeline, + std::string input_level, + std::string input_file, + std::string output_file, + nlohmann::json parameters) { processing_mutex.lock(); is_processing = true; - logger->info("Starting processing pipeline " + downlink_pipeline + "..."); + logger->info("Starting processing pipeline " + downlink_pipeline.name + "..."); logger->debug("Input file (" + input_level + ") : " + input_file); logger->debug("Output file : " + output_file); if (!std::filesystem::exists(output_file)) std::filesystem::create_directories(output_file); - // Get pipeline - std::optional pipeline = getPipelineFromName(downlink_pipeline); - ui_call_list_mutex->lock(); ui_call_list->clear(); ui_call_list_mutex->unlock(); - if (pipeline.has_value()) + try { - try - { - pipeline.value().run(input_file, output_file, parameters, input_level, true, ui_call_list, ui_call_list_mutex); - } - catch (std::exception &e) - { - logger->error("Fatal error running pipeline : " + std::string(e.what())); - is_processing = false; - processing_mutex.unlock(); - return; - } + downlink_pipeline.run(input_file, output_file, parameters, input_level, true, ui_call_list, ui_call_list_mutex); + } + catch (std::exception &e) + { + logger->error("Fatal error running pipeline : " + std::string(e.what())); + is_processing = false; + processing_mutex.unlock(); + return; } - else - logger->critical("Pipeline " + downlink_pipeline + " does not exist!"); is_processing = false; diff --git a/src-interface/processing.h b/src-interface/processing.h index 4c75c05c9..51ed3e189 100644 --- a/src-interface/processing.h +++ b/src-interface/processing.h @@ -3,6 +3,7 @@ #include #include #include "core/module.h" +#include "core/pipeline.h" #include "dll_export.h" namespace satdump @@ -13,6 +14,12 @@ namespace satdump SATDUMP_DLL2 extern std::shared_ptr ui_call_list_mutex; SATDUMP_DLL2 extern bool is_processing; + void process(Pipeline downlink_pipeline, + std::string input_level, + std::string input_file, + std::string output_file, + nlohmann::json parameters); + void process(std::string downlink_pipeline, std::string input_level, std::string input_file, diff --git a/src-interface/recorder/recorder.cpp b/src-interface/recorder/recorder.cpp index 83dfee5a6..f718ceb2a 100644 --- a/src-interface/recorder/recorder.cpp +++ b/src-interface/recorder/recorder.cpp @@ -473,21 +473,21 @@ namespace satdump style::endDisabled(); // Preset Menu - Pipeline selected_pipeline = pipelines[pipeline_selector.pipeline_id]; - if (selected_pipeline.preset.frequencies.size() > 0) + if (pipeline_selector.selected_pipeline.preset.frequencies.size() > 0) { - if (ImGui::BeginCombo("Freq###presetscombo", selected_pipeline.preset.frequencies[pipeline_preset_id].second == frequency_hz ? selected_pipeline.preset.frequencies[pipeline_preset_id].first.c_str() : "")) + if (ImGui::BeginCombo("Freq###presetscombo", pipeline_selector.selected_pipeline.preset.frequencies[pipeline_preset_id].second == frequency_hz ? + pipeline_selector.selected_pipeline.preset.frequencies[pipeline_preset_id].first.c_str() : "")) { - for (int n = 0; n < (int)selected_pipeline.preset.frequencies.size(); n++) + for (int n = 0; n < (int)pipeline_selector.selected_pipeline.preset.frequencies.size(); n++) { const bool is_selected = (pipeline_preset_id == n); - if (ImGui::Selectable(selected_pipeline.preset.frequencies[n].first.c_str(), is_selected)) + if (ImGui::Selectable(pipeline_selector.selected_pipeline.preset.frequencies[n].first.c_str(), is_selected)) { pipeline_preset_id = n; - if (selected_pipeline.preset.frequencies[pipeline_preset_id].second != 0) + if (pipeline_selector.selected_pipeline.preset.frequencies[pipeline_preset_id].second != 0) { - frequency_hz = selected_pipeline.preset.frequencies[pipeline_preset_id].second; + frequency_hz = pipeline_selector.selected_pipeline.preset.frequencies[pipeline_preset_id].second; set_frequency(frequency_hz); } } @@ -606,9 +606,9 @@ namespace satdump ImGui::SeparatorText(vfo.name.c_str()); ImGui::PopStyleColor(); ImGui::BulletText("Frequency: %s", format_notated(vfo.freq, "Hz").c_str()); - if (vfo.pipeline_id != -1) + if (vfo.selected_pipeline.name != "") { - ImGui::BulletText("Pipeline: %s", pipelines[vfo.pipeline_id].readable_name.c_str()); + ImGui::BulletText("Pipeline: %s", vfo.selected_pipeline.readable_name.c_str()); ImGui::BulletText("Directory: %s", vfo.output_dir.c_str()); } else if (vfo.file_sink) @@ -738,7 +738,7 @@ namespace satdump { if (ImGui::BeginTabItem(vfo.name.c_str())) { - if (vfo.pipeline_id != -1) + if (vfo.selected_pipeline.name != "") { float y_pos = ImGui::GetCursorPosY() + 35 * ui_scale; float live_width = recorder_size.x + 16 * ui_scale; diff --git a/src-interface/recorder/recorder.h b/src-interface/recorder/recorder.h index bbb109825..8e2c6ef9b 100644 --- a/src-interface/recorder/recorder.h +++ b/src-interface/recorder/recorder.h @@ -158,7 +158,7 @@ namespace satdump double freq; //// Live - int pipeline_id = -1; + Pipeline selected_pipeline; nlohmann::json pipeline_params; std::string output_dir; std::shared_ptr lpool; @@ -172,7 +172,7 @@ namespace satdump std::mutex vfos_mtx; std::vector vfo_list; - void add_vfo_live(std::string id, std::string name, double freq, int vpipeline_id, nlohmann::json vpipeline_params); + void add_vfo_live(std::string id, std::string name, double freq, Pipeline vpipeline, nlohmann::json vpipeline_params); void add_vfo_reco(std::string id, std::string name, double freq, dsp::BasebandType type, int decimation = -1); void del_vfo(std::string id); diff --git a/src-interface/recorder/recorder_proc.cpp b/src-interface/recorder/recorder_proc.cpp index d23bafdcb..e30077f80 100644 --- a/src-interface/recorder/recorder_proc.cpp +++ b/src-interface/recorder/recorder_proc.cpp @@ -226,7 +226,7 @@ namespace satdump if (automated_live_output_dir) { - pipeline_output_dir = prepareAutomatedPipelineFolder(time(0), source_ptr->d_frequency, pipelines[pipeline_selector.pipeline_id].name); + pipeline_output_dir = prepareAutomatedPipelineFolder(time(0), source_ptr->d_frequency, pipeline_selector.selected_pipeline.name); } else { @@ -235,7 +235,7 @@ namespace satdump try { - live_pipeline = std::make_unique(pipelines[pipeline_selector.pipeline_id], pipeline_params, pipeline_output_dir); + live_pipeline = std::make_unique(pipeline_selector.selected_pipeline, pipeline_params, pipeline_output_dir); splitter->reset_output("live"); live_pipeline->start(splitter->get_output("live"), ui_thread_pool); splitter->set_enabled("live", true); @@ -265,12 +265,12 @@ namespace satdump if (config::main_cfg["user_interface"]["finish_processing_after_live"]["value"].get() && live_pipeline->getOutputFiles().size() > 0) { - Pipeline pipeline = pipelines[pipeline_selector.pipeline_id]; + Pipeline pipeline = pipeline_selector.selected_pipeline; std::string input_file = live_pipeline->getOutputFiles()[0]; int start_level = pipeline.live_cfg.normal_live[pipeline.live_cfg.normal_live.size() - 1].first; std::string input_level = pipeline.steps[start_level].level_name; ui_thread_pool.push([=](int) - { processing::process(pipeline.name, input_level, input_file, pipeline_output_dir, pipeline_params); }); + { processing::process(pipeline, input_level, input_file, pipeline_output_dir, pipeline_params); }); } live_pipeline.reset(); @@ -341,7 +341,7 @@ namespace satdump if (satdump::general_tle_registry.get_from_norad(obj.norad).has_value()) name = satdump::general_tle_registry.get_from_norad(obj.norad)->name; name += " - " + format_notated(dl.frequency, "Hz"); - add_vfo_live(id, name, dl.frequency, dl.pipeline_selector->pipeline_id, dl.pipeline_selector->getParameters()); + add_vfo_live(id, name, dl.frequency, dl.pipeline_selector->selected_pipeline, dl.pipeline_selector->getParameters()); } if (dl.record) @@ -380,8 +380,9 @@ namespace satdump if (obj.downlinks[0].live) { - pipeline_selector.select_pipeline(pipelines[obj.downlinks[0].pipeline_selector->pipeline_id].name); + pipeline_selector.select_pipeline(obj.downlinks[0].pipeline_selector->selected_pipeline.name); pipeline_selector.setParameters(obj.downlinks[0].pipeline_selector->getParameters()); + pipeline_selector.selected_pipeline.steps = obj.downlinks[0].pipeline_selector->selected_pipeline.steps; start_processing(); } diff --git a/src-interface/recorder/recorder_vfo.cpp b/src-interface/recorder/recorder_vfo.cpp index 33f20bdb9..dd69126f6 100644 --- a/src-interface/recorder/recorder_vfo.cpp +++ b/src-interface/recorder/recorder_vfo.cpp @@ -7,7 +7,7 @@ namespace satdump { - void RecorderApplication::add_vfo_live(std::string id, std::string name, double freq, int vpipeline_id, nlohmann::json vpipeline_params) + void RecorderApplication::add_vfo_live(std::string id, std::string name, double freq, satdump::Pipeline vpipeline, nlohmann::json vpipeline_params) { vfos_mtx.lock(); @@ -17,7 +17,7 @@ namespace satdump wipInfo.id = id; wipInfo.name = name; wipInfo.freq = freq; - wipInfo.pipeline_id = vpipeline_id; + wipInfo.selected_pipeline = vpipeline; wipInfo.pipeline_params = vpipeline_params; wipInfo.lpool = std::make_shared(8); @@ -26,11 +26,11 @@ namespace satdump vpipeline_params["buffer_size"] = dsp::STREAM_BUFFER_SIZE; // This is required, as we WILL go over the (usually) default 8192 size vpipeline_params["start_timestamp"] = (double)time(0); // Some pipelines need this - std::string output_dir = prepareAutomatedPipelineFolder(time(0), freq, pipelines[vpipeline_id].name); + std::string output_dir = prepareAutomatedPipelineFolder(time(0), freq, vpipeline.name); wipInfo.output_dir = output_dir; - wipInfo.live_pipeline = std::make_shared(pipelines[vpipeline_id], vpipeline_params, output_dir); + wipInfo.live_pipeline = std::make_shared(vpipeline, vpipeline_params, output_dir); splitter->add_vfo(id, get_samplerate(), frequency_hz - freq); wipInfo.live_pipeline->start(splitter->get_vfo_output(id), *wipInfo.lpool.get()); splitter->set_vfo_enabled(id, true); @@ -107,7 +107,7 @@ namespace satdump splitter->set_vfo_enabled(it->id, false); - if (it->pipeline_id != -1) + if (it->selected_pipeline.name != "") it->live_pipeline->stop(); if (it->file_sink) @@ -119,18 +119,18 @@ namespace satdump splitter->del_vfo(it->id); - if (it->pipeline_id != -1) + if (it->selected_pipeline.name != "") { if (config::main_cfg["user_interface"]["finish_processing_after_live"]["value"].get() && it->live_pipeline->getOutputFiles().size() > 0) { - Pipeline pipeline = pipelines[it->pipeline_id]; + Pipeline pipeline = it->selected_pipeline; std::string input_file = it->live_pipeline->getOutputFiles()[0]; int start_level = pipeline.live_cfg.normal_live[pipeline.live_cfg.normal_live.size() - 1].first; std::string input_level = pipeline.steps[start_level].level_name; std::string output_dir = it->output_dir; nlohmann::json pipeline_params = it->pipeline_params; ui_thread_pool.push([=](int) - { processing::process(pipeline.name, input_level, input_file, output_dir, pipeline_params); }); + { processing::process(pipeline, input_level, input_file, output_dir, pipeline_params); }); } }