Anklang-0.3.0.dev956+gd75ac925 anklang-0.3.0.dev956+gd75ac925
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
server.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "server.hh"
3#include "jsonipc/jsonipc.hh"
4#include "crawler.hh"
5#include "platform.hh"
6#include "properties.hh"
7#include "serialize.hh"
8#include "main.hh"
9#include "driver.hh"
10#include "utils.hh"
11#include "project.hh"
12#include "path.hh"
13#include "sndfile.hh"
14#include "wave.hh"
15#include "internal.hh"
16#include <atomic>
17
18namespace Ase {
19
20// == ServerImpl ==
21static constexpr size_t telemetry_size = 4 * 1024 * 1024;
22
23ServerImpl *SERVER = nullptr;
24
25ServerImpl::ServerImpl () :
26 telemetry_arena (telemetry_size)
27{
28 assert_return (telemetry_arena.reserved() >= telemetry_size);
29 Block telemetry_header = telemetry_arena.allocate (64);
30 assert_return (telemetry_arena.location() == uint64 (telemetry_header.block_start));
31 const uint8_t header_sentinel[64] = {
32 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
33 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
34 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
35 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
36 };
37 assert_return (telemetry_header.block_length == sizeof (header_sentinel));
38 memcpy (telemetry_header.block_start, header_sentinel, telemetry_header.block_length);
39 if (!SERVER)
40 SERVER = this;
41}
42
43ServerImpl::~ServerImpl ()
44{
45 fatal_error ("ServerImpl references must persist");
46 if (SERVER == this)
47 SERVER = nullptr;
48}
49
51ServerImpl::get_version ()
52{
53 return ase_version();
54}
55
57ServerImpl::get_build_id ()
58{
59 return ase_build_id();
60}
61
63ServerImpl::get_opus_version ()
64{
65 return wave_writer_opus_version();
66}
67
69ServerImpl::get_flac_version ()
70{
71 return wave_writer_flac_version();
72}
73
75ServerImpl::get_sndfile_version ()
76{
77 return libsndfile_version();
78}
79
80void
81ServerImpl::shutdown ()
82{
83 // defer quit() slightly, so remote calls are still completed
84 main_loop->add ([] () { main_loop->quit (0); }, std::chrono::milliseconds (5), LoopPriority::NORMAL);
85}
86
87ProjectP
88ServerImpl::last_project ()
89{
90 return Project::last_project();
91}
92
93ProjectP
94ServerImpl::create_project (String projectname)
95{
96 return ProjectImpl::create (projectname);
97}
98
100ServerImpl::list_preferences ()
101{
102 const CStringS list = Preference::list();
103 return { std::begin (list), std::end (list) };
104}
105
106PropertyP
107ServerImpl::access_preference (const String &ident)
108{
109 return Preference::find (ident);
110}
111
113ServerImpl::ui_config ()
114{
115 UiConfig config;
116 config.has_ui_tests = !App.ui_tests.empty();
117 config.auto_exit = config.has_ui_tests; // Auto-exit when UI tests are present
118 return config;
119}
120
121// UI test state tracking
122static struct {
123 StringS tests; // All requested test names
124 ssize_t current = -1; // Index of next test to run
125 bool has_failed = false; // True if any test failed
126} ui_test_state;
127
128String
129ServerImpl::ui_test_fetch ()
130{
131 // Initialize tests on first call
132 if (ui_test_state.tests.empty() && !App.ui_tests.empty()) {
133 ui_test_state.tests = App.ui_tests;
134 ui_test_state.current = -1;
135 ui_test_state.has_failed = false;
136 }
137 // Keep running tests only as long they pass
138 if (ui_test_state.has_failed || ui_test_state.current + 1 >= ui_test_state.tests.size())
139 return "";
140 // Yield current test name
141 const String testname = ui_test_state.tests[++ui_test_state.current];
142 printerr ("%s %s\n", " CHECKING ", testname);
143 return testname;
144}
145
146void
147ServerImpl::ui_test_report (const String &testname, bool success)
148{
149 if (success && ui_test_state.current >= 0 &&
150 ui_test_state.current < ui_test_state.tests.size() &&
151 testname == ui_test_state.tests[ui_test_state.current])
152 printerr ("%s %s\n", " PASS ", testname);
153 else {
154 printerr ("%s %s\n", " FAIL ", testname);
155 ui_test_state.has_failed = true;
156 }
157 // Exit if all tests completed or failed
158 if (ui_test_state.current >= ui_test_state.tests.size() || ui_test_state.has_failed)
159 main_loop->add ([] () { main_loop->quit (ui_test_state.has_failed ? 1 : 0); });
160}
161
162String
163ServerImpl::ui_js_fetch ()
164{
165 return App.ui_js;
166}
167
168ServerImplP
169ServerImpl::instancep ()
170{
171 static ServerImplP *sptr = new ServerImplP (std::make_shared<ServerImpl>());
172 return *sptr;
173}
174
175bool
176ServerImpl::set_data (const String &key, const Value &value)
177{
178 const String ckey = canonify_key (key);
179 if (ckey.size() && ckey[0] != '_')
180 {
181 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
182 emit_event ("data", key);
183 return Path::stringwrite (filename, value.as_string());
184 }
185 else
186 return GadgetImpl::set_data (ckey, value);
187}
188
189Value
190ServerImpl::get_data (const String &key) const
191{
192 const String ckey = canonify_key (key);
193 if (ckey.size() && ckey[0] != '_')
194 {
195 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
196 return Path::stringread (filename);
197 }
198 else
199 return GadgetImpl::get_data (ckey);
200}
201
202// == Server ==
203ServerP
204Server::instancep ()
205{
206 return ServerImpl::instancep();
207}
208
209Server&
210Server::instance ()
211{
212 return *instancep();
213}
214
215// == FileCrawler ==
216ResourceCrawlerP
217Server::dir_crawler (const String &cwd)
218{
219 return FileCrawler::make_shared (cwd, true, false);
220}
221
222ResourceCrawlerP
223Server::url_crawler (const String &url)
224{
225 if (App.web_socket_server) {
226 String dir = App.web_socket_server->map_url (url);
227 if (!dir.empty())
228 return FileCrawler::make_shared (dir, false, false);
229 }
230 return nullptr;
231}
232
233String
234Server::engine_stats ()
235{
236 const String s = "Unused"; // TODO: get stats from trkn
237 printerr ("Server::engine_stats:\n%s\n", s);
238 return s;
239}
240
241void
242Server::exit_program (int status)
243{
244 main_loop->quit (status);
245}
246
247// == Choice ==
248Choice::Choice (String ident_, String label_, String blurb_, String notice_, String warning_) :
249 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
250 label (label_), blurb (blurb_), notice (notice_), warning (warning_)
251{
252 assert_return (ident.empty() == false);
253}
254
255Choice::Choice (String ident_, IconString icon_, String label_, String blurb_, String notice_, String warning_) :
256 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
257 icon (icon_), label (label_), blurb (blurb_), notice (notice_), warning (warning_)
258{
259 assert_return (ident.empty() == false);
260}
261
262Choice::Choice (IconString icon_, String label_, String blurb_) :
263 Choice ("", icon_, label_, blurb_)
264{}
265
266ChoiceS&
267operator+= (ChoiceS &choices, Choice &&newchoice)
268{
269 choices.push_back (std::move (newchoice));
270 return choices;
271}
272
273// == Error ==
275const char*
277{
278 switch (error)
279 {
280 // errno aliases are left to strerror
281 case Error::NONE: return _("OK");
282 // Ase specific errors
283 case Error::INTERNAL: return _("Internal error (please report)");
284 // file errors
285 case Error::FILE_EOF: return _("End of file");
286 case Error::FILE_OPEN_FAILED: return _("Open failed");
287 case Error::FILE_SEEK_FAILED: return _("Seek failed");
288 case Error::FILE_READ_FAILED: return _("Read failed");
289 case Error::FILE_WRITE_FAILED: return _("Write failed");
290 // content errors
291 case Error::PARSE_ERROR: return _("Parsing error");
292 case Error::NO_HEADER: return _("Failed to detect header");
293 case Error::NO_SEEK_INFO: return _("Failed to retrieve seek information");
294 case Error::NO_DATA_AVAILABLE: return _("No data available");
295 case Error::DATA_CORRUPT: return _("Data corrupt");
296 case Error::WRONG_N_CHANNELS: return _("Wrong number of channels");
297 case Error::FORMAT_INVALID: return _("Invalid format");
298 case Error::FORMAT_UNKNOWN: return _("Unknown format");
299 case Error::DATA_UNMATCHED: return _("Requested data values unmatched");
300 case Error::CODEC_FAILURE: return _("Codec failure");
301 case Error::BROKEN_ARCHIVE: return _("Broken archive");
302 case Error::BAD_PROJECT: return _("Not a valid project");
303 case Error::NO_PROJECT_DIR: return _("Missing project directory");
304 // Device errors
305 case Error::DEVICE_NOT_AVAILABLE: return _("No device (driver) available");
306 case Error::DEVICE_ASYNC: return _("Device not async capable");
307 case Error::DEVICE_BUSY: return _("Device busy");
308 case Error::DEVICE_FORMAT: return _("Failed to configure device format");
309 case Error::DEVICE_BUFFER: return _("Failed to configure device buffer");
310 case Error::DEVICE_LATENCY: return _("Failed to configure device latency");
311 case Error::DEVICE_CHANNELS: return _("Failed to configure number of device channels");
312 case Error::DEVICE_FREQUENCY: return _("Failed to configure device frequency");
313 case Error::DEVICES_MISMATCH: return _("Device configurations mismatch");
314 // miscellaneous errors
315 case Error::WAVE_NOT_FOUND: return _("No such wave");
316 case Error::UNIMPLEMENTED: return _("Functionality not implemented");
317 case Error::INVALID_PROPERTY: return _("Invalid object property");
318 case Error::INVALID_MIDI_CONTROL: return _("Invalid MIDI control type");
319 case Error::OPERATION_BUSY: return _("Operation already in prgress");
320 default:
321 return strerror (int (error));
322 }
323}
324
325// Map errno onto Ase::Error.
326Error
327ase_error_from_errno (int sys_errno, Error fallback)
328{
329 if (sys_errno < int (Error::INTERNAL))
330 return Error (sys_errno); // Error includes errnos
331 else
332 return fallback;
333}
334
335String
336ServerImpl::error_blurb (Error error) const
337{
338 return ase_error_blurb (error);
339}
340
341// == MusicalTuning ==
342static EnumInfo
343musical_tuning_info (MusicalTuning musicaltuning)
344{
345 switch (musicaltuning)
346 {
347 // Equal Temperament: http://en.wikipedia.org/wiki/Equal_temperament
348 case MusicalTuning::OD_12_TET:
349 return { _("12 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
350 _("The most common tuning system for modern Western music, "
351 "is the twelve-tone equal temperament, abbreviated as 12-TET, "
352 "which divides the octave into 12 equal parts.") };
353 case MusicalTuning::OD_7_TET:
354 return { _("7 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
355 _("A fairly common tuning system is the seven-tone equal temperament tuning system, "
356 "abbreviated as 7-TET. It divides the octave into 7 equal parts using 171 cent steps.") };
357 case MusicalTuning::OD_5_TET:
358 return { _("5 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
359 _("A fairly common tuning system is the five-tone equal temperament tuning system, "
360 "abbreviated as 5-TET. It divides the octave into 5 equal parts using 240 cent steps.") };
361 // Rational Intonation: http://en.wikipedia.org/wiki/Just_intonation
362 case MusicalTuning::DIATONIC_SCALE:
363 return { _("Diatonic Scale"), // http://en.wikipedia.org/wiki/Diatonic_scale
364 _("In music theory, a diatonic scale (also: heptatonia prima) is a seven-note "
365 "musical scale comprising five whole-tone and two half-tone steps. "
366 "The half tones are maximally separated, so between two half-tone steps "
367 "there are either two or three whole tones, repeating per octave.") }; // Werckmeister I
368 case MusicalTuning::INDIAN_SCALE:
369 return { _("Indian Scale"), // http://en.wikipedia.org/wiki/Just_intonation#Indian_scales
370 _("Diatonic scale used in Indian music with wolf interval at Dha, close to 3/2") };
371 case MusicalTuning::PYTHAGOREAN_TUNING:
372 return { _("Pythagorean Tuning"), // http://en.wikipedia.org/wiki/Pythagorean_tuning
373 _("Pythagorean tuning is the oldest way of tuning the 12-note chromatic scale, "
374 "in which the frequency relationships of all intervals are based on the ratio 3:2. "
375 "Its discovery is generally credited to Pythagoras.") };
376 case MusicalTuning::PENTATONIC_5_LIMIT:
377 return { _("Pentatonic 5-limit"), // http://en.wikipedia.org/wiki/Pentatonic_scale
378 _("Pentatonic scales are used in modern jazz and pop/rock contexts "
379 "because they work exceedingly well over several chords diatonic "
380 "to the same key, often better than the parent scale.") };
381 case MusicalTuning::PENTATONIC_BLUES:
382 return { _("Pentatonic Blues"), // http://en.wikipedia.org/wiki/Pentatonic_scale
383 _("The blues scale is the minor pentatonic with an additional augmented fourth, "
384 "which is referred to as the \"blues note\".") };
385 case MusicalTuning::PENTATONIC_GOGO:
386 return { _("Pentatonic Gogo"), // http://en.wikipedia.org/wiki/Pentatonic_scale
387 _("The Pentatonic Gogo scale is an anhemitonic pentatonic scale used to tune the "
388 "instruments of the Gogo people of Tanzania.") };
389 // Meantone Temperament: http://en.wikipedia.org/wiki/Meantone_temperament
390 case MusicalTuning::QUARTER_COMMA_MEANTONE:
391 return { _("Quarter-Comma Meantone"), // http://en.wikipedia.org/wiki/Quarter-comma_meantone
392 _("Quarter-comma meantone was the most common meantone temperament in the "
393 "sixteenth and seventeenth centuries and sometimes used later.") }; // Werckmeister II
394 case MusicalTuning::SILBERMANN_SORGE:
395 return { _("Silbermann-Sorge Temperament"), // http://de.wikipedia.org/wiki/Silbermann-Sorge-Temperatur
396 _("The Silbermann-Sorge temperament is a meantone temperament used for "
397 "Baroque era organs by Gottfried Silbermann.") };
398 // Well Temperament: http://en.wikipedia.org/wiki/Well_temperament
399 case MusicalTuning::WERCKMEISTER_3:
400 return { _("Werckmeister III"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
401 _("This tuning uses mostly pure (perfect) fifths, as in Pythagorean tuning, but each "
402 "of the fifths C-G, G-D, D-A and B-F# is made smaller, i.e. tempered by 1/4 comma. "
403 "Werckmeister designated this tuning as particularly suited for playing chromatic music.") };
404 case MusicalTuning::WERCKMEISTER_4:
405 return { _("Werckmeister IV"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
406 _("In this tuning the fifths C-G, D-A, E-B, F#-C#, and Bb-F are tempered narrow by 1/3 comma, "
407 "and the fifths G#-D# and Eb-Bb are widened by 1/3 comma. The other fifths are pure. "
408 "Most of its intervals are close to sixth-comma meantone. "
409 "Werckmeister designed this tuning for playing mainly diatonic music.") };
410 case MusicalTuning::WERCKMEISTER_5:
411 return { _("Werckmeister V"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
412 _("In this tuning the fifths D-A, A-E, F#-C#, C#-G#, and F-C are narrowed by 1/4 comma, "
413 "and the fifth G#-D# is widened by 1/4 comma. The other fifths are pure. "
414 "This temperament is closer to equal temperament than Werckmeister III or IV.") };
415 case MusicalTuning::WERCKMEISTER_6:
416 return { _("Werckmeister VI"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
417 _("This tuning is also known as Septenarius tuning is based on a division of the monochord "
418 "length into 196 = 7 * 7 * 4 parts. "
419 "The resulting scale has rational frequency relationships, but in practice involves pure "
420 "and impure sounding fifths. "
421 "Werckmeister described the Septenarius as a \"temperament which has nothing at all to do "
422 "with the divisions of the comma, nevertheless in practice so correct that one can be really "
423 "satisfied with it\".") };
424 case MusicalTuning::KIRNBERGER_3:
425 return { _("Kirnberger III"), // http://en.wikipedia.org/wiki/Johann_Philipp_Kirnberger_temperament
426 _("Kirnberger's method of compensating for and closing the circle of fifths is to split the \"wolf\" "
427 "interval known to those who have used meantone temperaments between four fifths instead, "
428 "allowing for four 1/4-comma wolves to take their place. "
429 "1/4-comma wolves are used extensively in meantone and are much easier to tune and to listen to. "
430 "Therefore, only one third remains pure (between C and E).") };
431 case MusicalTuning::YOUNG:
432 return { _("Young Temperament"), // http://en.wikipedia.org/wiki/Young_temperament
433 _("Thomas Young devised a form of musical tuning to make the harmony most perfect in those keys which "
434 "are the most frequently used (give better major thirds in those keys), but to not have any unplayable keys. "
435 "This is attempted by tuning upwards from C a sequence of six pure fourths, "
436 "as well as six equally imperfect fifths.") };
437 default:
438 return { "", "" };
439 }
440}
441static bool musical_tuning_info__ = EnumInfo::impl (musical_tuning_info);
442
443String
444ServerImpl::musical_tuning_blurb (MusicalTuning musicaltuning) const
445{
446 return EnumInfo::value_info (musicaltuning).blurb;
447}
448
449String
450ServerImpl::musical_tuning_label (MusicalTuning musicaltuning) const
451{
452 return EnumInfo::value_info (musicaltuning).label;
453}
454
455static std::atomic<uint> user_note_id = 1;
456
457uint64
458ServerImpl::user_note (const String &text, const String &channel, UserNote::Flags flags, const String &rest)
459{
460 UserNote unote { user_note_id++, flags, channel.empty() ? "misc" : channel, text, rest };
461 ValueR vrec;
462 json_parse (json_stringify (unote), vrec);
463 this->emit_event ("usernote", "", vrec);
464 String s;
465 s += string_format ("%s: usernote[%04x]: %s: %s", program_alias(), unote.noteid, unote.channel, unote.text);
466 if (!unote.rest.empty())
467 s += " (" + unote.rest + ")";
468 printerr ("%s\n", string_replace (s, "\n", "\t"));
469 return unote.noteid;
470}
471
472bool
473ServerImpl::user_reply (uint64 noteid, uint r)
474{
475 return false; // unhandled
476}
477
478ServerImpl::Block
479ServerImpl::telemem_allocate (uint32 length) const
480{
481 return telemetry_arena.allocate (length);
482}
483
484void
485ServerImpl::telemem_release (Block telememblock) const
486{
487 telemetry_arena.release (telememblock);
488}
489
490ptrdiff_t
491ServerImpl::telemem_start () const
492{
493 return telemetry_arena.location();
494}
495
496static bool
497validate_telemetry_segments (const TelemetrySegmentS &segments, size_t *payloadlength)
498{
499 *payloadlength = 0;
500 const TelemetrySegment *last = nullptr;
501 for (const auto &seg : segments)
502 {
503 if (last && seg.offset < last->offset + last->length)
504 return false; // check sorting and non-overlapping
505 if (seg.offset < 0 || (seg.offset & 3) || seg.length <= 0 || (seg.length & 3) ||
506 size_t (seg.offset + seg.length) > telemetry_size)
507 return false;
508 *payloadlength += seg.length;
509 last = &seg;
510 }
511 return true;
512}
513
514ASE_CLASS_DECLS (TelemetryPlan);
515class TelemetryPlan : public std::enable_shared_from_this<TelemetryPlan> {
516public:
517 int32 interval_ms_ = -1;
518 LoopID timerid_ = LoopID::INVALID;
519 JsonapiBinarySender send_blob_;
520 TelemetrySegmentS segments_;
521 const char *telemem_ = nullptr;
522 String payload_;
523 void send_telemetry();
524 void setup (const char *start, size_t payloadlength, const TelemetrySegmentS &plan, int32 interval_ms);
526};
527static CustomDataKey<TelemetryPlanP> telemetry_key;
528
529bool
530ServerImpl::broadcast_telemetry (const TelemetrySegmentS &segments, int32 interval_ms)
531{
532 size_t payloadlength = 0;
533 if (!validate_telemetry_segments (segments, &payloadlength))
534 {
535 warning ("%s: invalid segment list", "Ase::ServerImpl::broadcast_telemetry");
536 return false;
537 }
538 CustomDataContainer *cdata = jsonapi_connection_data();
539 if (!cdata)
540 {
541 warning ("%s: cannot broadcast telemetry without jsonapi connection", "Ase::ServerImpl::broadcast_telemetry");
542 return false;
543 }
544 TelemetryPlanP tplan = cdata->get_custom_data (&telemetry_key);
545 if (!tplan)
546 {
548 cdata->set_custom_data (&telemetry_key, tplan);
549 tplan->send_blob_ = jsonapi_connection_sender();
550 }
551 tplan->setup ((const char*) telemetry_arena.location(), payloadlength, segments, interval_ms);
552 return true;
553}
554
555void
556TelemetryPlan::setup (const char *start, size_t payloadlength, const TelemetrySegmentS &segments, int32 interval_ms)
557{
558 if (timerid_ == LoopID::INVALID || interval_ms_ != interval_ms)
559 {
560 if (timerid_ != LoopID::INVALID)
561 main_loop->cancel (timerid_);
562 auto tplan = shared_from_this();
563 auto send_telemetry = [tplan] () { tplan->send_telemetry(); return true; };
564 interval_ms_ = interval_ms;
565 timerid_ = interval_ms <= 0 || segments.empty() ? LoopID::INVALID : main_loop->add (send_telemetry, std::chrono::milliseconds (interval_ms));
566 }
567 if (timerid_ != LoopID::INVALID)
568 {
569 telemem_ = start;
570 segments_ = segments;
571 payload_.resize (payloadlength);
572 }
573 else
574 {
575 telemem_ = nullptr;
576 segments_ = {};
577 payload_.clear();
578 }
579}
580
581void
582TelemetryPlan::send_telemetry ()
583{
584 // Safety check: don't send if telemetry memory or segments are invalid
585 if (!telemem_ || segments_.empty() || payload_.empty())
586 return;
587 char *data = &payload_[0];
588 size_t datapos = 0;
589 for (const auto &seg : segments_) // offsets and lengths were validated earlier
590 {
591 memcpy (data + datapos, telemem_ + seg.offset, seg.length);
592 datapos += seg.length;
593 }
594 // send_blob_ handles the case where the connection is closed (returns false)
595 (void) send_blob_ (payload_);
596}
597
598TelemetryPlan::~TelemetryPlan()
599{
600 if (timerid_ != LoopID::INVALID)
601 {
602 // Only cancel if the loop is still running
603 if (!main_loop->has_quit())
604 main_loop->cancel (timerid_);
605 timerid_ = LoopID::INVALID;
606 }
607}
608
609} // Ase
T begin(T... args)
DataListContainer - typesafe storage and retrieval of arbitrary members.
Definition utils.hh:85
T get_custom_data(CustomDataKey< T > *key) const
Retrieve contents of the custom keyed data member, returns DataKey::fallback if nothing was set.
Definition utils.hh:101
void set_custom_data(CustomDataKey< T > *key, T data)
Assign data to the custom keyed data member, deletes any previously set data.
Definition utils.hh:98
CustomDataKey objects are used to identify and manage custom data members of CustomDataContainer obje...
Definition utils.hh:69
bool broadcast_telemetry(const TelemetrySegmentS &plan, int32 interval_ms) override
Broadcast telemetry memory segments to the current Jsonipc connection.
Definition server.cc:530
Central singleton, serves as API entry point.
Definition api.hh:394
T clear(T... args)
T data(T... args)
T empty(T... args)
T end(T... args)
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:28
#define _(...)
Retrieve the translation of a C or C++ string.
Definition internal.hh:17
memcpy
The Anklang C++ API namespace.
Definition api.hh:8
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
bool has_ui_tests
Whether any UI tests are pending.
Definition api.hh:389
String string_to_identifier(const String &input)
Force lower case, alphanumerics + underscore and non-digit start.
Definition strings.cc:54
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:24
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:27
bool json_parse(const String &jsonstring, T &target)
Parse a well formed JSON string and assign contents to target.
Definition serialize.hh:537
Error
Enum representing Error states.
Definition api.hh:21
bool auto_exit
Whether to auto-exit after tests complete.
Definition api.hh:390
const char * ase_error_blurb(Error error)
Describe Error condition.
Definition server.cc:276
String string_replace(const String &input, const String &marker, const String &replacement, size_t maxn)
Replace substring marker in input with replacement, at most maxn times.
Definition strings.cc:1144
ChoiceS & operator+=(ChoiceS &choices, Choice &&newchoice)
Convenience ChoiceS construction helper.
Definition server.cc:267
String program_alias()
Retrieve the program name as used for logging or debug messages.
Definition platform.cc:817
const char * ase_version()
Provide a string containing the package version.
Definition platform.cc:803
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:34
uint32_t uint32
A 32-bit unsigned integer.
Definition cxxaux.hh:23
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:17
String json_stringify(const T &source, Writ::Flags flags=Writ::Flags(0))
Create JSON string from source.
Definition serialize.hh:529
MusicalTuning
Musical tunings, see: http://en.wikipedia.org/wiki/Musical_tuning.
Definition api.hh:82
const char * ase_build_id()
Provide a string containing the ASE library build id.
Definition platform.cc:809
Configuration values for the UI.
Definition api.hh:388
unsigned long long uint64
T resize(T... args)
T size(T... args)
typedef uint8_t
strerror
Representation of one possible choice for selection properties.
Definition api.hh:95
uint64 location() const
Address of memory area.
Definition memory.cc:340
Block allocate(uint32 length) const
Create a memory block from cache-line aligned memory area, MT-Unsafe.
Definition memory.cc:371
void release(Block allocatedblock) const
Realease a previously allocated block, MT-Unsafe.
Definition memory.cc:380
Value type used to interface with various property types.
Definition value.hh:53
String as_string() const
Convert Value to a string, not very useful for RECORD or ARRAY.
Definition value.cc:95
typedef ssize_t