diff options
author | David Robillard <d@drobilla.net> | 2016-10-01 05:46:29 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2016-10-02 12:24:57 -0400 |
commit | 0f50e9239bbda77ce38f297870f8cf4158025acc (patch) | |
tree | 89e255ade0257ca3f1adf9d1e9d8a81195b45d15 /src | |
parent | 9b8bce71893ef450992f82a28a6a0287c479baaf (diff) | |
download | ingen-0f50e9239bbda77ce38f297870f8cf4158025acc.tar.gz ingen-0f50e9239bbda77ce38f297870f8cf4158025acc.tar.bz2 ingen-0f50e9239bbda77ce38f297870f8cf4158025acc.zip |
Show audio and load information in status line
Diffstat (limited to 'src')
-rw-r--r-- | src/URIs.cpp | 5 | ||||
-rw-r--r-- | src/gui/App.cpp | 81 | ||||
-rw-r--r-- | src/gui/App.hpp | 21 | ||||
-rw-r--r-- | src/gui/GraphBox.cpp | 14 | ||||
-rw-r--r-- | src/gui/GraphBox.hpp | 3 | ||||
-rw-r--r-- | src/gui/Port.cpp | 37 | ||||
-rw-r--r-- | src/gui/rgba.hpp | 58 | ||||
-rw-r--r-- | src/server/Engine.cpp | 63 | ||||
-rw-r--r-- | src/server/Engine.hpp | 55 | ||||
-rw-r--r-- | src/server/GraphImpl.cpp | 3 | ||||
-rw-r--r-- | src/server/RunContext.hpp | 15 | ||||
-rw-r--r-- | src/server/events/Get.cpp | 12 |
12 files changed, 312 insertions, 55 deletions
diff --git a/src/URIs.cpp b/src/URIs.cpp index b272e48e..4b771473 100644 --- a/src/URIs.cpp +++ b/src/URIs.cpp @@ -101,6 +101,11 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld) , ingen_head (forge, map, lworld, INGEN__head) , ingen_incidentTo (forge, map, lworld, INGEN__incidentTo) , ingen_loadedBundle (forge, map, lworld, INGEN__loadedBundle) + , ingen_maxEventLoad (forge, map, lworld, INGEN__maxEventLoad) + , ingen_maxRunLoad (forge, map, lworld, INGEN__maxRunLoad) + , ingen_meanRunLoad (forge, map, lworld, INGEN__meanRunLoad) + , ingen_minRunLoad (forge, map, lworld, INGEN__minRunLoad) + , ingen_numThreads (forge, map, lworld, INGEN__numThreads) , ingen_polyphonic (forge, map, lworld, INGEN__polyphonic) , ingen_polyphony (forge, map, lworld, INGEN__polyphony) , ingen_prototype (forge, map, lworld, INGEN__prototype) diff --git a/src/gui/App.cpp b/src/gui/App.cpp index c023fe8c..a3055c91 100644 --- a/src/gui/App.cpp +++ b/src/gui/App.cpp @@ -51,6 +51,7 @@ #include "ThreadedLoader.hpp" #include "WidgetFactory.hpp" #include "WindowFactory.hpp" +#include "rgba.hpp" using namespace std; @@ -74,6 +75,11 @@ App::App(Ingen::World* world) , _window_factory(new WindowFactory(*this)) , _world(world) , _sample_rate(48000) + , _block_length(1024) + , _n_threads(1) + , _max_event_load(0.0f) + , _min_run_load(0.0f) + , _max_run_load(0.0f) , _enable_signal(true) , _requested_plugins(false) , _is_plugin(false) @@ -193,6 +199,8 @@ App::attach(SPtr<SigClientInterface> client) sigc::mem_fun(this, &App::response)); _client->signal_error().connect( sigc::mem_fun(this, &App::error_message)); + _client->signal_put().connect( + sigc::mem_fun(this, &App::put)); _client->signal_property_change().connect( sigc::mem_fun(this, &App::property_change)); } @@ -271,18 +279,77 @@ App::set_tooltip(Gtk::Widget* widget, const LilvNode* node) } void +App::put(const Raul::URI& uri, + const Resource::Properties& properties, + Resource::Graph ctx) +{ + _enable_signal = false; + for (const auto& p : properties) { + property_change(uri, p.first, p.second); + } + _enable_signal = true; + _status_text = status_text(); + signal_status_text_changed.emit(_status_text); +} + +void App::property_change(const Raul::URI& subject, const Raul::URI& key, const Atom& value) { - if (subject == Raul::URI("ingen:/engine") && key == uris().param_sampleRate) { - if (value.type() == forge().Int) { - log().info(fmt("Sample rate: %1%\n") % uris().forge.str(value)); - _sample_rate = value.get<int32_t>(); - } else { - log().error("Engine sample rate property is not an integer\n"); - } + if (subject != Raul::URI("ingen:/engine")) { + return; + } else if (key == uris().param_sampleRate && value.type() == forge().Int) { + _sample_rate = value.get<int32_t>(); + } else if (key == uris().bufsz_maxBlockLength && value.type() == forge().Int) { + _block_length = value.get<int32_t>(); + } else if (key == uris().ingen_numThreads && value.type() == forge().Int) { + _n_threads = value.get<int>(); + } else if (key == uris().ingen_maxEventLoad && value.type() == forge().Float) { + _max_event_load = value.get<float>(); + } else if (key == uris().ingen_minRunLoad && value.type() == forge().Float) { + _min_run_load = value.get<float>(); + } else if (key == uris().ingen_meanRunLoad && value.type() == forge().Float) { + _mean_run_load = value.get<float>(); + } else if (key == uris().ingen_maxRunLoad && value.type() == forge().Float) { + _max_run_load = value.get<float>(); + } else { + _world->log().warn(fmt("Unknown engine property %1%\n") % key); + return; } + + if (_enable_signal) { + _status_text = status_text(); + signal_status_text_changed.emit(_status_text); + } +} + +static std::string +fraction_label(float f) +{ + static const uint32_t GREEN = 0x4A8A0EFF; + static const uint32_t RED = 0x960909FF; + + const uint32_t col = rgba_interpolate(GREEN, RED, std::min(f, 1.0f)); + char col_str[8]; + snprintf(col_str, sizeof(col_str), "%02X%02X%02X", + RGBA_R(col), RGBA_G(col), RGBA_B(col)); + return (fmt("<span color='#%s'>%d%%</span>") % col_str % (f * 100)).str(); +} + +std::string +App::status_text() const +{ + return (fmt("<b>Audio:</b> %2.1f kHz / %.1f ms <b>Load: </b> %s events + %s <b>DSP:</b> %s ≤ %s ≤ %s") + % (_sample_rate / 1e3f) + % (_block_length * 1e3f / (float)_sample_rate) + % fraction_label(_max_event_load) + % ((_n_threads == 1) + ? "1 thread" + : (fmt("%1% threads") % _n_threads).str()) + % fraction_label(_min_run_load) + % fraction_label(_mean_run_load) + % fraction_label(_max_run_load)).str(); } void diff --git a/src/gui/App.hpp b/src/gui/App.hpp index 6071c750..61336747 100644 --- a/src/gui/App.hpp +++ b/src/gui/App.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard <http://drobilla.net/> + Copyright 2007-2016 David Robillard <http://drobilla.net/> Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -25,6 +25,7 @@ #include <gtkmm/window.h> #include "ingen/Atom.hpp" +#include "ingen/Resource.hpp" #include "ingen/Status.hpp" #include "ingen/World.hpp" #include "ingen/ingen.h" @@ -125,8 +126,13 @@ public: SPtr<Serialiser> serialiser(); static SPtr<App> create(Ingen::World* world); + void run(); + std::string status_text() const; + + sigc::signal<void, const std::string&> signal_status_text_changed; + inline Ingen::World* world() const { return _world; } inline Ingen::URIs& uris() const { return _world->uris(); } inline Ingen::Log& log() const { return _world->log(); } @@ -137,6 +143,10 @@ protected: bool animate(); void response(int32_t id, Ingen::Status status, const std::string& subject); + void put(const Raul::URI& uri, + const Resource::Properties& properties, + Resource::Graph ctx); + void property_change(const Raul::URI& subject, const Raul::URI& key, const Atom& value); @@ -158,7 +168,14 @@ protected: Ingen::World* _world; - uint32_t _sample_rate; + int32_t _sample_rate; + int32_t _block_length; + int32_t _n_threads; + float _max_event_load; + float _mean_run_load; + float _min_run_load; + float _max_run_load; + std::string _status_text; typedef std::map<Port*, bool> ActivityPorts; ActivityPorts _activity_ports; diff --git a/src/gui/GraphBox.cpp b/src/gui/GraphBox.cpp index 10f063cc..692e378a 100644 --- a/src/gui/GraphBox.cpp +++ b/src/gui/GraphBox.cpp @@ -179,6 +179,10 @@ GraphBox::GraphBox(BaseObjectType* cobject, Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get(); clipboard->signal_owner_change().connect( sigc::mem_fun(this, &GraphBox::event_clipboard_changed)); + + _status_label = Gtk::manage(new Gtk::Label("STATUS")); + _status_bar->pack_start(*_status_label, false, true, 0); + _status_label->show(); } GraphBox::~GraphBox() @@ -228,6 +232,16 @@ GraphBox::init_box(App& app) _breadcrumbs = new BreadCrumbs(*_app); _breadcrumbs->signal_graph_selected.connect( sigc::mem_fun(this, &GraphBox::set_graph_from_path)); + + _status_label->set_markup(app.status_text()); + app.signal_status_text_changed.connect( + sigc::mem_fun(*this, &GraphBox::set_status_text)); +} + +void +GraphBox::set_status_text(const std::string& text) +{ + _status_label->set_markup(text); } void diff --git a/src/gui/GraphBox.hpp b/src/gui/GraphBox.hpp index 0a55227e..af17a1ac 100644 --- a/src/gui/GraphBox.hpp +++ b/src/gui/GraphBox.hpp @@ -73,6 +73,8 @@ public: void init_box(App& app); + void set_status_text(const std::string& text); + void set_graph(SPtr<const Client::GraphModel> graph, SPtr<GraphView> view); @@ -186,6 +188,7 @@ private: Gtk::Alignment* _alignment; BreadCrumbs* _breadcrumbs; Gtk::Statusbar* _status_bar; + Gtk::Label* _status_label; Gtk::HPaned* _doc_paned; Gtk::ScrolledWindow* _doc_scrolledwindow; diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp index 1a9750a6..c643b379 100644 --- a/src/gui/Port.cpp +++ b/src/gui/Port.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard <http://drobilla.net/> + Copyright 2007-2016 David Robillard <http://drobilla.net/> Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -33,6 +33,7 @@ #include "WidgetFactory.hpp" #include "WindowFactory.hpp" #include "ingen_config.h" +#include "rgba.hpp" using namespace Ingen::Client; using namespace std; @@ -339,38 +340,6 @@ Port::on_event(GdkEvent* ev) return false; } -/* Peak colour stuff */ - -static inline uint32_t -rgba_to_uint(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return ((((uint32_t)(r)) << 24) | - (((uint32_t)(g)) << 16) | - (((uint32_t)(b)) << 8) | - (((uint32_t)(a)))); -} - -static inline uint8_t -mono_interpolate(uint8_t v1, uint8_t v2, float f) -{ - return ((int)rint((v2) * (f) + (v1) * (1 - (f)))); -} - -#define RGBA_R(x) (((uint32_t)(x)) >> 24) -#define RGBA_G(x) ((((uint32_t)(x)) >> 16) & 0xFF) -#define RGBA_B(x) ((((uint32_t)(x)) >> 8) & 0xFF) -#define RGBA_A(x) (((uint32_t)(x)) & 0xFF) - -static inline uint32_t -rgba_interpolate(uint32_t c1, uint32_t c2, float f) -{ - return rgba_to_uint( - mono_interpolate(RGBA_R(c1), RGBA_R(c2), f), - mono_interpolate(RGBA_G(c1), RGBA_G(c2), f), - mono_interpolate(RGBA_B(c1), RGBA_B(c2), f), - mono_interpolate(RGBA_A(c1), RGBA_A(c2), f)); -} - inline static uint32_t peak_color(float peak) { @@ -386,8 +355,6 @@ peak_color(float peak) } } -/* End peak colour stuff */ - void Port::activity(const Atom& value) { diff --git a/src/gui/rgba.hpp b/src/gui/rgba.hpp new file mode 100644 index 00000000..8648aece --- /dev/null +++ b/src/gui/rgba.hpp @@ -0,0 +1,58 @@ +/* + This file is part of Ingen. + Copyright 2007-2016 David Robillard <http://drobilla.net/> + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef INGEN_GUI_RGBA_HPP +#define INGEN_GUI_RGBA_HPP + +#include <math.h> + +namespace Ingen { +namespace GUI { + +static inline uint32_t +rgba_to_uint(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return ((((uint32_t)(r)) << 24) | + (((uint32_t)(g)) << 16) | + (((uint32_t)(b)) << 8) | + (((uint32_t)(a)))); +} + +static inline uint8_t +mono_interpolate(uint8_t v1, uint8_t v2, float f) +{ + return ((int)rint((v2) * (f) + (v1) * (1 - (f)))); +} + +#define RGBA_R(x) (((uint32_t)(x)) >> 24) +#define RGBA_G(x) ((((uint32_t)(x)) >> 16) & 0xFF) +#define RGBA_B(x) ((((uint32_t)(x)) >> 8) & 0xFF) +#define RGBA_A(x) (((uint32_t)(x)) & 0xFF) + +static inline uint32_t +rgba_interpolate(uint32_t c1, uint32_t c2, float f) +{ + return rgba_to_uint( + mono_interpolate(RGBA_R(c1), RGBA_R(c2), f), + mono_interpolate(RGBA_G(c1), RGBA_G(c2), f), + mono_interpolate(RGBA_B(c1), RGBA_B(c2), f), + mono_interpolate(RGBA_A(c1), RGBA_A(c2), f)); +} + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_RGBA_HPP diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp index 1a0ab0a0..893f6f92 100644 --- a/src/server/Engine.cpp +++ b/src/server/Engine.cpp @@ -83,9 +83,11 @@ Engine::Engine(Ingen::World* world) , _worker(new Worker(world->log(), event_queue_size())) , _sync_worker(new Worker(world->log(), event_queue_size(), true)) , _listener(NULL) + , _cycle_start_time(0) , _rand_engine(0) , _uniform_dist(0.0f, 1.0f) , _quit_flag(false) + , _reset_load_flag(false) , _direct_driver(true) , _atomic_bundles(world->conf().option("atomic-bundles").get<int32_t>()) { @@ -264,8 +266,29 @@ Engine::quit() bool Engine::main_iteration() { + const Ingen::URIs& uris = world()->uris(); + _post_processor->process(); _maid->cleanup(); + + if (_event_load.changed) { + _broadcaster->set_property(Raul::URI("ingen:/engine"), + uris.ingen_maxEventLoad, + uris.forge.make(_event_load.max / 100.0f)); + _event_load.changed = false; + } + + if (_run_load.changed) { + _broadcaster->put(Raul::URI("ingen:/engine"), + { { uris.ingen_meanRunLoad, + uris.forge.make(floorf(_run_load.mean) / 100.0f) }, + { uris.ingen_minRunLoad, + uris.forge.make(_run_load.min / 100.0f) }, + { uris.ingen_maxRunLoad, + uris.forge.make(_run_load.max / 100.0f) } }); + _run_load.changed = false; + } + return !_quit_flag; } @@ -275,6 +298,7 @@ Engine::set_driver(SPtr<Driver> driver) _driver = driver; for (RunContext* ctx : _run_contexts) { ctx->set_priority(driver->real_time_priority()); + ctx->set_rate(driver->sample_rate()); } } @@ -285,14 +309,31 @@ Engine::event_time() return 0; } - const SampleCount start = _direct_driver + // FIXME: Jitter with direct driver + const SampleCount now = _direct_driver ? run_context().start() : _driver->frame_time(); - /* Exactly one cycle latency (some could run ASAP if we get lucky, but not - always, and a slight constant latency is far better than jittery lower - (average) latency */ - return start + _driver->block_length(); + return now + _driver->block_length(); +} + +uint64_t +Engine::current_time(const RunContext& context) const +{ + struct timespec time; +#ifdef CLOCK_MONOTONIC_RAW + clock_gettime(CLOCK_MONOTONIC_RAW, &time); +#else + clock_gettime(CLOCK_MONOTONIC, &time); +#endif + + return (uint64_t)time.tv_sec * 1e6 + (uint64_t)time.tv_nsec / 1e3; +} + +void +Engine::reset_load() +{ + _reset_load_flag = true; } void @@ -367,6 +408,7 @@ unsigned Engine::run(uint32_t sample_count) { RunContext& ctx = run_context(); + _cycle_start_time = current_time(ctx); // Apply control bindings to input control_bindings()->pre_process( @@ -377,6 +419,7 @@ Engine::run(uint32_t sample_count) // Process events that came in during the last cycle // (Aiming for jitter-free 1 block event latency, ideally) const unsigned n_processed_events = process_events(); + const uint64_t t_events = current_time(ctx); // Run root graph if (_root_graph) { @@ -387,6 +430,16 @@ Engine::run(uint32_t sample_count) ctx, _root_graph->port_impl(1)->buffer(0).get()); } + // Update load for this cycle + if (ctx.duration() > 0) { + _event_load.update(t_events - _cycle_start_time, ctx.duration()); + _run_load.update(current_time(ctx) - t_events, ctx.duration()); + if (_reset_load_flag) { + _run_load = Load(); + _reset_load_flag = false; + } + } + return n_processed_events; } diff --git a/src/server/Engine.hpp b/src/server/Engine.hpp index 2d5e053e..fc80d64b 100644 --- a/src/server/Engine.hpp +++ b/src/server/Engine.hpp @@ -89,8 +89,27 @@ public: void set_driver(SPtr<Driver> driver); + /** Return the frame time to execute an event that arrived now. + * + * This aims to return a time one cycle from "now", so that events ideally + * have 1 cycle of latency with no jitter. + */ SampleCount event_time(); + /** Return the time this cycle began processing in microseconds. + * + * This value is comparable to the value returned by current_time(). + */ + inline uint64_t cycle_start_time(const RunContext& context) const { + return _cycle_start_time; + } + + /** Return the current time in microseconds. */ + uint64_t current_time(const RunContext& context) const; + + /** Reset the load statistics (when the expected DSP load changes). */ + void reset_load(); + /** Enqueue an event to be processed (non-realtime threads only). */ void enqueue_event(Event* ev, Event::Mode mode=Event::Mode::NORMAL); @@ -128,11 +147,41 @@ public: SPtr<Store> store() const; size_t event_queue_size() const; - bool atomic_bundles() const { return _atomic_bundles; } + size_t n_threads() const { return _run_contexts.size(); } + bool atomic_bundles() const { return _atomic_bundles; } private: Ingen::World* _world; + struct Load { + void update(uint64_t time, uint64_t available) { + const uint64_t load = time * 100 / available; + if (load < min) { + min = load; + changed = true; + } + if (load > max) { + max = load; + changed = true; + } + if (++n == 1) { + mean = load; + } else { + const float a = mean + ((float)load - mean) / (float)++n; + if (a != mean) { + changed = floorf(a) != floorf(mean); + mean = a; + } + } + } + + uint64_t min = std::numeric_limits<uint64_t>::max(); + uint64_t max = 0; + float mean = 0.0f; + uint64_t n = 0; + bool changed = false; + }; + BlockFactory* _block_factory; Broadcaster* _broadcaster; BufferFactory* _buffer_factory; @@ -153,6 +202,9 @@ private: SocketListener* _listener; std::vector<RunContext*> _run_contexts; + uint64_t _cycle_start_time; + Load _event_load; + Load _run_load; std::mt19937 _rand_engine; std::uniform_real_distribution<float> _uniform_dist; @@ -161,6 +213,7 @@ private: std::mutex _tasks_mutex; bool _quit_flag; + bool _reset_load_flag; bool _direct_driver; bool _atomic_bundles; }; diff --git a/src/server/GraphImpl.cpp b/src/server/GraphImpl.cpp index 22276a34..bdd0a69a 100644 --- a/src/server/GraphImpl.cpp +++ b/src/server/GraphImpl.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard <http://drobilla.net/> + Copyright 2007-2016 David Robillard <http://drobilla.net/> Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -302,6 +302,7 @@ GraphImpl::set_compiled_graph(CompiledGraph* cg) { if (_compiled_graph && _compiled_graph != cg) { _engine.maid()->dispose(_compiled_graph); + _engine.reset_load(); } _compiled_graph = cg; } diff --git a/src/server/RunContext.hpp b/src/server/RunContext.hpp index 803e0c3b..eba30545 100644 --- a/src/server/RunContext.hpp +++ b/src/server/RunContext.hpp @@ -87,6 +87,18 @@ public: /** Return true iff any notifications are pending. */ bool pending_notifications() const { return _event_sink->read_space(); } + /** Return the duration of this cycle in microseconds. + * + * This is the cycle length in frames (nframes) converted to microseconds, + * that is, the amount of real time that this cycle's audio represents. + * Note that this is unrelated to the amount of time available to execute a + * cycle (other than the fact that it must be processed in significantly + * less time to avoid a dropout when running in real time). + */ + inline uint64_t duration() const { + return (uint64_t)_nframes * 1e6 / _rate; + } + inline void locate(FrameTime s, SampleCount nframes) { _start = s; _end = s + nframes; @@ -103,6 +115,7 @@ public: } void set_priority(int priority); + void set_rate(SampleCount rate) { _rate = rate; } inline Engine& engine() const { return _engine; } inline Task* task() const { return _task; } @@ -112,6 +125,7 @@ public: inline FrameTime end() const { return _end; } inline SampleCount offset() const { return _offset; } inline SampleCount nframes() const { return _nframes; } + inline SampleCount rate() const { return _rate; } inline bool realtime() const { return _realtime; } protected: @@ -129,6 +143,7 @@ protected: FrameTime _end; ///< End frame of this cycle, timeline relative SampleCount _offset; ///< Offset into data buffers SampleCount _nframes; ///< Number of frames past offset to process + SampleCount _rate; ///< Sample rate in Hz bool _realtime; ///< True iff context is hard realtime bool _copy; ///< True iff this is a copy (shared event_sink) }; diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp index fa56f23a..bec57104 100644 --- a/src/server/events/Get.cpp +++ b/src/server/events/Get.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard <http://drobilla.net/> + Copyright 2007-2016 David Robillard <http://drobilla.net/> Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -90,10 +90,14 @@ Get::post_process() } else if (_uri == "ingen:/engine") { // TODO: Keep a proper RDF model of the engine URIs& uris = _engine.world()->uris(); - _request_client->set_property( + _request_client->put( Raul::URI("ingen:/engine"), - uris.param_sampleRate, - uris.forge.make(int32_t(_engine.driver()->sample_rate()))); + { { uris.param_sampleRate, + uris.forge.make(int32_t(_engine.driver()->sample_rate())) }, + { uris.bufsz_maxBlockLength, + uris.forge.make(int32_t(_engine.driver()->block_length())) }, + { uris.ingen_numThreads, + uris.forge.make(int32_t(_engine.n_threads())) } }); } else { _response.send(_request_client.get()); } |