diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98e8bf9a..d4aa1869 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,7 @@
- Added parameter tooltips for quickly viewing parameter values
- Added parameter context menu for entering numerical values, unmapping, etc
- Changed parameter initialization to double-click
-- Added undo history
+- Added undo/redo history
- Added GlWidget for rendering to an OpenGL context
- Added ability to disable modules with a context menu item and key command
- Added default template patch
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 2e1bd216..19b60a40 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = "VCV Rack"
+PROJECT_NAME = "VCV Rack API"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
diff --git a/include/engine/Module.hpp b/include/engine/Module.hpp
index 6976748d..df58f3fb 100644
--- a/include/engine/Module.hpp
+++ b/include/engine/Module.hpp
@@ -21,27 +21,54 @@ namespace plugin {
namespace engine {
+/** DSP processor instance for your module. */
struct Module {
- plugin::Model *model = NULL;
- /** Automatically generated by the engine. */
+ plugin::Model *model = NULL; /** Unique ID for referring to the module in the engine.
+ Assigned when added to the engine.
+ */
int id = -1;
- /** Arrays of components */
+
+ /** Arrays of components.
+ Initialized with config().
+ */
std::vector params;
std::vector outputs;
std::vector inputs;
std::vector lights;
std::vector paramQuantities;
- /** Access to adjacent modules */
+
+ /** ID of the Module immediately to the left, or -1 if nonexistent. */
int leftModuleId = -1;
+ /** Pointer to the left Module, or NULL if nonexistent. */
Module *leftModule = NULL;
+ /** Double buffer for receiving messages from adjacent modules.
+ If this module receives messages from adjacent modules, allocate both message buffers with identical blocks of memory (arrays, structs, etc).
+ Remember to free the buffer in the Module destructor.
+ Example:
+
+ leftProducerMessage = new MyModuleMessage;
+ leftConsumerMessage = new MyModuleMessage;
+
+ At the end of each timestep, the buffers are flipped/swapped.
+
+ You may choose for the Module to write to its own message buffer for consumption by other modules.
+ As long as this convention is followed by the left Module, this is fine.
+ */
void *leftProducerMessage = NULL;
void *leftConsumerMessage = NULL;
+
int rightModuleId = -1;
Module *rightModule = NULL;
void *rightProducerMessage = NULL;
void *rightConsumerMessage = NULL;
- /** For CPU meter. */
+
+ /** Seconds spent in the process() method, with exponential smoothing.
+ Only written when CPU timing is enabled, since time measurement is expensive.
+ */
float cpuTime = 0.f;
+ /** Whether the Module is skipped from stepping by the engine.
+ Module subclasses should not read/write this variable.
+ */
bool bypass = false;
/** Constructs a Module with no params, inputs, outputs, and lights. */
diff --git a/include/math.hpp b/include/math.hpp
index ba44e13f..fee748f9 100644
--- a/include/math.hpp
+++ b/include/math.hpp
@@ -15,32 +15,32 @@ namespace math {
// basic integer functions
////////////////////
-/** Returns true if x is odd. */
+/** Returns true if `x` is odd. */
inline bool isEven(int x) {
return x % 2 == 0;
}
-/** Returns true if x is odd. */
+/** Returns true if `x` is odd. */
inline bool isOdd(int x) {
return x % 2 != 0;
}
/** Limits `x` between `a` and `b`.
-If b < a, returns a.
+If `b < a`, returns a.
*/
inline int clamp(int x, int a, int b) {
return std::max(std::min(x, b), a);
}
/** Limits `x` between `a` and `b`.
-If b < a, switches the two values.
+If `b < a`, switches the two values.
*/
inline int clampSafe(int x, int a, int b) {
return clamp(x, std::min(a, b), std::max(a, b));
}
-/** Euclidean modulus. Always returns 0 <= mod < b.
-b must be positive.
+/** Euclidean modulus. Always returns `0 <= mod < b`.
+`b` must be positive.
See https://en.wikipedia.org/wiki/Euclidean_division
*/
inline int eucMod(int a, int b) {
@@ -52,7 +52,7 @@ inline int eucMod(int a, int b) {
}
/** Euclidean division.
-b must be positive.
+`b` must be positive.
*/
inline int eucDiv(int a, int b) {
int div = a / b;
@@ -72,7 +72,7 @@ inline void eucDivMod(int a, int b, int *div, int *mod) {
}
}
-/** Returns floor(log_2(n)), or 0 if n == 1. */
+/** Returns `floor(log_2(n))`, or 0 if `n == 1`. */
inline int log2(int n) {
int i = 0;
while (n >>= 1) {
@@ -91,14 +91,14 @@ inline bool isPow2(int n) {
////////////////////
/** Limits `x` between `a` and `b`.
-If b < a, returns a.
+If `b < a`, returns a.
*/
inline float clamp(float x, float a, float b) {
return std::fmax(std::fmin(x, b), a);
}
/** Limits `x` between `a` and `b`.
-If b < a, switches the two values.
+If `b < a`, switches the two values.
*/
inline float clampSafe(float x, float a, float b) {
return clamp(x, std::fmin(a, b), std::fmax(a, b));
@@ -116,7 +116,7 @@ inline float normalizeZero(float x) {
return x + 0.f;
}
-/** Euclidean modulus. Always returns 0 <= mod < b.
+/** Euclidean modulus. Always returns `0 <= mod < b`.
See https://en.wikipedia.org/wiki/Euclidean_division.
*/
inline float eucMod(float a, float base) {
@@ -124,12 +124,12 @@ inline float eucMod(float a, float base) {
return (mod >= 0.f) ? mod : mod + base;
}
-/** Returns whether a is within epsilon distance from b. */
+/** Returns whether `a` is within epsilon distance from `b`. */
inline bool isNear(float a, float b, float epsilon = 1e-6f) {
return std::fabs(a - b) <= epsilon;
}
-/** If the magnitude of x if less than epsilon, return 0. */
+/** If the magnitude of `x` if less than epsilon, return 0. */
inline float chop(float x, float epsilon = 1e-6f) {
return isNear(x, 0.f, epsilon) ? 0.f : x;
}
@@ -143,7 +143,7 @@ inline float crossfade(float a, float b, float p) {
}
/** Linearly interpolates an array `p` with index `x`.
-Assumes that the array at `p` is of length at least floor(x)+1.
+Assumes that the array at `p` is of length at least `floor(x) + 1`.
*/
inline float interpolateLinear(const float *p, float x) {
int xi = x;
@@ -151,9 +151,11 @@ inline float interpolateLinear(const float *p, float x) {
return crossfade(p[xi], p[xi+1], xf);
}
-/** Complex multiplies c = a * b.
+/** Complex multiplication `c = a * b`.
Arguments may be the same pointers.
-i.e. cmultf(&ar, &ai, ar, ai, br, bi)
+Example:
+
+ cmultf(&ar, &ai, ar, ai, br, bi);
*/
inline void complexMult(float *cr, float *ci, float ar, float ai, float br, float bi) {
*cr = ar * br - ai * bi;
@@ -174,7 +176,7 @@ struct Vec {
Vec(float x, float y) : x(x), y(y) {}
/** Negates the vector.
- Equivalent to a reflection across the y=-x line.
+ Equivalent to a reflection across the `y = -x` line.
*/
Vec neg() const {
return Vec(-x, -y);
@@ -213,7 +215,7 @@ struct Vec {
return Vec(x * cos - y * sin, x * sin + y * cos);
}
/** Swaps the coordinates.
- Equivalent to a reflection across the y=x line.
+ Equivalent to a reflection across the `y = x` line.
*/
Vec flip() const {
return Vec(y, x);