Configuration with CMake
-So far, the "building" side of things has been left under the carpet.
+So far, the "building" side of things has been left under the carpet.
It is actually not very complicated.
We have:
-
@@ -182,7 +182,7 @@
- A logging system -
- An 1D FFT +
- An 1D FFT
/* SPDX-License-Identifier: GPL-3.0-or-later */
#include <@AVND_MAIN_FILE@>
@@ -195,9 +195,9 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */
#include <@AVND_MAIN_FILE@>
@@ -260,7 +260,7 @@ CMake functio
)
Doing it by hand
-This is not very hard: Avendish is a header-only library, so you just have to add the avendish/include
folder to your include path,
+
This is not very hard: Avendish is a header-only library, so you just have to add the avendish/include
folder to your include path,
and the -std=c++20
flag to your build-system.
Depending on your compiler, you may also need to add flags such as -fconcepts
(GCC <= 9) ; -fcoroutines
(GCC <= 11) ; -fcoroutines-ts
(Clang <= 14).
@@ -273,8 +273,8 @@ Doing it by
Finally, we have to wrap our class with the binding.
// Defines struct MyProcessor { ... };
-#include "MyProcessor.hpp"
-#include "MyBinding.hpp"
+#include "MyProcessor.hpp"
+#include "MyBinding.hpp"
// Set up those typedefs to provide services to plug-ins which need it
struct my_config {
using logger_type = ...;
diff --git a/advanced/fft.html b/advanced/fft.html
index ed775358..f3882d40 100644
--- a/advanced/fft.html
+++ b/advanced/fft.html
@@ -203,24 +203,24 @@ FFT feature
template <halp::has_fft_1d<double> C>
struct PeakBand
{
- halp_meta(name, "Peak band")
- halp_meta(c_name, "avnd_peak_band")
- halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
+ halp_meta(name, "Peak band")
+ halp_meta(c_name, "avnd_peak_band")
+ halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
struct
{
- halp::audio_channel<"In", double> audio;
+ halp::audio_channel<"In", double> audio;
} inputs;
struct
{
- halp::val_port<"Peak", double> peak;
- halp::val_port<"Band", int> band;
+ halp::val_port<"Peak", double> peak;
+ halp::val_port<"Band", int> band;
} outputs;
// Instantiate the FFT provided by the configuration.
// Syntax is a bit ugly as we are already in a template
- // causing the need for the "::template " thing ; in C++23
+ // causing the need for the "::template " thing ; in C++23
// it should be possible to omit typename.
using fft_type = typename C::template fft_type<double>;
fft_type fft;
diff --git a/advanced/injection.html b/advanced/injection.html
index e2faac19..860eb49f 100644
--- a/advanced/injection.html
+++ b/advanced/injection.html
@@ -178,11 +178,11 @@ Feature i
Supported bindings: all
Many processors may require some kind of common, cross-cutting algorithm or system for their proper operation.
-Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
-For now, there are two:
+Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
+For now, there are two:
template<typename Conf>
// Get a compile error if the bindings cannot provide the thing.
diff --git a/advanced/logging.html b/advanced/logging.html
index 7fad2f9e..ee24fa64 100644
--- a/advanced/logging.html
+++ b/advanced/logging.html
@@ -177,7 +177,7 @@ Logging featu
Supported bindings: all
-The API is modeled after spdlog and expects the fmt syntax:
+The API is modeled after spdlog and expects the fmt syntax:
#pragma once
/* SPDX-License-Identifier: GPL-3.0-or-later */
@@ -197,17 +197,17 @@ Logging featu
template <typename C>
requires
// Here we pass template arguments as a primitive form of dependency injection.
- // Out effect is saying: "I want to be passed configured with a type
- // holding a "logger_type" typedef
+ // Out effect is saying: "I want to be passed configured with a type
+ // holding a "logger_type" typedef
// which will be something matching the logger concept.
halp::has_logger<C>
struct Logger
{
// halp_meta is simply a macro that expands to a consteval function.
// Hopefully C++ would use a similar syntax for reflexion.
- halp_meta(name, "Helpers")
- halp_meta(c_name, "avnd_helpers_logger")
- halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
+ halp_meta(name, "Helpers")
+ halp_meta(c_name, "avnd_helpers_logger")
+ halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
// We store our logger in the class to make things simpler.
// no_unique_address makes sure that it stays a zero-memory-cost abstraction
@@ -218,17 +218,17 @@ Logging featu
// Ideally metaclasses would make that obsolete.
void example(float x)
{
- logger.trace("example: {}", x);
- logger.info("example: {}", x);
- logger.debug("example: {}", x);
- logger.warn("example: {}", x);
- logger.error("example: {}", x);
- logger.critical("example: {}", x);
+ logger.trace("example: {}", x);
+ logger.info("example: {}", x);
+ logger.debug("example: {}", x);
+ logger.warn("example: {}", x);
+ logger.error("example: {}", x);
+ logger.critical("example: {}", x);
}
struct
{
- halp::func_ref<"member", &Logger<C>::example> my_message;
+ halp::func_ref<"member", &Logger<C>::example> my_message;
} messages;
};
}
diff --git a/advanced/port_types.codeedit.html b/advanced/port_types.codeedit.html
index d9681c2c..887b3ecd 100644
--- a/advanced/port_types.codeedit.html
+++ b/advanced/port_types.codeedit.html
@@ -177,15 +177,15 @@ Code editors
Supported bindings: ossia
-For live-coding and similar purposes, it is common to embed a domain-specific programming language
+
For live-coding and similar purposes, it is common to embed a domain-specific programming language
into a host environment: Faust, math expression languages, Javascript, Lisp, etc...
-If one adds the language
metadata to a string port, then the port will be recognized
-as a programming language code input: hosts are encouraged to show some relevant text editor for code
+
If one adds the language
metadata to a string port, then the port will be recognized
+as a programming language code input: hosts are encouraged to show some relevant text editor for code
instead of a simple line edit.
Example
-struct : halp::lineedit<"Program", "">
+struct : halp::lineedit<"Program", "">
{
- halp_meta(language, "INTERCAL")
+ halp_meta(language, "INTERCAL")
} program;
should show up as a code editor with support for INTERCAL programs.
diff --git a/advanced/port_types.example.html b/advanced/port_types.example.html
index 4cb5a1ce..1b270ace 100644
--- a/advanced/port_types.example.html
+++ b/advanced/port_types.example.html
@@ -197,54 +197,54 @@ Example
struct ControlGallery
{
- halp_meta(name, "Control gallery");
- halp_meta(c_name, "control_gallery");
- halp_meta(category, "Demo");
- halp_meta(author, "<AUTHOR>");
- halp_meta(description, "<DESCRIPTION>");
- halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
+ halp_meta(name, "Control gallery");
+ halp_meta(c_name, "control_gallery");
+ halp_meta(category, "Demo");
+ halp_meta(author, "<AUTHOR>");
+ halp_meta(description, "<DESCRIPTION>");
+ halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
struct
{
//! Buttons are level-triggers: true as long as the button is pressed
- halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
+ halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
//! In contrast, impulses are edge-triggers: there is only a value at the moment of the click.
- halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
+ halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
//! Common widgets
- halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
+ halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
float_slider;
- halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
+ halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
//// // FIXME
//// struct {
- //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
+ //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
//// ossia::timed_vec<float> values{};
//// } log_float_slider;
////
#if defined(__clang__) || defined(_MSC_VER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104720
- halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
+ halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
int_slider;
- halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
+ halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
int_spinbox;
#endif
//! Will look like a checkbox
- halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
+ halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
//! Same, but allows to choose what is displayed.
- // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
+ // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
//! Allows to edit some text.
- halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
+ halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
//! First member of the pair is the text, second is the value.
//! Defining comboboxes and enumerations is a tiny bit more complicated
struct : halp::sample_accurate_values<halp::combo_pair<float>>
{
- halp_meta(name, "Combo box");
+ halp_meta(name, "Combo box");
enum widget
{
combobox
@@ -252,7 +252,7 @@ Example
struct range
{
- halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // Bar
};
@@ -262,7 +262,7 @@ Example
//! Here value will be the string
struct : halp::sample_accurate_values<std::string_view>
{
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget
{
enumeration
@@ -270,7 +270,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -282,7 +282,7 @@ Example
//! is below:
struct : halp::sample_accurate_values<int>
{
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget
{
enumeration
@@ -290,7 +290,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
+ std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
int init{1}; // Red
};
@@ -301,9 +301,9 @@ Example
/// //! Same as Enum but won't reject strings that are not part of the list.
/// struct {
/// static const constexpr std::array<const char*, 3> choices() {
- /// return {"Square", "Sine", "Triangle"};
+ /// return {"Square", "Sine", "Triangle"};
/// };
- /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
+ /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
/// ossia::timed_vec<std::string> values{};
/// } unvalidated_enumeration;
@@ -321,21 +321,21 @@ Example
//! OSC messages can use either the int index or the string.
struct enum_t
{
- halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
+ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
};
halp::accurate<enum_t> simpler_enumeration;
struct combobox_t
{
- halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
+ halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
};
halp::accurate<combobox_t> simpler_enumeration_in_a_combobox;
//! Crosshair XY chooser
- halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
+ halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
//! Color chooser. Colors are in 8-bit RGBA by default.
- halp::accurate<halp::color_chooser<"Color">> color;
+ halp::accurate<halp::color_chooser<"Color">> color;
} inputs;
@@ -354,12 +354,12 @@ Example
auto val = input.values.begin()->second;
if constexpr(std::is_enum_v<decltype(val)>) {
#if __has_include(<magic_enum.hpp>)
- fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
+ fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
#else
- fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
+ fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
#endif
} else {
- fmt::print("changed: {} {}", Control::name(), val);
+ fmt::print("changed: {} {}", Control::name(), val);
}
}
});
diff --git a/advanced/port_types.file.html b/advanced/port_types.file.html
index 77e6cc62..faf7d85f 100644
--- a/advanced/port_types.file.html
+++ b/advanced/port_types.file.html
@@ -180,7 +180,7 @@ File ports
File ports are currently only supported with the ossia binding.
They allow to specify that we want the content of a file.
The host will take care of loading, mmaping, converting, etc... the file in the relevant format - as far as possible outside of DSP / processing threads.
-Every file port should at least conform to the very basic following concept:
+Every file port should at least conform to the very basic following concept:
template <typename T>
concept file = requires(T t) {
t.filename;
@@ -204,21 +204,21 @@ File watch
Note that this has an obvious performance cost as the host must check regularly for changes: do not overdo it!
File filters
File ports should prompt the host to open a file chooser.
-One is generally only interested in a specific file type.
-This can be specified in the following ways:
+One is generally only interested in a specific file type.
+This can be specified in the following ways:
General file filters
Here, the filter is a string of either of the following formats:
-"*.jpg *.jpeg"
-"JPEG Images (*.jpg *.jpeg)"
+"*.jpg *.jpeg"
+"JPEG Images (*.jpg *.jpeg)"
struct my_file_port : ... {
// Currently implemented:
// Any audio file that can be loaded by the host
- static consteval auto filters() { return "CSV files (*.csv)"; }
+ static consteval auto filters() { return "CSV files (*.csv)"; }
};
Domain-specific file filters
-This is for the case where you want a general kind of media and don't care specifically about the extension:
+
This is for the case where you want a general kind of media and don't care specifically about the extension:
for instance, for audio files you could have .wav, .aiff, .mp3, etc etc ; it is pointless to try to specify a whole list.
Instead, the host knows which audio file formats it is able to load and should just be able to show its own audio-specific file chooser.
struct my_file_port : ... {
diff --git a/advanced/port_types.file.midi.html b/advanced/port_types.file.midi.html
index 95b08679..e253eb4a 100644
--- a/advanced/port_types.file.midi.html
+++ b/advanced/port_types.file.midi.html
@@ -200,7 +200,7 @@ Port definiti
struct
{
- static consteval auto name() { return "My midifile"}
+ static consteval auto name() { return "My midifile"}
struct {
// Can be any vector-ish container, but must support push_back
std::vector<std::vector<midi_event>> tracks;
@@ -233,13 +233,13 @@ Port definiti
struct {
// Default event type is simple_midi_track_event for performance and compile times,
// but it can be changed through the template arguments
- halp::midifile_port<"My midifile", midi_track_event> snd;
+ halp::midifile_port<"My midifile", midi_track_event> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::midifile_port
-struct : halp::midifile_port<"My midifile"> {
+struct : halp::midifile_port<"My midifile"> {
void update(MyObject& obj) {
// This code is called whenever the midifile has been changed by the user
}
diff --git a/advanced/port_types.file.raw.html b/advanced/port_types.file.raw.html
index f90aa0cf..5e636dca 100644
--- a/advanced/port_types.file.raw.html
+++ b/advanced/port_types.file.raw.html
@@ -184,7 +184,7 @@ Port definiti
A file input port can be defined like this:
struct
{
- static consteval auto name() { return "My file"}
+ static consteval auto name() { return "My file"}
struct {
// The file data.
// Only requirement for the type is that it can be assigned {data, size}.
@@ -206,14 +206,14 @@ Port definiti
A helper type is provided:
struct {
- halp::file_port<"My file"> snd;
+ halp::file_port<"My file"> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::file_port
// text_file_view (the default) has the text flag, and mmap_file_view has the mmap flag.
-struct : halp::file_port<"My file", mmap_file_view> {
+struct : halp::file_port<"My file", mmap_file_view> {
void update(MyObject& obj) {
// This code is called whenever the file has been changed by the user
}
diff --git a/advanced/port_types.file.sound.html b/advanced/port_types.file.sound.html
index f72925ba..ae033e5c 100644
--- a/advanced/port_types.file.sound.html
+++ b/advanced/port_types.file.sound.html
@@ -183,7 +183,7 @@ Port definiti
A soundfile input port looks like this:
struct
{
- static consteval auto name() { return "My soundfile"}
+ static consteval auto name() { return "My soundfile"}
struct {
const float** data{}; // The audio channels
int64_t frames{}; // How many samples are there in a channel
@@ -194,7 +194,7 @@ Port definiti
A helper type is provided:
struct {
- halp::soundfile_port<"My soundfile"> snd;
+ halp::soundfile_port<"My soundfile"> snd;
} inputs;
void operator()(int frames) {
@@ -214,13 +214,13 @@ Port definiti
}
It allows choosing the sample format in which the samples are loaded:
-halp::soundfile_port<"My soundfile", float> snd_float;
-halp::soundfile_port<"My soundfile", double> snd_double;
+halp::soundfile_port<"My soundfile", float> snd_float;
+halp::soundfile_port<"My soundfile", double> snd_double;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::soundfile
-struct : halp::soundfile_port<"My soundfile"> {
+struct : halp::soundfile_port<"My soundfile"> {
void update(MyObject& obj) {
// This code is called whenever the soundfile has been changed by the user
}
diff --git a/advanced/port_types.html b/advanced/port_types.html
index f5d3e252..56b00d5d 100644
--- a/advanced/port_types.html
+++ b/advanced/port_types.html
@@ -231,11 +231,11 @@ template<typename T>
using my_pair = std::pair<std::string_view, T>;
struct {
- halp_meta(name, "Enum 1");
+ halp_meta(name, "Enum 1");
enum widget { combobox };
struct range {
- my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // == Bar
};
@@ -257,11 +257,11 @@ Enumerating with only string
Consider the following port:
struct {
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -273,11 +273,11 @@ struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -289,12 +289,12 @@ enum my_enum { A, B, C };
struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range
{
- std::string_view values[3]{"A", "B", "C"};
+ std::string_view values[3]{"A", "B", "C"};
my_enum init = my_enum::B;
};
@@ -309,9 +309,9 @@ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
+halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
-declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
+declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
Containers
Supported bindings: ossia
@@ -347,7 +347,7 @@ std::map
} my_port;
C arrays
-C arrays aren't supported due to limitations in the reflection capabilities of C++:
+C arrays aren't supported due to limitations in the reflection capabilities of C++:
struct {
int value[2]; // Won't work
} my_port;
@@ -376,7 +376,7 @@ Optionals
std::optional<int> value;
} my_port;
-This is used to give message semantics to the port: optionals are reset before execution of the current
+
This is used to give message semantics to the port: optionals are reset before execution of the current
tick, both for inputs and outputs. If an input is set, it means that a message was received for this tick.
If the processor sets the output, a message will be sent outwards.
This is mostly equivalent to messages and callbacks, but with a value-based instead of function-based API
@@ -404,7 +404,7 @@
struct Foo {
int a, b;
struct {
@@ -422,10 +422,10 @@
It is possible to specify field names in an aggregate manually, in order to have the sub-object be detected as a map and not a list:
@@ -440,19 +440,19 @@
This maps to:
(map) {
- name: "foo"
+ name: "foo"
, geometry: (list) [3, 4, 120, 356]
, probability: 0.95
}
Helper type
-To create a port ithout having to declare a struct, you can directly use:
-halp::val_port<"My port", std::string> my_port;
.
+To create a port ithout having to declare a struct, you can directly use:
+halp::val_port<"My port", std::string> my_port;
.
CMake functio
)
Doing it by hand
-This is not very hard: Avendish is a header-only library, so you just have to add the avendish/include
folder to your include path,
+
This is not very hard: Avendish is a header-only library, so you just have to add the avendish/include
folder to your include path,
and the -std=c++20
flag to your build-system.
Depending on your compiler, you may also need to add flags such as -fconcepts
(GCC <= 9) ; -fcoroutines
(GCC <= 11) ; -fcoroutines-ts
(Clang <= 14).
@@ -273,8 +273,8 @@ Doing it by
Finally, we have to wrap our class with the binding.
// Defines struct MyProcessor { ... };
-#include "MyProcessor.hpp"
-#include "MyBinding.hpp"
+#include "MyProcessor.hpp"
+#include "MyBinding.hpp"
// Set up those typedefs to provide services to plug-ins which need it
struct my_config {
using logger_type = ...;
diff --git a/advanced/fft.html b/advanced/fft.html
index ed775358..f3882d40 100644
--- a/advanced/fft.html
+++ b/advanced/fft.html
@@ -203,24 +203,24 @@ FFT feature
template <halp::has_fft_1d<double> C>
struct PeakBand
{
- halp_meta(name, "Peak band")
- halp_meta(c_name, "avnd_peak_band")
- halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
+ halp_meta(name, "Peak band")
+ halp_meta(c_name, "avnd_peak_band")
+ halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
struct
{
- halp::audio_channel<"In", double> audio;
+ halp::audio_channel<"In", double> audio;
} inputs;
struct
{
- halp::val_port<"Peak", double> peak;
- halp::val_port<"Band", int> band;
+ halp::val_port<"Peak", double> peak;
+ halp::val_port<"Band", int> band;
} outputs;
// Instantiate the FFT provided by the configuration.
// Syntax is a bit ugly as we are already in a template
- // causing the need for the "::template " thing ; in C++23
+ // causing the need for the "::template " thing ; in C++23
// it should be possible to omit typename.
using fft_type = typename C::template fft_type<double>;
fft_type fft;
diff --git a/advanced/injection.html b/advanced/injection.html
index e2faac19..860eb49f 100644
--- a/advanced/injection.html
+++ b/advanced/injection.html
@@ -178,11 +178,11 @@ Feature i
Supported bindings: all
Many processors may require some kind of common, cross-cutting algorithm or system for their proper operation.
-Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
-For now, there are two:
+Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
+For now, there are two:
template<typename Conf>
// Get a compile error if the bindings cannot provide the thing.
diff --git a/advanced/logging.html b/advanced/logging.html
index 7fad2f9e..ee24fa64 100644
--- a/advanced/logging.html
+++ b/advanced/logging.html
@@ -177,7 +177,7 @@ Logging featu
Supported bindings: all
-The API is modeled after spdlog and expects the fmt syntax:
+The API is modeled after spdlog and expects the fmt syntax:
#pragma once
/* SPDX-License-Identifier: GPL-3.0-or-later */
@@ -197,17 +197,17 @@ Logging featu
template <typename C>
requires
// Here we pass template arguments as a primitive form of dependency injection.
- // Out effect is saying: "I want to be passed configured with a type
- // holding a "logger_type" typedef
+ // Out effect is saying: "I want to be passed configured with a type
+ // holding a "logger_type" typedef
// which will be something matching the logger concept.
halp::has_logger<C>
struct Logger
{
// halp_meta is simply a macro that expands to a consteval function.
// Hopefully C++ would use a similar syntax for reflexion.
- halp_meta(name, "Helpers")
- halp_meta(c_name, "avnd_helpers_logger")
- halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
+ halp_meta(name, "Helpers")
+ halp_meta(c_name, "avnd_helpers_logger")
+ halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
// We store our logger in the class to make things simpler.
// no_unique_address makes sure that it stays a zero-memory-cost abstraction
@@ -218,17 +218,17 @@ Logging featu
// Ideally metaclasses would make that obsolete.
void example(float x)
{
- logger.trace("example: {}", x);
- logger.info("example: {}", x);
- logger.debug("example: {}", x);
- logger.warn("example: {}", x);
- logger.error("example: {}", x);
- logger.critical("example: {}", x);
+ logger.trace("example: {}", x);
+ logger.info("example: {}", x);
+ logger.debug("example: {}", x);
+ logger.warn("example: {}", x);
+ logger.error("example: {}", x);
+ logger.critical("example: {}", x);
}
struct
{
- halp::func_ref<"member", &Logger<C>::example> my_message;
+ halp::func_ref<"member", &Logger<C>::example> my_message;
} messages;
};
}
diff --git a/advanced/port_types.codeedit.html b/advanced/port_types.codeedit.html
index d9681c2c..887b3ecd 100644
--- a/advanced/port_types.codeedit.html
+++ b/advanced/port_types.codeedit.html
@@ -177,15 +177,15 @@ Code editors
Supported bindings: ossia
-For live-coding and similar purposes, it is common to embed a domain-specific programming language
+
For live-coding and similar purposes, it is common to embed a domain-specific programming language
into a host environment: Faust, math expression languages, Javascript, Lisp, etc...
-If one adds the language
metadata to a string port, then the port will be recognized
-as a programming language code input: hosts are encouraged to show some relevant text editor for code
+
If one adds the language
metadata to a string port, then the port will be recognized
+as a programming language code input: hosts are encouraged to show some relevant text editor for code
instead of a simple line edit.
Example
-struct : halp::lineedit<"Program", "">
+struct : halp::lineedit<"Program", "">
{
- halp_meta(language, "INTERCAL")
+ halp_meta(language, "INTERCAL")
} program;
should show up as a code editor with support for INTERCAL programs.
diff --git a/advanced/port_types.example.html b/advanced/port_types.example.html
index 4cb5a1ce..1b270ace 100644
--- a/advanced/port_types.example.html
+++ b/advanced/port_types.example.html
@@ -197,54 +197,54 @@ Example
struct ControlGallery
{
- halp_meta(name, "Control gallery");
- halp_meta(c_name, "control_gallery");
- halp_meta(category, "Demo");
- halp_meta(author, "<AUTHOR>");
- halp_meta(description, "<DESCRIPTION>");
- halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
+ halp_meta(name, "Control gallery");
+ halp_meta(c_name, "control_gallery");
+ halp_meta(category, "Demo");
+ halp_meta(author, "<AUTHOR>");
+ halp_meta(description, "<DESCRIPTION>");
+ halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
struct
{
//! Buttons are level-triggers: true as long as the button is pressed
- halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
+ halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
//! In contrast, impulses are edge-triggers: there is only a value at the moment of the click.
- halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
+ halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
//! Common widgets
- halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
+ halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
float_slider;
- halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
+ halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
//// // FIXME
//// struct {
- //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
+ //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
//// ossia::timed_vec<float> values{};
//// } log_float_slider;
////
#if defined(__clang__) || defined(_MSC_VER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104720
- halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
+ halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
int_slider;
- halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
+ halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
int_spinbox;
#endif
//! Will look like a checkbox
- halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
+ halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
//! Same, but allows to choose what is displayed.
- // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
+ // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
//! Allows to edit some text.
- halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
+ halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
//! First member of the pair is the text, second is the value.
//! Defining comboboxes and enumerations is a tiny bit more complicated
struct : halp::sample_accurate_values<halp::combo_pair<float>>
{
- halp_meta(name, "Combo box");
+ halp_meta(name, "Combo box");
enum widget
{
combobox
@@ -252,7 +252,7 @@ Example
struct range
{
- halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // Bar
};
@@ -262,7 +262,7 @@ Example
//! Here value will be the string
struct : halp::sample_accurate_values<std::string_view>
{
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget
{
enumeration
@@ -270,7 +270,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -282,7 +282,7 @@ Example
//! is below:
struct : halp::sample_accurate_values<int>
{
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget
{
enumeration
@@ -290,7 +290,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
+ std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
int init{1}; // Red
};
@@ -301,9 +301,9 @@ Example
/// //! Same as Enum but won't reject strings that are not part of the list.
/// struct {
/// static const constexpr std::array<const char*, 3> choices() {
- /// return {"Square", "Sine", "Triangle"};
+ /// return {"Square", "Sine", "Triangle"};
/// };
- /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
+ /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
/// ossia::timed_vec<std::string> values{};
/// } unvalidated_enumeration;
@@ -321,21 +321,21 @@ Example
//! OSC messages can use either the int index or the string.
struct enum_t
{
- halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
+ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
};
halp::accurate<enum_t> simpler_enumeration;
struct combobox_t
{
- halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
+ halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
};
halp::accurate<combobox_t> simpler_enumeration_in_a_combobox;
//! Crosshair XY chooser
- halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
+ halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
//! Color chooser. Colors are in 8-bit RGBA by default.
- halp::accurate<halp::color_chooser<"Color">> color;
+ halp::accurate<halp::color_chooser<"Color">> color;
} inputs;
@@ -354,12 +354,12 @@ Example
auto val = input.values.begin()->second;
if constexpr(std::is_enum_v<decltype(val)>) {
#if __has_include(<magic_enum.hpp>)
- fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
+ fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
#else
- fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
+ fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
#endif
} else {
- fmt::print("changed: {} {}", Control::name(), val);
+ fmt::print("changed: {} {}", Control::name(), val);
}
}
});
diff --git a/advanced/port_types.file.html b/advanced/port_types.file.html
index 77e6cc62..faf7d85f 100644
--- a/advanced/port_types.file.html
+++ b/advanced/port_types.file.html
@@ -180,7 +180,7 @@ File ports
File ports are currently only supported with the ossia binding.
They allow to specify that we want the content of a file.
The host will take care of loading, mmaping, converting, etc... the file in the relevant format - as far as possible outside of DSP / processing threads.
-Every file port should at least conform to the very basic following concept:
+Every file port should at least conform to the very basic following concept:
template <typename T>
concept file = requires(T t) {
t.filename;
@@ -204,21 +204,21 @@ File watch
Note that this has an obvious performance cost as the host must check regularly for changes: do not overdo it!
File filters
File ports should prompt the host to open a file chooser.
-One is generally only interested in a specific file type.
-This can be specified in the following ways:
+One is generally only interested in a specific file type.
+This can be specified in the following ways:
General file filters
Here, the filter is a string of either of the following formats:
-"*.jpg *.jpeg"
-"JPEG Images (*.jpg *.jpeg)"
+"*.jpg *.jpeg"
+"JPEG Images (*.jpg *.jpeg)"
struct my_file_port : ... {
// Currently implemented:
// Any audio file that can be loaded by the host
- static consteval auto filters() { return "CSV files (*.csv)"; }
+ static consteval auto filters() { return "CSV files (*.csv)"; }
};
Domain-specific file filters
-This is for the case where you want a general kind of media and don't care specifically about the extension:
+
This is for the case where you want a general kind of media and don't care specifically about the extension:
for instance, for audio files you could have .wav, .aiff, .mp3, etc etc ; it is pointless to try to specify a whole list.
Instead, the host knows which audio file formats it is able to load and should just be able to show its own audio-specific file chooser.
struct my_file_port : ... {
diff --git a/advanced/port_types.file.midi.html b/advanced/port_types.file.midi.html
index 95b08679..e253eb4a 100644
--- a/advanced/port_types.file.midi.html
+++ b/advanced/port_types.file.midi.html
@@ -200,7 +200,7 @@ Port definiti
struct
{
- static consteval auto name() { return "My midifile"}
+ static consteval auto name() { return "My midifile"}
struct {
// Can be any vector-ish container, but must support push_back
std::vector<std::vector<midi_event>> tracks;
@@ -233,13 +233,13 @@ Port definiti
struct {
// Default event type is simple_midi_track_event for performance and compile times,
// but it can be changed through the template arguments
- halp::midifile_port<"My midifile", midi_track_event> snd;
+ halp::midifile_port<"My midifile", midi_track_event> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::midifile_port
-struct : halp::midifile_port<"My midifile"> {
+struct : halp::midifile_port<"My midifile"> {
void update(MyObject& obj) {
// This code is called whenever the midifile has been changed by the user
}
diff --git a/advanced/port_types.file.raw.html b/advanced/port_types.file.raw.html
index f90aa0cf..5e636dca 100644
--- a/advanced/port_types.file.raw.html
+++ b/advanced/port_types.file.raw.html
@@ -184,7 +184,7 @@ Port definiti
A file input port can be defined like this:
struct
{
- static consteval auto name() { return "My file"}
+ static consteval auto name() { return "My file"}
struct {
// The file data.
// Only requirement for the type is that it can be assigned {data, size}.
@@ -206,14 +206,14 @@ Port definiti
A helper type is provided:
struct {
- halp::file_port<"My file"> snd;
+ halp::file_port<"My file"> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::file_port
// text_file_view (the default) has the text flag, and mmap_file_view has the mmap flag.
-struct : halp::file_port<"My file", mmap_file_view> {
+struct : halp::file_port<"My file", mmap_file_view> {
void update(MyObject& obj) {
// This code is called whenever the file has been changed by the user
}
diff --git a/advanced/port_types.file.sound.html b/advanced/port_types.file.sound.html
index f72925ba..ae033e5c 100644
--- a/advanced/port_types.file.sound.html
+++ b/advanced/port_types.file.sound.html
@@ -183,7 +183,7 @@ Port definiti
A soundfile input port looks like this:
struct
{
- static consteval auto name() { return "My soundfile"}
+ static consteval auto name() { return "My soundfile"}
struct {
const float** data{}; // The audio channels
int64_t frames{}; // How many samples are there in a channel
@@ -194,7 +194,7 @@ Port definiti
A helper type is provided:
struct {
- halp::soundfile_port<"My soundfile"> snd;
+ halp::soundfile_port<"My soundfile"> snd;
} inputs;
void operator()(int frames) {
@@ -214,13 +214,13 @@ Port definiti
}
It allows choosing the sample format in which the samples are loaded:
-halp::soundfile_port<"My soundfile", float> snd_float;
-halp::soundfile_port<"My soundfile", double> snd_double;
+halp::soundfile_port<"My soundfile", float> snd_float;
+halp::soundfile_port<"My soundfile", double> snd_double;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::soundfile
-struct : halp::soundfile_port<"My soundfile"> {
+struct : halp::soundfile_port<"My soundfile"> {
void update(MyObject& obj) {
// This code is called whenever the soundfile has been changed by the user
}
diff --git a/advanced/port_types.html b/advanced/port_types.html
index f5d3e252..56b00d5d 100644
--- a/advanced/port_types.html
+++ b/advanced/port_types.html
@@ -231,11 +231,11 @@ template<typename T>
using my_pair = std::pair<std::string_view, T>;
struct {
- halp_meta(name, "Enum 1");
+ halp_meta(name, "Enum 1");
enum widget { combobox };
struct range {
- my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // == Bar
};
@@ -257,11 +257,11 @@ Enumerating with only string
Consider the following port:
struct {
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -273,11 +273,11 @@ struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -289,12 +289,12 @@ enum my_enum { A, B, C };
struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range
{
- std::string_view values[3]{"A", "B", "C"};
+ std::string_view values[3]{"A", "B", "C"};
my_enum init = my_enum::B;
};
@@ -309,9 +309,9 @@ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
+halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
-declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
+declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
Containers
Supported bindings: ossia
@@ -347,7 +347,7 @@ std::map
} my_port;
C arrays
-C arrays aren't supported due to limitations in the reflection capabilities of C++:
+C arrays aren't supported due to limitations in the reflection capabilities of C++:
struct {
int value[2]; // Won't work
} my_port;
@@ -376,7 +376,7 @@ Optionals
std::optional<int> value;
} my_port;
-This is used to give message semantics to the port: optionals are reset before execution of the current
+
This is used to give message semantics to the port: optionals are reset before execution of the current
tick, both for inputs and outputs. If an input is set, it means that a message was received for this tick.
If the processor sets the output, a message will be sent outwards.
This is mostly equivalent to messages and callbacks, but with a value-based instead of function-based API
@@ -404,7 +404,7 @@
struct Foo {
int a, b;
struct {
@@ -422,10 +422,10 @@
It is possible to specify field names in an aggregate manually, in order to have the sub-object be detected as a map and not a list:
@@ -440,19 +440,19 @@
This maps to:
(map) {
- name: "foo"
+ name: "foo"
, geometry: (list) [3, 4, 120, 356]
, probability: 0.95
}
Helper type
-To create a port ithout having to declare a struct, you can directly use:
-halp::val_port<"My port", std::string> my_port;
.
+To create a port ithout having to declare a struct, you can directly use:
+halp::val_port<"My port", std::string> my_port;
.
avendish/include
folder to your include path,
+avendish/include
folder to your include path,
and the -std=c++20
flag to your build-system.Depending on your compiler, you may also need to add flags such as -fconcepts
(GCC <= 9) ; -fcoroutines
(GCC <= 11) ; -fcoroutines-ts
(Clang <= 14).
Doing it by
// Defines struct MyProcessor { ... };
-#include "MyProcessor.hpp"
-#include "MyBinding.hpp"
+#include "MyProcessor.hpp"
+#include "MyBinding.hpp"
// Set up those typedefs to provide services to plug-ins which need it
struct my_config {
using logger_type = ...;
diff --git a/advanced/fft.html b/advanced/fft.html
index ed775358..f3882d40 100644
--- a/advanced/fft.html
+++ b/advanced/fft.html
@@ -203,24 +203,24 @@ FFT feature
template <halp::has_fft_1d<double> C>
struct PeakBand
{
- halp_meta(name, "Peak band")
- halp_meta(c_name, "avnd_peak_band")
- halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
+ halp_meta(name, "Peak band")
+ halp_meta(c_name, "avnd_peak_band")
+ halp_meta(uuid, "5610b62e-ef1f-4a34-abe0-e57816bc44c2")
struct
{
- halp::audio_channel<"In", double> audio;
+ halp::audio_channel<"In", double> audio;
} inputs;
struct
{
- halp::val_port<"Peak", double> peak;
- halp::val_port<"Band", int> band;
+ halp::val_port<"Peak", double> peak;
+ halp::val_port<"Band", int> band;
} outputs;
// Instantiate the FFT provided by the configuration.
// Syntax is a bit ugly as we are already in a template
- // causing the need for the "::template " thing ; in C++23
+ // causing the need for the "::template " thing ; in C++23
// it should be possible to omit typename.
using fft_type = typename C::template fft_type<double>;
fft_type fft;
diff --git a/advanced/injection.html b/advanced/injection.html
index e2faac19..860eb49f 100644
--- a/advanced/injection.html
+++ b/advanced/injection.html
@@ -178,11 +178,11 @@ Feature i
Supported bindings: all
Many processors may require some kind of common, cross-cutting algorithm or system for their proper operation.
-Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
-For now, there are two:
+Processors can optionally declare a template argument, which will contain the implementations of these "cross-cutting concerns" supported by the backend.
+For now, there are two:
template<typename Conf>
// Get a compile error if the bindings cannot provide the thing.
diff --git a/advanced/logging.html b/advanced/logging.html
index 7fad2f9e..ee24fa64 100644
--- a/advanced/logging.html
+++ b/advanced/logging.html
@@ -177,7 +177,7 @@ Logging featu
Supported bindings: all
-The API is modeled after spdlog and expects the fmt syntax:
+The API is modeled after spdlog and expects the fmt syntax:
#pragma once
/* SPDX-License-Identifier: GPL-3.0-or-later */
@@ -197,17 +197,17 @@ Logging featu
template <typename C>
requires
// Here we pass template arguments as a primitive form of dependency injection.
- // Out effect is saying: "I want to be passed configured with a type
- // holding a "logger_type" typedef
+ // Out effect is saying: "I want to be passed configured with a type
+ // holding a "logger_type" typedef
// which will be something matching the logger concept.
halp::has_logger<C>
struct Logger
{
// halp_meta is simply a macro that expands to a consteval function.
// Hopefully C++ would use a similar syntax for reflexion.
- halp_meta(name, "Helpers")
- halp_meta(c_name, "avnd_helpers_logger")
- halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
+ halp_meta(name, "Helpers")
+ halp_meta(c_name, "avnd_helpers_logger")
+ halp_meta(uuid, "3a646521-48f4-429b-a2b1-d67beb0d65cf")
// We store our logger in the class to make things simpler.
// no_unique_address makes sure that it stays a zero-memory-cost abstraction
@@ -218,17 +218,17 @@ Logging featu
// Ideally metaclasses would make that obsolete.
void example(float x)
{
- logger.trace("example: {}", x);
- logger.info("example: {}", x);
- logger.debug("example: {}", x);
- logger.warn("example: {}", x);
- logger.error("example: {}", x);
- logger.critical("example: {}", x);
+ logger.trace("example: {}", x);
+ logger.info("example: {}", x);
+ logger.debug("example: {}", x);
+ logger.warn("example: {}", x);
+ logger.error("example: {}", x);
+ logger.critical("example: {}", x);
}
struct
{
- halp::func_ref<"member", &Logger<C>::example> my_message;
+ halp::func_ref<"member", &Logger<C>::example> my_message;
} messages;
};
}
diff --git a/advanced/port_types.codeedit.html b/advanced/port_types.codeedit.html
index d9681c2c..887b3ecd 100644
--- a/advanced/port_types.codeedit.html
+++ b/advanced/port_types.codeedit.html
@@ -177,15 +177,15 @@ Code editors
Supported bindings: ossia
-For live-coding and similar purposes, it is common to embed a domain-specific programming language
+
For live-coding and similar purposes, it is common to embed a domain-specific programming language
into a host environment: Faust, math expression languages, Javascript, Lisp, etc...
-If one adds the language
metadata to a string port, then the port will be recognized
-as a programming language code input: hosts are encouraged to show some relevant text editor for code
+
If one adds the language
metadata to a string port, then the port will be recognized
+as a programming language code input: hosts are encouraged to show some relevant text editor for code
instead of a simple line edit.
Example
-struct : halp::lineedit<"Program", "">
+struct : halp::lineedit<"Program", "">
{
- halp_meta(language, "INTERCAL")
+ halp_meta(language, "INTERCAL")
} program;
should show up as a code editor with support for INTERCAL programs.
diff --git a/advanced/port_types.example.html b/advanced/port_types.example.html
index 4cb5a1ce..1b270ace 100644
--- a/advanced/port_types.example.html
+++ b/advanced/port_types.example.html
@@ -197,54 +197,54 @@ Example
struct ControlGallery
{
- halp_meta(name, "Control gallery");
- halp_meta(c_name, "control_gallery");
- halp_meta(category, "Demo");
- halp_meta(author, "<AUTHOR>");
- halp_meta(description, "<DESCRIPTION>");
- halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
+ halp_meta(name, "Control gallery");
+ halp_meta(c_name, "control_gallery");
+ halp_meta(category, "Demo");
+ halp_meta(author, "<AUTHOR>");
+ halp_meta(description, "<DESCRIPTION>");
+ halp_meta(uuid, "a9b0e2c6-61e9-45df-a75d-27abf7fb43d7");
struct
{
//! Buttons are level-triggers: true as long as the button is pressed
- halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
+ halp::accurate<halp::maintained_button<"Press me ! (Button)">> button;
//! In contrast, impulses are edge-triggers: there is only a value at the moment of the click.
- halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
+ halp::accurate<halp::impulse_button<"Press me ! (Impulse)">> impulse_button;
//! Common widgets
- halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
+ halp::accurate<halp::hslider_f32<"Float slider", halp::range{0., 1., 0.5}>>
float_slider;
- halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
+ halp::accurate<halp::knob_f32<"Float knob", halp::range{0., 1., 0.5}>> float_knob;
//// // FIXME
//// struct {
- //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
+ //// // FIXME meta_control(Control::LogFloatSlider, "Float slider (log)", 0., 1., 0.5);
//// ossia::timed_vec<float> values{};
//// } log_float_slider;
////
#if defined(__clang__) || defined(_MSC_VER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104720
- halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
+ halp::accurate<halp::hslider_i32<"Int slider", halp::range{0., 1000., 10.}>>
int_slider;
- halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
+ halp::accurate<halp::spinbox_i32<"Int spinbox", halp::range{0, 1000, 10}>>
int_spinbox;
#endif
//! Will look like a checkbox
- halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
+ halp::accurate<halp::toggle<"Toggle", halp::toggle_setup{.init = true}>> toggle;
//! Same, but allows to choose what is displayed.
- // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
+ // FIXME halp::accurate<halp::chooser_toggle<"Toggle", {"Falsey", "Truey"}, false>> chooser_toggle;
//! Allows to edit some text.
- halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
+ halp::accurate<halp::lineedit<"Line edit", "Henlo">> lineedit;
//! First member of the pair is the text, second is the value.
//! Defining comboboxes and enumerations is a tiny bit more complicated
struct : halp::sample_accurate_values<halp::combo_pair<float>>
{
- halp_meta(name, "Combo box");
+ halp_meta(name, "Combo box");
enum widget
{
combobox
@@ -252,7 +252,7 @@ Example
struct range
{
- halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ halp::combo_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // Bar
};
@@ -262,7 +262,7 @@ Example
//! Here value will be the string
struct : halp::sample_accurate_values<std::string_view>
{
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget
{
enumeration
@@ -270,7 +270,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -282,7 +282,7 @@ Example
//! is below:
struct : halp::sample_accurate_values<int>
{
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget
{
enumeration
@@ -290,7 +290,7 @@ Example
struct range
{
- std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
+ std::string_view values[4]{"Roses 2", "Red 2", "Violets 2", "Blue 2"};
int init{1}; // Red
};
@@ -301,9 +301,9 @@ Example
/// //! Same as Enum but won't reject strings that are not part of the list.
/// struct {
/// static const constexpr std::array<const char*, 3> choices() {
- /// return {"Square", "Sine", "Triangle"};
+ /// return {"Square", "Sine", "Triangle"};
/// };
- /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
+ /// // FIXME meta_control(Control::UnvalidatedEnum, "Unchecked enum", 1, choices());
/// ossia::timed_vec<std::string> values{};
/// } unvalidated_enumeration;
@@ -321,21 +321,21 @@ Example
//! OSC messages can use either the int index or the string.
struct enum_t
{
- halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
+ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole)
};
halp::accurate<enum_t> simpler_enumeration;
struct combobox_t
{
- halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
+ halp__enum_combobox("Color", Blue, Red, Green, Teal, Blue, Black, Orange)
};
halp::accurate<combobox_t> simpler_enumeration_in_a_combobox;
//! Crosshair XY chooser
- halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
+ halp::accurate<halp::xy_pad_f32<"XY", halp::range{-5.f, 5.f, 0.f}>> position;
//! Color chooser. Colors are in 8-bit RGBA by default.
- halp::accurate<halp::color_chooser<"Color">> color;
+ halp::accurate<halp::color_chooser<"Color">> color;
} inputs;
@@ -354,12 +354,12 @@ Example
auto val = input.values.begin()->second;
if constexpr(std::is_enum_v<decltype(val)>) {
#if __has_include(<magic_enum.hpp>)
- fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
+ fmt::print("changed: {} {}", Control::name(), magic_enum::enum_name(val));
#else
- fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
+ fmt::print("changed: {} {}", Control::name(), static_cast<std::underlying_type_t<decltype(val)>>(val));
#endif
} else {
- fmt::print("changed: {} {}", Control::name(), val);
+ fmt::print("changed: {} {}", Control::name(), val);
}
}
});
diff --git a/advanced/port_types.file.html b/advanced/port_types.file.html
index 77e6cc62..faf7d85f 100644
--- a/advanced/port_types.file.html
+++ b/advanced/port_types.file.html
@@ -180,7 +180,7 @@ File ports
File ports are currently only supported with the ossia binding.
They allow to specify that we want the content of a file.
The host will take care of loading, mmaping, converting, etc... the file in the relevant format - as far as possible outside of DSP / processing threads.
-Every file port should at least conform to the very basic following concept:
+Every file port should at least conform to the very basic following concept:
template <typename T>
concept file = requires(T t) {
t.filename;
@@ -204,21 +204,21 @@ File watch
Note that this has an obvious performance cost as the host must check regularly for changes: do not overdo it!
File filters
File ports should prompt the host to open a file chooser.
-One is generally only interested in a specific file type.
-This can be specified in the following ways:
+One is generally only interested in a specific file type.
+This can be specified in the following ways:
General file filters
Here, the filter is a string of either of the following formats:
-"*.jpg *.jpeg"
-"JPEG Images (*.jpg *.jpeg)"
+"*.jpg *.jpeg"
+"JPEG Images (*.jpg *.jpeg)"
struct my_file_port : ... {
// Currently implemented:
// Any audio file that can be loaded by the host
- static consteval auto filters() { return "CSV files (*.csv)"; }
+ static consteval auto filters() { return "CSV files (*.csv)"; }
};
Domain-specific file filters
-This is for the case where you want a general kind of media and don't care specifically about the extension:
+
This is for the case where you want a general kind of media and don't care specifically about the extension:
for instance, for audio files you could have .wav, .aiff, .mp3, etc etc ; it is pointless to try to specify a whole list.
Instead, the host knows which audio file formats it is able to load and should just be able to show its own audio-specific file chooser.
struct my_file_port : ... {
diff --git a/advanced/port_types.file.midi.html b/advanced/port_types.file.midi.html
index 95b08679..e253eb4a 100644
--- a/advanced/port_types.file.midi.html
+++ b/advanced/port_types.file.midi.html
@@ -200,7 +200,7 @@ Port definiti
struct
{
- static consteval auto name() { return "My midifile"}
+ static consteval auto name() { return "My midifile"}
struct {
// Can be any vector-ish container, but must support push_back
std::vector<std::vector<midi_event>> tracks;
@@ -233,13 +233,13 @@ Port definiti
struct {
// Default event type is simple_midi_track_event for performance and compile times,
// but it can be changed through the template arguments
- halp::midifile_port<"My midifile", midi_track_event> snd;
+ halp::midifile_port<"My midifile", midi_track_event> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::midifile_port
-struct : halp::midifile_port<"My midifile"> {
+struct : halp::midifile_port<"My midifile"> {
void update(MyObject& obj) {
// This code is called whenever the midifile has been changed by the user
}
diff --git a/advanced/port_types.file.raw.html b/advanced/port_types.file.raw.html
index f90aa0cf..5e636dca 100644
--- a/advanced/port_types.file.raw.html
+++ b/advanced/port_types.file.raw.html
@@ -184,7 +184,7 @@ Port definiti
A file input port can be defined like this:
struct
{
- static consteval auto name() { return "My file"}
+ static consteval auto name() { return "My file"}
struct {
// The file data.
// Only requirement for the type is that it can be assigned {data, size}.
@@ -206,14 +206,14 @@ Port definiti
A helper type is provided:
struct {
- halp::file_port<"My file"> snd;
+ halp::file_port<"My file"> snd;
} inputs;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::file_port
// text_file_view (the default) has the text flag, and mmap_file_view has the mmap flag.
-struct : halp::file_port<"My file", mmap_file_view> {
+struct : halp::file_port<"My file", mmap_file_view> {
void update(MyObject& obj) {
// This code is called whenever the file has been changed by the user
}
diff --git a/advanced/port_types.file.sound.html b/advanced/port_types.file.sound.html
index f72925ba..ae033e5c 100644
--- a/advanced/port_types.file.sound.html
+++ b/advanced/port_types.file.sound.html
@@ -183,7 +183,7 @@ Port definiti
A soundfile input port looks like this:
struct
{
- static consteval auto name() { return "My soundfile"}
+ static consteval auto name() { return "My soundfile"}
struct {
const float** data{}; // The audio channels
int64_t frames{}; // How many samples are there in a channel
@@ -194,7 +194,7 @@ Port definiti
A helper type is provided:
struct {
- halp::soundfile_port<"My soundfile"> snd;
+ halp::soundfile_port<"My soundfile"> snd;
} inputs;
void operator()(int frames) {
@@ -214,13 +214,13 @@ Port definiti
}
It allows choosing the sample format in which the samples are loaded:
-halp::soundfile_port<"My soundfile", float> snd_float;
-halp::soundfile_port<"My soundfile", double> snd_double;
+halp::soundfile_port<"My soundfile", float> snd_float;
+halp::soundfile_port<"My soundfile", double> snd_double;
Callback
Like other ports, it is possible to get an update callback, by implementing an update
method ;
the simplest way is to make an empty struct which inherits from halp::soundfile
-struct : halp::soundfile_port<"My soundfile"> {
+struct : halp::soundfile_port<"My soundfile"> {
void update(MyObject& obj) {
// This code is called whenever the soundfile has been changed by the user
}
diff --git a/advanced/port_types.html b/advanced/port_types.html
index f5d3e252..56b00d5d 100644
--- a/advanced/port_types.html
+++ b/advanced/port_types.html
@@ -231,11 +231,11 @@ template<typename T>
using my_pair = std::pair<std::string_view, T>;
struct {
- halp_meta(name, "Enum 1");
+ halp_meta(name, "Enum 1");
enum widget { combobox };
struct range {
- my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
+ my_pair<float> values[3]{{"Foo", -10.f}, {"Bar", 5.f}, {"Baz", 10.f}};
int init{1}; // == Bar
};
@@ -257,11 +257,11 @@ Enumerating with only string
Consider the following port:
struct {
- halp_meta(name, "Enum 2");
+ halp_meta(name, "Enum 2");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -273,11 +273,11 @@ struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range {
- std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
+ std::string_view values[4]{"Roses", "Red", "Violets", "Blue"};
int init{1}; // Red
};
@@ -289,12 +289,12 @@ enum my_enum { A, B, C };
struct {
- halp_meta(name, "Enum 3");
+ halp_meta(name, "Enum 3");
enum widget { enumeration };
struct range
{
- std::string_view values[3]{"A", "B", "C"};
+ std::string_view values[3]{"A", "B", "C"};
my_enum init = my_enum::B;
};
@@ -309,9 +309,9 @@ halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
+halp__enum("Simple Enum", Peg, Square, Peg, Round, Hole) my_port;
-declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
+declares a port named "Simple Enum". The default value will be "Peg", the 4 enumerators are Square, Peg, Round, Hole.
Containers
Supported bindings: ossia
@@ -347,7 +347,7 @@ std::map
} my_port;
C arrays
-C arrays aren't supported due to limitations in the reflection capabilities of C++:
+C arrays aren't supported due to limitations in the reflection capabilities of C++:
struct {
int value[2]; // Won't work
} my_port;
@@ -376,7 +376,7 @@ Optionals
std::optional<int> value;
} my_port;
-This is used to give message semantics to the port: optionals are reset before execution of the current
+
This is used to give message semantics to the port: optionals are reset before execution of the current
tick, both for inputs and outputs. If an input is set, it means that a message was received for this tick.
If the processor sets the output, a message will be sent outwards.
This is mostly equivalent to messages and callbacks, but with a value-based instead of function-based API
@@ -404,7 +404,7 @@
struct Foo {
int a, b;
struct {
@@ -422,10 +422,10 @@
It is possible to specify field names in an aggregate manually, in order to have the sub-object be detected as a map and not a list:
@@ -440,19 +440,19 @@
This maps to:
(map) {
- name: "foo"
+ name: "foo"
, geometry: (list) [3, 4, 120, 356]
, probability: 0.95
}
Helper type
-To create a port ithout having to declare a struct, you can directly use:
-halp::val_port<"My port", std::string> my_port;
.
+To create a port ithout having to declare a struct, you can directly use:
+halp::val_port<"My port", std::string> my_port;
.
Presets
// Our inputs
struct
{
- halp::hslider_f32<"Preamp"> preamp;
- halp::hslider_f32<"Volume"> volume;
+ halp::hslider_f32<"Preamp"> preamp;
+ halp::hslider_f32<"Volume"> volume;
} inputs;
// We define the type of our programs, like in the other cases
@@ -197,8 +197,8 @@ Presets
// Note: it's an array instead of a function because
// it's apparently hard to deduce N in array<..., N>, unlike in C arrays.
static constexpr const program programs[]{
- {.name{"Low gain"}, .parameters{.preamp = {0.3}, .volume = {0.6}}},
- {.name{"Hi gain"}, .parameters{.preamp = {1.0}, .volume = {1.0}}},
+ {.name{"Low gain"}, .parameters{.preamp = {0.3}, .volume = {0.6}}},
+ {.name{"Hi gain"}, .parameters{.preamp = {1.0}, .volume = {1.0}}},
};
diff --git a/advanced/sample_accurate.example.html b/advanced/sample_accurate.example.html
index 55f2d343..050047e7 100644
--- a/advanced/sample_accurate.example.html
+++ b/advanced/sample_accurate.example.html
@@ -187,24 +187,24 @@ ossia score) are able to give precise timestamps to control values.
If an algorithm supports this level of precision, it can be expressed by extending value ports in the following way:
struct {
- static consteval auto name() { return "Control"; }
+ static consteval auto name() { return "Control"; }
/* a value_map type */ values;
float value;
} control;
-
-
value
will always carry the "running" value at the beginning of the tick, like before.
-values
is a type which should be API-wise more-or-less compatible withstd::map<int, type_of_value>
.
+value
will always carry the "running" value at the beginning of the tick, like before.
+values
is a type which should be API-wise more-or-less compatible withstd::map<int, type_of_value>
.
For every message received in the tick, values
will be set (which means that they can also be empty if no message at all was received on that port).
There are actually three options for implementing values
.
-
-
Option A:
+std::map<int, float> values
: the simplest case. Can be slow. A helper which usesboost::small_flat_map
is provided: it provides neat performance and won't allocate unless the port is spammed.Option A:
std::map<int, float> values
: the simplest case. Can be slow. A helper which usesboost::small_flat_map
is provided: it provides neat performance and won't allocate unless the port is spammed. -
Option B:
@@ -211,12 +211,12 @@std::optional<float>* values;
: here, astd::optional<float>
array of the same length than audio channels will be allocated. Indexing is the same than for audio samples.values[frame_index] is lost as the index now only goes up to the allocated messages (which can be zero if no message was received for this tick).
Helpers
A single helper is provided for now:
halp::accurate<T>
.It can be used like this to wrap an existing control type to add it a sample-accurate storage buffer:
-halp::accurate<halp::val_port<"Out", float>> my_port; -halp::accurate<halp::knob_i32<"Blah", int>> my_widget; +
diff --git a/advanced/ui.html b/advanced/ui.html index 9429acd5..e3b0a6f1 100644 --- a/advanced/ui.html +++ b/advanced/ui.html @@ -176,7 +176,7 @@halp::accurate<halp::val_port<"Out", float>> my_port; +halp::accurate<halp::knob_i32<"Blah", int>> my_widget;
Avendish documentation
Creating user interfaces
We have seen so far that we can specify widgets for our controls. Multiple back-ends may render these widgets in various ways. This is already a good start for making user interfaces, but most media systems generally have more specific user interface needs.
-Avendish allows three levels of UI definition:
+Avendish allows three levels of UI definition:
- Automatic: nothing to do, all the widgets corresponding to inputs and outputs of the processor will be generated automatically in a list. This is not pretty but sufficient for many simple cases. For instance, here is how some Avendish plug-ins render in ossia score.
Layout-base
By default, this will do nothing: we have to fill it.
ui
will be the top-level widget. Child widgets can be added simply by defining struct members. -Containers are defined by adding alayout()
function which returns an enum value, which may +Containers are defined by adding alayout()
function which returns an enum value, which may currently be any of the following names:hbox, vbox, @@ -205,7 +205,7 @@
Layout-base static constexpr auto layout() { enum { hbox } d{}; return d; } struct { static constexpr auto layout() { enum { vbox } d{}; return d; } - const char* text = "text"; + const char* text = "text"; decltype(&ins::int_ctl) int_widget = &ins::int_ctl; } widgets; @@ -215,7 +215,7 @@
Layout-base static constexpr auto height() { return 20; } } a_spacing; - const char* text = "text2"; + const char* text = "text2"; };
This defines, conceptually, the following layout:
@@ -239,15 +239,15 @@Grid
static constexpr auto columns() { return 3; }If
-columns()
is defined, children widget will be laid out in the first row until the column count is reached, then in the second row, etc. until there are no more children items, and conversely ifrows()
is defined.That is, given:
+That is, given:
struct { static constexpr auto layout() { enum { grid } d{}; return d; } static constexpr auto columns() { return 3; } - const char* text1 = "A"; - const char* text2 = "B"; - const char* text3 = "C"; - const char* text4 = "D"; - const char* text5 = "E"; + const char* text1 = "A"; + const char* text2 = "B"; + const char* text3 = "C"; + const char* text4 = "D"; + const char* text5 = "E"; } a_grid;
The layout will be:
@@ -270,15 +270,15 @@Tabs
static constexpr auto layout() { enum { tabs } d{}; return d; } struct { static constexpr auto layout() { enum { hbox } d{}; return d; } - static constexpr auto name() { return "First tab"; } - const char* text1 = "A"; - const char* text2 = "B"; + static constexpr auto name() { return "First tab"; } + const char* text1 = "A"; + const char* text2 = "B"; } a_hbox; struct { static constexpr auto layout() { enum { hbox } d{}; return d; } - static constexpr auto name() { return "Second tab"; } - const char* text3 = "C"; - const char* text4 = "D"; + static constexpr auto name() { return "Second tab"; } + const char* text3 = "C"; + const char* text4 = "D"; } a_vbox; } a_tabs; @@ -295,30 +295,30 @@Background
static constexpr auto background() { enum { dark } d{}; return d; }
Explicit positioning
-In "group" or "container" layouts, widgets will not be positioned automatically.
+x
andy
methods can be used for that.In "group" or "container" layouts, widgets will not be positioned automatically.
x
andy
methods can be used for that.static constexpr auto x() { return 20; } static constexpr auto y() { return 20; }
Explicit sizing
-Containers can be given an explicit (device independent) pixel size with
+Containers can be given an explicit (device independent) pixel size with
static constexpr auto width() { return 100; } static constexpr auto height() { return 50; }
Otherwise, things will be made to fit in a best-effort way.
Items
Text labels
-The simplest item is the text label: simply adding a
+const char*
member is sufficient.The simplest item is the text label: simply adding a
const char*
member is sufficient.Controls
-One can add a control (either input or output) simply by adding a member pointer to it:
+One can add a control (either input or output) simply by adding a member pointer to it:
struct MyProcessor { struct ins { - halp::hslider_f32<"Foo"> foo; + halp::hslider_f32<"Foo"> foo; } inputs; struct ui { static constexpr auto layout() { enum { hbox } d{}; return d; } - const char* text = "text"; + const char* text = "text"; decltype(&ins::foo) int_widget = &ins::foo; }; }; @@ -330,7 +330,7 @@
Helpers
Helpers simplify common tasks ; here, C++20 designated-initializers allow us to have a very pretty API and reduce repetitions:
Widget helpers
halp::label l1{ - .text = "some long foo" + .text = "some long foo" , .x = 100 , .y = 25 }; @@ -347,12 +347,12 @@
Propert using enum halp::colors; using enum halp::layouts; - halp_meta(name, "Main") + halp_meta(name, "Main") halp_meta(layout, hbox) halp_meta(background, mid) struct { - halp_meta(name, "Widget") + halp_meta(name, "Widget") halp_meta(layout, vbox) halp_meta(background, dark) halp::item<&ins::int_ctl> widget; diff --git a/advanced/ui.messages.example.html b/advanced/ui.messages.example.html index a1a25a33..b335037a 100644 --- a/advanced/ui.messages.example.html +++ b/advanced/ui.messages.example.html @@ -210,7 +210,7 @@
Messa ctx.set_fill_color({0, 0, 0, 255}); ctx.begin_path(); - ctx.draw_text(20., 20., fmt::format("{}", press_count)); + ctx.draw_text(20., 20., fmt::format("{}", press_count)); ctx.fill(); } @@ -256,9 +256,9 @@
Messa */ struct MessageBusUi { - static consteval auto name() { return "MessageBusUi example"; } - static consteval auto c_name() { return "avnd_mbus_ui"; } - static consteval auto uuid() { return "4ed8e7fd-a1fa-40a7-bbbe-13ee50044248"; } + static consteval auto name() { return "MessageBusUi example"; } + static consteval auto c_name() { return "avnd_mbus_ui"; } + static consteval auto uuid() { return "4ed8e7fd-a1fa-40a7-bbbe-13ee50044248"; } struct { @@ -298,7 +298,7 @@
Messa // 1. Receive a message on the processing thread from the UI void process_message(const ui_to_processor& msg) { - fprintf(stderr, "Got message in processing thread !\n"); + fprintf(stderr, "Got message in processing thread !\n"); send_message(processor_to_ui{.bar = 1.0, .baz{3, 4}}); } @@ -329,16 +329,16 @@
Messa void init(ui& ui) { ui.foo.button.on_pressed = [&] { - fprintf(stderr, "Sending message from UI thread !\n"); + fprintf(stderr, "Sending message from UI thread !\n"); this->send_message( - ui_to_processor{.foo = 123, .bar = "hiii", .x = 0.5f, .y = {1, 3, 5}}); + ui_to_processor{.foo = 123, .bar = "hiii", .x = 0.5f, .y = {1, 3, 5}}); }; } // 4. Receive a message on the UI thread from the processing thread static void process_message(ui& self, processor_to_ui msg) { - fprintf(stderr, "Got message in ui thread ! %d %d\n", msg.baz.x, msg.baz.y); + fprintf(stderr, "Got message in ui thread ! %d %d\n", msg.baz.x, msg.baz.y); self.foo.button.press_count++; } diff --git a/advanced/ui.messages.html b/advanced/ui.messages.html index 4f51b8ff..808c2fc4 100644 --- a/advanced/ui.messages.html +++ b/advanced/ui.messages.html @@ -177,13 +177,13 @@
UI message bus<
Supported bindings: ossia
Some UIs may have more complicated logic that cannot just be represented through -widgets changing single controls: pressing a button may trigger the loading of a file, +
Some UIs may have more complicated logic that cannot just be represented through +widgets changing single controls: pressing a button may trigger the loading of a file, the entire reconfiguration of the UI, etc.
-Thus, the engine may have to be notified of such changes happening in the UI. The way this is +
Thus, the engine may have to be notified of such changes happening in the UI. The way this is generally done is through thread-safe queues exchanging messages.
-An experimental implementation of this has been done in ossia score. -Here is a skeleton for how to write such a plug-in:
+An experimental implementation of this has been done in ossia score. +Here is a skeleton for how to write such a plug-in:
-using message_to_ui = ...; using message_to_engine = ...; @@ -226,12 +226,12 @@
UI message bus< }; }
Note that
+message_to_ui
andmessage_to_engine
can be any simple type:Note that
message_to_ui
andmessage_to_engine
can be any simple type:- Ints, floats, strings, etc.
std::vector
std::variant
-- Any combination and nesting of those in an aggregate struct. +
- Any combination and nesting of those in an aggregate struct.
For example, the following type will automatically be serialized & deserialized:
-struct ui_to_processor { diff --git a/advanced/ui.painting.html b/advanced/ui.painting.html index 04eeec0d..fdd232c9 100644 --- a/advanced/ui.painting.html +++ b/advanced/ui.painting.html @@ -229,7 +229,7 @@
N double rot{}; };
This produces the small squares animation here:
+This produces the small squares animation here:
Interactive items for controlling single ports
This is even more experimental :)
@@ -370,11 +370,11 @@Painter API
t.set_fill_color({255, 255, 255, 127}); // Text: - t.set_font("Comic Sans"); + t.set_font("Comic Sans"); t.set_font_size(10.0); // In points // x , y , text - t.draw_text(0., 0., "Hello World"); + t.draw_text(0., 0., "Hello World"); // Drawing // x1, y1, x2 , y2 @@ -387,7 +387,7 @@Painter API
t.draw_rounded_rect(0., 0., 10., 10., 5.); // x , y , filename - t.draw_pixmap(0., 0., "pixmap"); + t.draw_pixmap(0., 0., "pixmap"); // x , y , w , h t.draw_ellipse(0., 0., 10., 10.); diff --git a/advanced/workers.html b/advanced/workers.html index e0f269ad..40a3e8d6 100644 --- a/advanced/workers.html +++ b/advanced/workers.html @@ -177,16 +177,16 @@Workers
Supported bindings: ossia
It is relatively common to require to perform some long-running work in a separate thread: +
It is relatively common to require to perform some long-running work in a separate thread: processing samples, etc.
Avendish provides two APIs for doing this: a general one, and a simpler one for the specific case of pre-processing the data of a port (for instance when a file is loaded).
The general idea is that the processor code sends a request to the worker with some data. -The host processes the request in a thread. This returns a function which is then called back +The host processes the request in a thread. This returns a function which is then called back onto the processor, to update its state with the result of the computations.
General worker API Usage
In the main class, define a
worker
struct/instance ; the arguments can be anything. -Here we'll have a request that takes anint, std::string
set of arguments ; to have multiple +Here we'll have a request that takes anint, std::string
set of arguments ; to have multiple behaviours one can use a std::variant of potential requests.struct MyObject { @@ -195,7 +195,7 @@
// 1. Within the DSP thread: void operator()(...) { if(something_happened) { - this->worker.request(123, "foo"); + this->worker.request(123, "foo"); } } // 2. Implement the worker::work function: std::function<void(MyObject&)> MyObject::worker::work(int x, std::string foo) { - // 3. Implement the "threaded" work part: + // 3. Implement the "threaded" work part: // This is executed in a separate worker thread, slow operations can be done here // safely. @@ -230,7 +230,7 @@
// Sadly does not do anything as the object inside the lambda is const by default, @@ -255,7 +255,7 @@
https://github.com/ossia/score-addon-threedim/blob/main/Threedim/StructureSynth.hpp
Simple threaded port-processing API usage
-This API is a "simplified" version of the above one for the common case of wanting +
This API is a "simplified" version of the above one for the common case of wanting to pre-process some data which was loaded from the hard drive.
It is accessed by adding the following to a port:
struct : my_file_port { diff --git a/development/predicates.html b/development/predicates.html index 191ce64f..d5274270 100644 --- a/development/predicates.html +++ b/development/predicates.html @@ -175,7 +175,7 @@
Avendish documentation
Type predicates and introspection
The core enabler of Avendish is the ability to filter struct definitions according to predicates.
-That is, given:
+That is, given:
struct Foo { int16_t x; float y; @@ -205,8 +205,8 @@
Doing something for the Nth member of a struct without an instance
-This function lifts a run-time index into a compile-time value. -This is useful for instance for mapping a run-time parameter id coming from a DAW, +
This function lifts a run-time index into a compile-time value. +This is useful for instance for mapping a run-time parameter id coming from a DAW, into a field, such as when a parameter changes.
fields_instrospection<T>::for_nth( index, @@ -232,18 +232,18 @@
Predicate introspection
The type
-predicate_introspection<T, Pred>
allows similar operations on a filtered subset of the struct members.For instance, given the predicate:
+For instance, given the predicate:
-template<typename Field> using is_int<Field> = std::integral_constant<bool, std::is_integral_v<Field>>;
then
+then
-using ints = predicate_introspection<Foo, is_int>;
will allow to query all the
int16_t
andint32_t
members of the struct. +will allow to query all the
-int16_t
andint32_t
members of the struct. This example is assumed for all the cases below.
+predicate_introspection<Foo, is_int>
will work within this referential: indices will refer to -these types. That is, the element 0 will beint16_t
and element 1 will beint32_t
. -Multiple methods are provided to go from and to indices in the complete struct, to indices in the filtered version:predicate_introspection<Foo, is_int>
will work within this referential: indices will refer to +these types. That is, the element 0 will beint16_t
and element 1 will beint32_t
. +Multiple methods are provided to go from and to indices in the complete struct, to indices in the filtered version: