Anklang-0.3.0.dev835+g24d8ae08 anklang-0.3.0.dev835+g24d8ae08
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
162ServerImplP
163ServerImpl::instancep ()
164{
165 static ServerImplP *sptr = new ServerImplP (std::make_shared<ServerImpl>());
166 return *sptr;
167}
168
169bool
170ServerImpl::set_data (const String &key, const Value &value)
171{
172 const String ckey = canonify_key (key);
173 if (ckey.size() && ckey[0] != '_')
174 {
175 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
176 emit_event ("data", key);
177 return Path::stringwrite (filename, value.as_string());
178 }
179 else
180 return GadgetImpl::set_data (ckey, value);
181}
182
183Value
184ServerImpl::get_data (const String &key) const
185{
186 const String ckey = canonify_key (key);
187 if (ckey.size() && ckey[0] != '_')
188 {
189 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
190 return Path::stringread (filename);
191 }
192 else
193 return GadgetImpl::get_data (ckey);
194}
195
196// == Server ==
197ServerP
198Server::instancep ()
199{
200 return ServerImpl::instancep();
201}
202
203Server&
204Server::instance ()
205{
206 return *instancep();
207}
208
209// == FileCrawler ==
210ResourceCrawlerP
211Server::dir_crawler (const String &cwd)
212{
213 return FileCrawler::make_shared (cwd, true, false);
214}
215
216ResourceCrawlerP
217Server::url_crawler (const String &url)
218{
219 if (App.web_socket_server) {
220 String dir = App.web_socket_server->map_url (url);
221 if (!dir.empty())
222 return FileCrawler::make_shared (dir, false, false);
223 }
224 return nullptr;
225}
226
227String
228Server::engine_stats ()
229{
230 const String s = "Unused"; // TODO: get stats from trkn
231 printerr ("Server::engine_stats:\n%s\n", s);
232 return s;
233}
234
235void
236Server::exit_program (int status)
237{
238 main_loop->quit (status);
239}
240
241// == Choice ==
242Choice::Choice (String ident_, String label_, String blurb_, String notice_, String warning_) :
243 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
244 label (label_), blurb (blurb_), notice (notice_), warning (warning_)
245{
246 assert_return (ident.empty() == false);
247}
248
249Choice::Choice (String ident_, IconString icon_, String label_, String blurb_, String notice_, String warning_) :
250 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
251 icon (icon_), label (label_), blurb (blurb_), notice (notice_), warning (warning_)
252{
253 assert_return (ident.empty() == false);
254}
255
256Choice::Choice (IconString icon_, String label_, String blurb_) :
257 Choice ("", icon_, label_, blurb_)
258{}
259
260ChoiceS&
261operator+= (ChoiceS &choices, Choice &&newchoice)
262{
263 choices.push_back (std::move (newchoice));
264 return choices;
265}
266
267// == Error ==
269const char*
271{
272 switch (error)
273 {
274 // errno aliases are left to strerror
275 case Error::NONE: return _("OK");
276 // Ase specific errors
277 case Error::INTERNAL: return _("Internal error (please report)");
278 // file errors
279 case Error::FILE_EOF: return _("End of file");
280 case Error::FILE_OPEN_FAILED: return _("Open failed");
281 case Error::FILE_SEEK_FAILED: return _("Seek failed");
282 case Error::FILE_READ_FAILED: return _("Read failed");
283 case Error::FILE_WRITE_FAILED: return _("Write failed");
284 // content errors
285 case Error::PARSE_ERROR: return _("Parsing error");
286 case Error::NO_HEADER: return _("Failed to detect header");
287 case Error::NO_SEEK_INFO: return _("Failed to retrieve seek information");
288 case Error::NO_DATA_AVAILABLE: return _("No data available");
289 case Error::DATA_CORRUPT: return _("Data corrupt");
290 case Error::WRONG_N_CHANNELS: return _("Wrong number of channels");
291 case Error::FORMAT_INVALID: return _("Invalid format");
292 case Error::FORMAT_UNKNOWN: return _("Unknown format");
293 case Error::DATA_UNMATCHED: return _("Requested data values unmatched");
294 case Error::CODEC_FAILURE: return _("Codec failure");
295 case Error::BROKEN_ARCHIVE: return _("Broken archive");
296 case Error::BAD_PROJECT: return _("Not a valid project");
297 case Error::NO_PROJECT_DIR: return _("Missing project directory");
298 // Device errors
299 case Error::DEVICE_NOT_AVAILABLE: return _("No device (driver) available");
300 case Error::DEVICE_ASYNC: return _("Device not async capable");
301 case Error::DEVICE_BUSY: return _("Device busy");
302 case Error::DEVICE_FORMAT: return _("Failed to configure device format");
303 case Error::DEVICE_BUFFER: return _("Failed to configure device buffer");
304 case Error::DEVICE_LATENCY: return _("Failed to configure device latency");
305 case Error::DEVICE_CHANNELS: return _("Failed to configure number of device channels");
306 case Error::DEVICE_FREQUENCY: return _("Failed to configure device frequency");
307 case Error::DEVICES_MISMATCH: return _("Device configurations mismatch");
308 // miscellaneous errors
309 case Error::WAVE_NOT_FOUND: return _("No such wave");
310 case Error::UNIMPLEMENTED: return _("Functionality not implemented");
311 case Error::INVALID_PROPERTY: return _("Invalid object property");
312 case Error::INVALID_MIDI_CONTROL: return _("Invalid MIDI control type");
313 case Error::OPERATION_BUSY: return _("Operation already in prgress");
314 default:
315 return strerror (int (error));
316 }
317}
318
319// Map errno onto Ase::Error.
320Error
321ase_error_from_errno (int sys_errno, Error fallback)
322{
323 if (sys_errno < int (Error::INTERNAL))
324 return Error (sys_errno); // Error includes errnos
325 else
326 return fallback;
327}
328
329String
330ServerImpl::error_blurb (Error error) const
331{
332 return ase_error_blurb (error);
333}
334
335// == MusicalTuning ==
336static EnumInfo
337musical_tuning_info (MusicalTuning musicaltuning)
338{
339 switch (musicaltuning)
340 {
341 // Equal Temperament: http://en.wikipedia.org/wiki/Equal_temperament
342 case MusicalTuning::OD_12_TET:
343 return { _("12 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
344 _("The most common tuning system for modern Western music, "
345 "is the twelve-tone equal temperament, abbreviated as 12-TET, "
346 "which divides the octave into 12 equal parts.") };
347 case MusicalTuning::OD_7_TET:
348 return { _("7 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
349 _("A fairly common tuning system is the seven-tone equal temperament tuning system, "
350 "abbreviated as 7-TET. It divides the octave into 7 equal parts using 171 cent steps.") };
351 case MusicalTuning::OD_5_TET:
352 return { _("5 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
353 _("A fairly common tuning system is the five-tone equal temperament tuning system, "
354 "abbreviated as 5-TET. It divides the octave into 5 equal parts using 240 cent steps.") };
355 // Rational Intonation: http://en.wikipedia.org/wiki/Just_intonation
356 case MusicalTuning::DIATONIC_SCALE:
357 return { _("Diatonic Scale"), // http://en.wikipedia.org/wiki/Diatonic_scale
358 _("In music theory, a diatonic scale (also: heptatonia prima) is a seven-note "
359 "musical scale comprising five whole-tone and two half-tone steps. "
360 "The half tones are maximally separated, so between two half-tone steps "
361 "there are either two or three whole tones, repeating per octave.") }; // Werckmeister I
362 case MusicalTuning::INDIAN_SCALE:
363 return { _("Indian Scale"), // http://en.wikipedia.org/wiki/Just_intonation#Indian_scales
364 _("Diatonic scale used in Indian music with wolf interval at Dha, close to 3/2") };
365 case MusicalTuning::PYTHAGOREAN_TUNING:
366 return { _("Pythagorean Tuning"), // http://en.wikipedia.org/wiki/Pythagorean_tuning
367 _("Pythagorean tuning is the oldest way of tuning the 12-note chromatic scale, "
368 "in which the frequency relationships of all intervals are based on the ratio 3:2. "
369 "Its discovery is generally credited to Pythagoras.") };
370 case MusicalTuning::PENTATONIC_5_LIMIT:
371 return { _("Pentatonic 5-limit"), // http://en.wikipedia.org/wiki/Pentatonic_scale
372 _("Pentatonic scales are used in modern jazz and pop/rock contexts "
373 "because they work exceedingly well over several chords diatonic "
374 "to the same key, often better than the parent scale.") };
375 case MusicalTuning::PENTATONIC_BLUES:
376 return { _("Pentatonic Blues"), // http://en.wikipedia.org/wiki/Pentatonic_scale
377 _("The blues scale is the minor pentatonic with an additional augmented fourth, "
378 "which is referred to as the \"blues note\".") };
379 case MusicalTuning::PENTATONIC_GOGO:
380 return { _("Pentatonic Gogo"), // http://en.wikipedia.org/wiki/Pentatonic_scale
381 _("The Pentatonic Gogo scale is an anhemitonic pentatonic scale used to tune the "
382 "instruments of the Gogo people of Tanzania.") };
383 // Meantone Temperament: http://en.wikipedia.org/wiki/Meantone_temperament
384 case MusicalTuning::QUARTER_COMMA_MEANTONE:
385 return { _("Quarter-Comma Meantone"), // http://en.wikipedia.org/wiki/Quarter-comma_meantone
386 _("Quarter-comma meantone was the most common meantone temperament in the "
387 "sixteenth and seventeenth centuries and sometimes used later.") }; // Werckmeister II
388 case MusicalTuning::SILBERMANN_SORGE:
389 return { _("Silbermann-Sorge Temperament"), // http://de.wikipedia.org/wiki/Silbermann-Sorge-Temperatur
390 _("The Silbermann-Sorge temperament is a meantone temperament used for "
391 "Baroque era organs by Gottfried Silbermann.") };
392 // Well Temperament: http://en.wikipedia.org/wiki/Well_temperament
393 case MusicalTuning::WERCKMEISTER_3:
394 return { _("Werckmeister III"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
395 _("This tuning uses mostly pure (perfect) fifths, as in Pythagorean tuning, but each "
396 "of the fifths C-G, G-D, D-A and B-F# is made smaller, i.e. tempered by 1/4 comma. "
397 "Werckmeister designated this tuning as particularly suited for playing chromatic music.") };
398 case MusicalTuning::WERCKMEISTER_4:
399 return { _("Werckmeister IV"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
400 _("In this tuning the fifths C-G, D-A, E-B, F#-C#, and Bb-F are tempered narrow by 1/3 comma, "
401 "and the fifths G#-D# and Eb-Bb are widened by 1/3 comma. The other fifths are pure. "
402 "Most of its intervals are close to sixth-comma meantone. "
403 "Werckmeister designed this tuning for playing mainly diatonic music.") };
404 case MusicalTuning::WERCKMEISTER_5:
405 return { _("Werckmeister V"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
406 _("In this tuning the fifths D-A, A-E, F#-C#, C#-G#, and F-C are narrowed by 1/4 comma, "
407 "and the fifth G#-D# is widened by 1/4 comma. The other fifths are pure. "
408 "This temperament is closer to equal temperament than Werckmeister III or IV.") };
409 case MusicalTuning::WERCKMEISTER_6:
410 return { _("Werckmeister VI"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
411 _("This tuning is also known as Septenarius tuning is based on a division of the monochord "
412 "length into 196 = 7 * 7 * 4 parts. "
413 "The resulting scale has rational frequency relationships, but in practice involves pure "
414 "and impure sounding fifths. "
415 "Werckmeister described the Septenarius as a \"temperament which has nothing at all to do "
416 "with the divisions of the comma, nevertheless in practice so correct that one can be really "
417 "satisfied with it\".") };
418 case MusicalTuning::KIRNBERGER_3:
419 return { _("Kirnberger III"), // http://en.wikipedia.org/wiki/Johann_Philipp_Kirnberger_temperament
420 _("Kirnberger's method of compensating for and closing the circle of fifths is to split the \"wolf\" "
421 "interval known to those who have used meantone temperaments between four fifths instead, "
422 "allowing for four 1/4-comma wolves to take their place. "
423 "1/4-comma wolves are used extensively in meantone and are much easier to tune and to listen to. "
424 "Therefore, only one third remains pure (between C and E).") };
425 case MusicalTuning::YOUNG:
426 return { _("Young Temperament"), // http://en.wikipedia.org/wiki/Young_temperament
427 _("Thomas Young devised a form of musical tuning to make the harmony most perfect in those keys which "
428 "are the most frequently used (give better major thirds in those keys), but to not have any unplayable keys. "
429 "This is attempted by tuning upwards from C a sequence of six pure fourths, "
430 "as well as six equally imperfect fifths.") };
431 default:
432 return { "", "" };
433 }
434}
435static bool musical_tuning_info__ = EnumInfo::impl (musical_tuning_info);
436
437String
438ServerImpl::musical_tuning_blurb (MusicalTuning musicaltuning) const
439{
440 return EnumInfo::value_info (musicaltuning).blurb;
441}
442
443String
444ServerImpl::musical_tuning_label (MusicalTuning musicaltuning) const
445{
446 return EnumInfo::value_info (musicaltuning).label;
447}
448
449static std::atomic<uint> user_note_id = 1;
450
451uint64
452ServerImpl::user_note (const String &text, const String &channel, UserNote::Flags flags, const String &rest)
453{
454 UserNote unote { user_note_id++, flags, channel.empty() ? "misc" : channel, text, rest };
455 ValueR vrec;
456 json_parse (json_stringify (unote), vrec);
457 this->emit_event ("usernote", "", vrec);
458 String s;
459 s += string_format ("%s: usernote[%04x]: %s: %s", program_alias(), unote.noteid, unote.channel, unote.text);
460 if (!unote.rest.empty())
461 s += " (" + unote.rest + ")";
462 printerr ("%s\n", string_replace (s, "\n", "\t"));
463 return unote.noteid;
464}
465
466bool
467ServerImpl::user_reply (uint64 noteid, uint r)
468{
469 return false; // unhandled
470}
471
472ServerImpl::Block
473ServerImpl::telemem_allocate (uint32 length) const
474{
475 return telemetry_arena.allocate (length);
476}
477
478void
479ServerImpl::telemem_release (Block telememblock) const
480{
481 telemetry_arena.release (telememblock);
482}
483
484ptrdiff_t
485ServerImpl::telemem_start () const
486{
487 return telemetry_arena.location();
488}
489
490static bool
491validate_telemetry_segments (const TelemetrySegmentS &segments, size_t *payloadlength)
492{
493 *payloadlength = 0;
494 const TelemetrySegment *last = nullptr;
495 for (const auto &seg : segments)
496 {
497 if (last && seg.offset < last->offset + last->length)
498 return false; // check sorting and non-overlapping
499 if (seg.offset < 0 || (seg.offset & 3) || seg.length <= 0 || (seg.length & 3) ||
500 size_t (seg.offset + seg.length) > telemetry_size)
501 return false;
502 *payloadlength += seg.length;
503 last = &seg;
504 }
505 return true;
506}
507
508ASE_CLASS_DECLS (TelemetryPlan);
509class TelemetryPlan : public std::enable_shared_from_this<TelemetryPlan> {
510public:
511 int32 interval_ms_ = -1;
512 LoopID timerid_ = LoopID::INVALID;
513 JsonapiBinarySender send_blob_;
514 TelemetrySegmentS segments_;
515 const char *telemem_ = nullptr;
516 String payload_;
517 void send_telemetry();
518 void setup (const char *start, size_t payloadlength, const TelemetrySegmentS &plan, int32 interval_ms);
520};
521static CustomDataKey<TelemetryPlanP> telemetry_key;
522
523bool
524ServerImpl::broadcast_telemetry (const TelemetrySegmentS &segments, int32 interval_ms)
525{
526 size_t payloadlength = 0;
527 if (!validate_telemetry_segments (segments, &payloadlength))
528 {
529 warning ("%s: invalid segment list", "Ase::ServerImpl::broadcast_telemetry");
530 return false;
531 }
532 CustomDataContainer *cdata = jsonapi_connection_data();
533 if (!cdata)
534 {
535 warning ("%s: cannot broadcast telemetry without jsonapi connection", "Ase::ServerImpl::broadcast_telemetry");
536 return false;
537 }
538 TelemetryPlanP tplan = cdata->get_custom_data (&telemetry_key);
539 if (!tplan)
540 {
542 cdata->set_custom_data (&telemetry_key, tplan);
543 tplan->send_blob_ = jsonapi_connection_sender();
544 }
545 tplan->setup ((const char*) telemetry_arena.location(), payloadlength, segments, interval_ms);
546 return true;
547}
548
549void
550TelemetryPlan::setup (const char *start, size_t payloadlength, const TelemetrySegmentS &segments, int32 interval_ms)
551{
552 if (timerid_ == LoopID::INVALID || interval_ms_ != interval_ms)
553 {
554 if (timerid_ != LoopID::INVALID)
555 main_loop->cancel (timerid_);
556 auto tplan = shared_from_this();
557 auto send_telemetry = [tplan] () { tplan->send_telemetry(); return true; };
558 interval_ms_ = interval_ms;
559 timerid_ = interval_ms <= 0 || segments.empty() ? LoopID::INVALID : main_loop->add (send_telemetry, std::chrono::milliseconds (interval_ms));
560 }
561 if (timerid_ != LoopID::INVALID)
562 {
563 telemem_ = start;
564 segments_ = segments;
565 payload_.resize (payloadlength);
566 }
567 else
568 {
569 telemem_ = nullptr;
570 segments_ = {};
571 payload_.clear();
572 }
573}
574
575void
576TelemetryPlan::send_telemetry ()
577{
578 // Safety check: don't send if telemetry memory or segments are invalid
579 if (!telemem_ || segments_.empty() || payload_.empty())
580 return;
581 char *data = &payload_[0];
582 size_t datapos = 0;
583 for (const auto &seg : segments_) // offsets and lengths were validated earlier
584 {
585 memcpy (data + datapos, telemem_ + seg.offset, seg.length);
586 datapos += seg.length;
587 }
588 // send_blob_ handles the case where the connection is closed (returns false)
589 (void) send_blob_ (payload_);
590}
591
592TelemetryPlan::~TelemetryPlan()
593{
594 if (timerid_ != LoopID::INVALID)
595 {
596 // Only cancel if the loop is still running
597 if (!main_loop->has_quit())
598 main_loop->cancel (timerid_);
599 timerid_ = LoopID::INVALID;
600 }
601}
602
603} // Ase
T begin(T... args)
DataListContainer - typesafe storage and retrieval of arbitrary members.
Definition utils.hh:86
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:102
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:99
CustomDataKey objects are used to identify and manage custom data members of CustomDataContainer obje...
Definition utils.hh:70
bool broadcast_telemetry(const TelemetrySegmentS &plan, int32 interval_ms) override
Broadcast telemetry memory segments to the current Jsonipc connection.
Definition server.cc:524
Central singleton, serves as API entry point.
Definition api.hh:398
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:29
#define _(...)
Retrieve the translation of a C or C++ string.
Definition internal.hh:18
memcpy
The Anklang C++ API namespace.
Definition api.hh:9
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:393
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:25
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:28
bool json_parse(const String &jsonstring, T &target)
Parse a well formed JSON string and assign contents to target.
Definition serialize.hh:538
Error
Enum representing Error states.
Definition api.hh:22
bool auto_exit
Whether to auto-exit after tests complete.
Definition api.hh:394
const char * ase_error_blurb(Error error)
Describe Error condition.
Definition server.cc:270
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:261
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:35
uint32_t uint32
A 32-bit unsigned integer.
Definition cxxaux.hh:24
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
String json_stringify(const T &source, Writ::Flags flags=Writ::Flags(0))
Create JSON string from source.
Definition serialize.hh:530
MusicalTuning
Musical tunings, see: http://en.wikipedia.org/wiki/Musical_tuning.
Definition api.hh:83
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:392
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:96
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:54
String as_string() const
Convert Value to a string, not very useful for RECORD or ARRAY.
Definition value.cc:95
typedef ssize_t