settings() runs before MayaFlux::Init(). Anything you set here takes effect when the engine initialises and is locked for the lifetime of the process. Modifying config structs after Init() logs a warning and has no effect.
Defaults are intentionally reasonable: 48 kHz, 512-frame buffer, stereo output, 60 FPS, Vulkan rendering. Leave settings() empty if the defaults are adequate.
Configuration via JSON file
The entire engine configuration can be expressed as a JSON file and loaded in one call before Init(). Every config struct exposes a describe() method used by JSONSerializer; the JSON keys map directly to those field names.
void settings() {
}
bool load_config_from_file(const std::string &path)
Load engine configuration from a JSON file, applying any present fields to the pre-Init config struct...
Fields absent from the file retain their defaults.
The launcher binary loads a config file for you, so no call is needed. It uses mayaflux.json in the project source folder if that file exists, or the file named by --config path/to/file.json. The file is read before settings() runs, so values set in settings() win.
Pass --config-override (a flag, with no path) to reverse the order: settings() runs first and the file is loaded after it. The file then replaces the stream, graphics, input and network sections as a whole, so anything it does not mention returns to its default. The journal options are applied as calls on top of whatever is already set. The same behaviour can be compiled in with the MAYAFLUX_CONFIG_OVERRIDE define.
flowchart LR
subgraph N["Default: settings() wins"]
direction LR
n1["struct defaults"] --> n2["config file replaces<br/>stream, graphics, input, network"] --> n3["settings() edits on top"] --> n4["Init()"]
end
subgraph O["--config-override: the file wins"]
direction LR
o1["struct defaults"] --> o2["settings() edits"] --> o3["config file replaces<br/>stream, graphics, input, network"] --> o4["Init()"]
end
A complete file covering all four sections plus journal:
{
"stream": {
"sample_rate": 48000,
"buffer_size": 256,
"format": "FLOAT64",
"non_interleaved": false,
"output": { "enabled": true, "channels": 2, "device_id": -1, "device_name": "" },
"input": { "enabled": false, "channels": 2, "device_id": -1, "device_name": "" },
"priority": "REALTIME",
"handle_xruns": true,
"stream_latency_ms": 0.0
},
"graphics": {
"target_frame_rate": 60,
"backend_info": {
"device_preference": 0,
"device_index": -1,
"device_uuid": "",
"device_name": "",
"require_presentation": true,
"strict_device_selection": false
},
"surface_info": {
"format": "B8G8R8A8_SRGB",
"color_space": "SRGB_NONLINEAR",
"present_mode": "FIFO",
"image_count": 3,
"enable_hdr": false,
"measure_frame_time": false
},
"resource_limits": {
"max_windows": 16,
"max_staging_buffer_mb": 256,
"max_compute_buffer_mb": 1024,
"max_texture_cache_mb": 2048,
"max_descriptor_sets": 1024,
"max_pipelines": 256
},
"text_config": {
"family": "sans-serif",
"style": "",
"pixel_size": 24,
"atlas_size": 512
}
},
"input": {
"hid": { "enabled": false },
"midi": { "enabled": false },
"osc": { "enabled": false, "receive_port": 8000 },
"serial":{ "enabled": false }
},
"network": {
"udp": { "enabled": false, "default_receive_port": 8000, "default_send_port": 9000 },
"tcp": { "enabled": false, "listen_port": 0 },
"shared_memory": { "enabled": false }
},
"journal": {
"severity": "INFO",
"sink_to_console": false,
"log_file": "",
"disable_components": [],
"disable_contexts": [],
"include_components": [],
"include_contexts": []
}
}
Audio stream: <tt>GlobalStreamInfo</tt>
void settings() {
stream.output.device_name =
"";
stream.priority = Core::GlobalStreamInfo::StreamPriority::REALTIME;
stream.stream_latency_ms = 0.0;
}
Core::GlobalStreamInfo stream
Core::GlobalStreamInfo & get_global_stream_info()
Gets the stream configuration from the default engine.
The audio backend (PIPEWIRE, WASAPI, COREAUDIO) is selected at compile time and cannot be changed at runtime. Backend-specific tuning can be passed through stream.backend_options as an unordered_map<string, any>.
StreamPriority options: LOW, NORMAL, HIGH, REALTIME.
Graphics: <tt>GlobalGraphicsConfig</tt>
void settings() {
gfx.target_frame_rate = 60;
gfx.surface_info.present_mode = Core::GraphicsSurfaceInfo::PresentMode::FIFO;
gfx.surface_info.format = Core::GraphicsSurfaceInfo::SurfaceFormat::B8G8R8A8_SRGB;
gfx.surface_info.image_count = 3;
gfx.surface_info.enable_hdr = false;
gfx.text_config.family = "sans-serif";
gfx.text_config.pixel_size = 24;
gfx.text_config.atlas_size = 512;
gfx.resource_limits.max_texture_cache_mb = 2048;
gfx.resource_limits.max_compute_buffer_mb = 1024;
gfx.resource_limits.max_windows = 16;
}
Core::GlobalGraphicsConfig & get_global_graphics_config()
Gets the graphics configuration from the default engine.
PresentMode options: FIFO (vsync), IMMEDIATE (no vsync), MAILBOX (triple buffer), FIFO_RELAXED.
SurfaceFormat options: B8G8R8A8_SRGB (default), R8G8B8A8_SRGB, R16G16B16A16_SFLOAT (HDR), A2B10G10R10_UNORM, others.
The windowing backend (COCOA on macOS, WAYLAND on Linux, WINDOWS on Windows) is selected at compile time. WindowingBackend::NONE disables windowing entirely for headless/offline use and must be set if no windows are created.
Key repeat timing for native backends (Wayland, Win32, Cocoa) is in gfx.key_repeat_config.
GPU selection
On a machine with more than one GPU, gfx.backend_info decides which one the engine runs on. Every enumerated device is logged during startup with the information needed to pin it: (example)
GPU [0] AMD Radeon RX 7900 XTX (RADV NAVI31) | type=DiscreteGpu driver=MesaRadv (radv)
api=1.4.354 | uuid=00000000030000000000000000000000 | gfx=0 compute=1 transfer=0 |
present=gfx:yes mask:0x7 mesh=yes vram=24560MB pci_bus=3 | score=4623
Devices that cannot be used are listed too, with the reason: no graphics queue family, an API version below 1.3, no VK_KHR_swapchain, or no presentation support on the graphics queue family.
void settings() {
gfx.backend_info.device_preference =
Core::GraphicsBackendInfo::DevicePreference::DISCRETE;
gfx.backend_info.device_uuid = "00000000030000000000000000000000";
gfx.backend_info.device_name = "7900";
gfx.backend_info.strict_device_selection = true;
}
Selectors apply in precedence order: device_index, device_uuid, device_name, then device_preference as a scoring bias. device_index is an index into enumeration order, which is loader and driver dependent, so it is a debugging escape hatch rather than a durable setting. device_uuid is the only selector stable across driver updates and enumeration reordering.
DevicePreference options: AUTO, DISCRETE, INTEGRATED, VIRTUAL, EXTERNAL. In JSON these are integers in that order, since the enum does not currently serialise to a string.
EXTERNAL is a heuristic rather than a device class. Vulkan reports a Thunderbolt eGPU as a discrete GPU, indistinguishable from a built-in one, so EXTERNAL means discrete weighted toward the highest PCI bus number, on the reasoning that an externally attached device sits behind a PCIe switch well above the root complex. It needs VK_EXT_pci_bus_info, which is common on Linux and rare elsewhere; without it, EXTERNAL behaves as DISCRETE.
Set require_presentation to false for headless and compute-only work, including any run with windowing_backend set to NONE. With it true, a device whose graphics queue family cannot present is rejected.
MAYAFLUX_GPU overrides the config at runtime without a rebuild. An all-digits value is an index, anything else a name substring:
MAYAFLUX_GPU=1 ./my_piece
MAYAFLUX_GPU=intel ./my_piece
Selection composes below driver-level filtering rather than overriding it. VK_DRIVER_FILES, MESA_VK_DEVICE_SELECT, DRI_PRIME, and __NV_PRIME_RENDER_OFFLOAD all act before the engine sees the device list, so if a GPU is missing from the startup log entirely, one of those is the reason.
Device extensions
required_extensions and optional_extensions on gfx.backend_info request Vulkan device extensions beyond what the engine enables itself. A required extension the device does not support fails at startup with the name; an unsupported optional one is skipped with a warning.
gfx.backend_info.optional_extensions = { "VK_EXT_memory_budget" };
Input: <tt>GlobalInputConfig</tt>
Input backends are all disabled by default. Enable only what you need.
void settings() {
input.midi.enabled =
true;
input.osc.enabled =
true;
input.osc.receive_port = 8000;
input.hid.enabled =
true;
}
Core::GlobalInputConfig input
Core::GlobalInputConfig & get_global_input_config()
Gets the input configuration from the default engine.
Network: <tt>GlobalNetworkConfig</tt>
void settings() {
net.udp.enabled = true;
net.udp.default_receive_port = 8000;
net.udp.default_send_port = 9000;
net.tcp.enabled = true;
net.tcp.listen_port = 0;
}
Core::GlobalNetworkConfig & get_global_network_config()
Gets the network configuration from the default engine.
Journal (logging)
void settings() {
{ MayaFlux::Journal::Context::AudioProcessing }, false);
}
void set_journal_component_filter(const std::vector< Journal::Component > &component, bool enabled)
Enables or disables logging for specific journal components.
void store_journal_entries(const std::string &file_name)
Stores journal entries to a file by adding a FileSink to the Archivist.
void set_journal_severity(Journal::Severity severity)
Sets the minimum severity level for journal entries to be logged.
void sink_journal_to_console()
Outputs journal entries to the console by adding a ConsoleSink to the Archivist NOTE: This records th...
void set_journal_context_filter(const std::vector< Journal::Context > &context, bool enabled)
Enables or disables logging for specific journal contexts.
@ Vruta
Coroutines, schedulers, clocks, task management.
@ Buffers
Buffers, Managers, processors and processing chains.
Via JSON the same fields are in the "journal" key. "disable_components", "disable_contexts", "include_components", and "include_contexts" take string names matching the enum values (case-insensitive). Empty include lists allow all values; nonempty lists allow only their entries, subject to the disable lists.
Journal configuration is the only part of settings() that takes effect immediately rather than at Init().
Reading config at runtime
After Init(), config values are readable from anywhere:
void compose() {
}
uint32_t get_buffer_size()
Gets the buffer size from the default engine.
uint32_t get_sample_rate()
Gets the sample rate from the default engine.
uint32_t get_num_out_channels()
Gets the number of output channels from the default engine.
The full structs are also accessible via get_global_stream_info() etc., but writing to them after Init() logs a warning and will not take effect.
Common configurations
Low-latency performance:
void settings() {
gfx.surface_info.present_mode = Core::GraphicsSurfaceInfo::PresentMode::MAILBOX;
gfx.target_frame_rate = 120;
}
Audio input enabled:
Headless / offline (no window):
void settings() {
gfx.windowing_backend = Core::GlobalGraphicsConfig::WindowingBackend::NONE;
}
OSC + MIDI input:
void settings() {
input.osc.enabled =
true;
input.osc.receive_port = 9000;
input.midi.enabled =
true;
}
Load all settings from file, then override one value:
void settings() {
}
uint32_t buffer_size
Number of samples per processing block.