diff --git a/examples/fx_trem/daisy-seed/Makefile b/examples/fx_trem/daisy-seed/Makefile
new file mode 100644
index 0000000..a369483
--- /dev/null
+++ b/examples/fx_trem/daisy-seed/Makefile
@@ -0,0 +1,7 @@
+ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
+
+TARGET = bw_example_fx_trem
+
+C_SOURCES += ${ROOT_DIR}/../src/bw_example_fx_trem.c
+
+include ${ROOT_DIR}/../../common/daisy-seed/daisy-seed.mk
diff --git a/examples/fx_trem/daisy-seed/config_daisy_seed.h b/examples/fx_trem/daisy-seed/config_daisy_seed.h
new file mode 100644
index 0000000..c56c264
--- /dev/null
+++ b/examples/fx_trem/daisy-seed/config_daisy_seed.h
@@ -0,0 +1,36 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File authors: Stefano D'Angelo
+ */
+
+#ifndef _CONFIG_DAISY_SEED_H
+#define _CONFIG_DAISY_SEED_H
+
+struct config_pin {
+ int param_index;
+ int pin;
+};
+
+#define NUM_PINS 2
+
+static struct config_pin config_pins[NUM_PINS] = {
+ { 0, 15 },
+ { 1, 16 }
+};
+
+#endif
diff --git a/examples/fx_trem/src/bw_example_fx_trem.c b/examples/fx_trem/src/bw_example_fx_trem.c
new file mode 100644
index 0000000..5f5bbcf
--- /dev/null
+++ b/examples/fx_trem/src/bw_example_fx_trem.c
@@ -0,0 +1,54 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File author: Stefano D'Angelo
+ */
+
+#include "bw_example_fx_trem.h"
+
+void bw_example_fx_trem_init(bw_example_fx_trem *instance) {
+ bw_trem_init(&instance->trem_coeffs);
+}
+
+void bw_example_fx_trem_set_sample_rate(bw_example_fx_trem *instance, float sample_rate) {
+ bw_trem_set_sample_rate(&instance->trem_coeffs, sample_rate);
+}
+
+void bw_example_fx_trem_reset(bw_example_fx_trem *instance) {
+ bw_trem_reset_coeffs(&instance->trem_coeffs);
+ bw_trem_reset_state(&instance->trem_coeffs, &instance->trem_state);
+}
+
+void bw_example_fx_trem_process(bw_example_fx_trem *instance, const float** x, float** y, int n_samples) {
+ bw_trem_process(&instance->trem_coeffs, &instance->trem_state, x[0], y[0], n_samples);
+}
+
+void bw_example_fx_trem_set_parameter(bw_example_fx_trem *instance, int index, float value) {
+ instance->params[index] = value;
+ switch (index) {
+ case p_speed:
+ bw_trem_set_frequency(&instance->trem_coeffs, (20.f - 1.f) * value * value * value + 1.f);
+ break;
+ case p_amount:
+ bw_trem_set_amount(&instance->trem_coeffs, value);
+ break;
+ }
+}
+
+float bw_example_fx_trem_get_parameter(bw_example_fx_trem *instance, int index) {
+ return instance->params[index];
+}
diff --git a/examples/fx_trem/src/bw_example_fx_trem.h b/examples/fx_trem/src/bw_example_fx_trem.h
new file mode 100644
index 0000000..b600424
--- /dev/null
+++ b/examples/fx_trem/src/bw_example_fx_trem.h
@@ -0,0 +1,57 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File author: Stefano D'Angelo
+ */
+
+#ifndef _BW_EXAMPLE_FX_TREM_H
+#define _BW_EXAMPLE_FX_TREM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+enum {
+ p_speed,
+ p_amount,
+ p_n
+};
+
+struct _bw_example_fx_trem {
+ // Sub-components
+ bw_trem_coeffs trem_coeffs;
+ bw_trem_state trem_state;
+
+ // Parameters
+ float params[p_n];
+};
+typedef struct _bw_example_fx_trem bw_example_fx_trem;
+
+void bw_example_fx_trem_init(bw_example_fx_trem *instance);
+void bw_example_fx_trem_set_sample_rate(bw_example_fx_trem *instance, float sample_rate);
+void bw_example_fx_trem_reset(bw_example_fx_trem *instance);
+void bw_example_fx_trem_process(bw_example_fx_trem *instance, const float** x, float** y, int n_samples);
+void bw_example_fx_trem_set_parameter(bw_example_fx_trem *instance, int index, float value);
+float bw_example_fx_trem_get_parameter(bw_example_fx_trem *instance, int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/examples/fx_trem/src/config.h b/examples/fx_trem/src/config.h
new file mode 100644
index 0000000..b20c6bf
--- /dev/null
+++ b/examples/fx_trem/src/config.h
@@ -0,0 +1,88 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File authors: Stefano D'Angelo
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+// Definitions
+
+#define IO_MONO 1
+#define IO_STEREO (1<<1)
+
+struct config_io_bus {
+ const char *name;
+ char out;
+ char aux;
+ char cv;
+ char configs;
+};
+
+struct config_parameter {
+ const char *name;
+ const char *shortName;
+ const char *units;
+ char out;
+ char bypass;
+ int steps;
+ float defaultValueUnmapped;
+};
+
+// Data
+
+#define COMPANY_NAME "Orastron"
+#define COMPANY_WEBSITE "https://www.orastron.com/"
+#define COMPANY_MAILTO "mailto:info@orastron.com"
+
+#define PLUGIN_NAME "bw_example_fx_trem"
+#define PLUGIN_VERSION "0.3.0"
+
+#define NUM_BUSES_IN 1
+#define NUM_BUSES_OUT 1
+#define NUM_CHANNELS_IN 1
+#define NUM_CHANNELS_OUT 1
+
+static struct config_io_bus config_buses_in[NUM_BUSES_IN] = {
+ { "Audio in", 0, 0, 0, IO_MONO }
+};
+
+static struct config_io_bus config_buses_out[NUM_BUSES_OUT] = {
+ { "Audio out", 1, 0, 0, IO_MONO }
+};
+
+#define NUM_PARAMETERS 2
+
+static struct config_parameter config_parameters[NUM_PARAMETERS] = {
+ { "Speed", "Speed", "", 0, 0, 0, 0.5f },
+ { "Amount", "Amount", "", 0, 0, 0, 0.5f }
+};
+
+// Internal API
+
+#include "bw_example_fx_trem.h"
+
+#define P_TYPE bw_example_fx_trem
+#define P_INIT bw_example_fx_trem_init
+#define P_SET_SAMPLE_RATE bw_example_fx_trem_set_sample_rate
+#define P_RESET bw_example_fx_trem_reset
+#define P_PROCESS bw_example_fx_trem_process
+#define P_SET_PARAMETER bw_example_fx_trem_set_parameter
+#define P_GET_PARAMETER bw_example_fx_trem_get_parameter
+
+#endif
diff --git a/examples/fx_trem/vst3/Makefile b/examples/fx_trem/vst3/Makefile
new file mode 100644
index 0000000..4618a88
--- /dev/null
+++ b/examples/fx_trem/vst3/Makefile
@@ -0,0 +1,6 @@
+ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
+
+NAME := bw_example_fx_trem
+SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_trem.c
+
+include ${ROOT_DIR}/../../common/vst3/vst3.mk
diff --git a/examples/fx_trem/vst3/config_vst3.h b/examples/fx_trem/vst3/config_vst3.h
new file mode 100644
index 0000000..bd161a5
--- /dev/null
+++ b/examples/fx_trem/vst3/config_vst3.h
@@ -0,0 +1,36 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File authors: Stefano D'Angelo, Paolo Marrone
+ */
+
+#ifndef _VST3_CONFIG_H
+#define _VST3_CONFIG_H
+
+#define PLUGIN_SUBCATEGORY "Fx|Modulation"
+
+#define PLUGIN_GUID_1 0xf26324d0
+#define PLUGIN_GUID_2 0x66ed4652
+#define PLUGIN_GUID_3 0x9197bb20
+#define PLUGIN_GUID_4 0xf6bfc407
+
+#define CTRL_GUID_1 0x17fcf5e1
+#define CTRL_GUID_2 0x93154192
+#define CTRL_GUID_3 0x8264849e
+#define CTRL_GUID_4 0x22e52112
+
+#endif
diff --git a/examples/fx_trem/web/Makefile b/examples/fx_trem/web/Makefile
new file mode 100644
index 0000000..b82dfd0
--- /dev/null
+++ b/examples/fx_trem/web/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
+SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_trem.c
+
+include ${ROOT_DIR}/../../common/web/web.mk
diff --git a/examples/fx_trem/web/config.js b/examples/fx_trem/web/config.js
new file mode 100644
index 0000000..1b18f5b
--- /dev/null
+++ b/examples/fx_trem/web/config.js
@@ -0,0 +1,43 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File author: Stefano D'Angelo
+ */
+
+var buses = [
+ {
+ stereo: false,
+ output: false
+ },
+ {
+ stereo: false,
+ output: true
+ }
+];
+
+var parameters = [
+ {
+ name: "Speed",
+ output: false,
+ defaultValue: 0.5
+ },
+ {
+ name: "Amount",
+ output: false,
+ defaultValue: 0.5
+ }
+];
diff --git a/include/bw_ringmod.h b/include/bw_ringmod.h
index 8de3d38..5daca28 100644
--- a/include/bw_ringmod.h
+++ b/include/bw_ringmod.h
@@ -98,9 +98,9 @@ static inline void bw_ringmod_process(bw_ringmod_coeffs *BW_RESTRICT coeffs, con
* output buffer `y`, while using and updating `coeffs` (control and audio
* rate).
*
- * #### bw_ringmod_set_mod_amount()
+ * #### bw_ringmod_set_amount()
* ```>>> */
-static inline void bw_ringmod_set_mod_amount(bw_ringmod_coeffs *BW_RESTRICT coeffs, float value);
+static inline void bw_ringmod_set_amount(bw_ringmod_coeffs *BW_RESTRICT coeffs, float value);
/*! <<<```
* Sets the modulation amount parameter to the given `value` (`0.f` = no
* modulation, `1.f` = full modulation, `-1.f` = full modulation with
@@ -159,7 +159,7 @@ static inline void bw_ringmod_process(bw_ringmod_coeffs *BW_RESTRICT coeffs, con
}
}
-static inline void bw_ringmod_set_mod_amount(bw_ringmod_coeffs *BW_RESTRICT coeffs, float value) {
+static inline void bw_ringmod_set_amount(bw_ringmod_coeffs *BW_RESTRICT coeffs, float value) {
coeffs->mod_amount = value;
}
diff --git a/include/bw_trem.h b/include/bw_trem.h
new file mode 100644
index 0000000..e3162ed
--- /dev/null
+++ b/include/bw_trem.h
@@ -0,0 +1,211 @@
+/*
+ * Brickworks
+ *
+ * Copyright (C) 2023 Orastron Srl unipersonale
+ *
+ * Brickworks is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * Brickworks is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Brickworks. If not, see .
+ *
+ * File author: Stefano D'Angelo
+ */
+
+/*!
+ * module_type {{{ dsp }}}
+ * version {{{ 0.4.0 }}}
+ * requires {{{
+ * bw_config bw_common bw_math bw_one_pole bw_osc_sin bw_phase_gen bw_ringmod
+ * }}}
+ * description {{{
+ * Tremolo with variable speed and amount.
+ * }}}
+ * changelog {{{
+ *
+ * - Version 0.4.0:
+ *
+ *
+ *
+ * }}}
+ */
+
+#ifndef _BW_TREM_H
+#define _BW_TREM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+/*! api {{{
+ * #### bw_trem_coeffs
+ * ```>>> */
+typedef struct _bw_trem_coeffs bw_trem_coeffs;
+/*! <<<```
+ * Coefficients and related.
+ *
+ * ### bw_trem_state
+ * ```>>> */
+typedef struct _bw_trem_state bw_trem_state;
+/*! <<<```
+ * Internal state and related.
+ *
+ * #### bw_trem_init()
+ * ```>>> */
+static inline void bw_trem_init(bw_trem_coeffs *BW_RESTRICT coeffs);
+/*! <<<```
+ * Initializes input parameter values in `coeffs`.
+ *
+ * #### bw_trem_set_sample_rate()
+ * ```>>> */
+static inline void bw_trem_set_sample_rate(bw_trem_coeffs *BW_RESTRICT coeffs, float sample_rate);
+/*! <<<```
+ * Sets the `sample_rate` (Hz) value in `coeffs`.
+ *
+ * #### bw_trem_reset_coeffs()
+ * ```>>> */
+static inline void bw_trem_reset_coeffs(bw_trem_coeffs *BW_RESTRICT coeffs);
+/*! <<<```
+ * Resets coefficients in `coeffs` to assume their target values.
+ *
+ * #### bw_trem_reset_state()
+ * ```>>> */
+static inline void bw_trem_reset_state(const bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state);
+/*! <<<```
+ * Resets the given `state` to its initial values using the given `coeffs`.
+ *
+ * #### bw_trem_update_coeffs_ctrl()
+ * ```>>> */
+static inline void bw_trem_update_coeffs_ctrl(bw_trem_coeffs *BW_RESTRICT coeffs);
+/*! <<<```
+ * Triggers control-rate update of coefficients in `coeffs`.
+ *
+ * #### bw_trem_update_coeffs_audio()
+ * ```>>> */
+static inline void bw_trem_update_coeffs_audio(bw_trem_coeffs *BW_RESTRICT coeffs);
+/*! <<<```
+ * Triggers audio-rate update of coefficients in `coeffs`.
+ *
+ * #### bw_trem_process1()
+ * ```>>> */
+static inline float bw_trem_process1(const bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state, float x);
+/*! <<<```
+ * Processes one input sample `x` using `coeffs`, while using and updating
+ * `state`. Returns the corresponding output sample.
+ *
+ * #### bw_trem_process()
+ * ```>>> */
+static inline void bw_trem_process(bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state, const float *x, float *y, int n_samples);
+/*! <<<```
+ * Processes the first `n_samples` of the input buffer `x` and fills the
+ * first `n_samples` of the output buffer `y`, while using and updating both
+ * `coeffs` and `state` (control and audio rate).
+ *
+ * #### bw_trem_set_speed()
+ * ```>>> */
+static inline void bw_trem_set_frequency(bw_trem_coeffs *BW_RESTRICT coeffs, float value);
+/*! <<<```
+ * Sets the modulation frequency (speed) `value` (Hz) in `coeffs`.
+ *
+ * Default value: `1.f`.
+ *
+ * #### bw_trem_set_thresh_dBFS()
+ * ```>>> */
+static inline void bw_trem_set_amount(bw_trem_coeffs *BW_RESTRICT coeffs, float value);
+/*! <<<```
+ * Sets the amount parameter to the given `value` (`0.f` = no tremolo, `1.f`
+ * = full tremolo, `-1.f` = full tremolo with inverted polarity) in `coeffs`.
+ *
+ * Default value: `1.f`.
+ * }}} */
+
+/*** Implementation ***/
+
+/* WARNING: This part of the file is not part of the public API. Its content may
+ * change at any time in future versions. Please, do not use it directly. */
+
+#include
+#include
+#include
+
+struct _bw_trem_coeffs {
+ // Sub-components
+ bw_phase_gen_coeffs phase_gen_coeffs;
+ bw_ringmod_coeffs ringmod_coeffs;
+
+ // Coefficients
+
+ // Parameters
+};
+
+struct _bw_trem_state {
+ bw_phase_gen_state phase_gen_state;
+};
+
+static inline void bw_trem_init(bw_trem_coeffs *BW_RESTRICT coeffs) {
+ bw_phase_gen_init(&coeffs->phase_gen_coeffs);
+ bw_ringmod_init(&coeffs->ringmod_coeffs);
+}
+
+static inline void bw_trem_set_sample_rate(bw_trem_coeffs *BW_RESTRICT coeffs, float sample_rate) {
+ bw_phase_gen_set_sample_rate(&coeffs->phase_gen_coeffs, sample_rate);
+ bw_ringmod_set_sample_rate(&coeffs->ringmod_coeffs, sample_rate);
+}
+
+static inline void bw_trem_reset_coeffs(bw_trem_coeffs *BW_RESTRICT coeffs) {
+ bw_phase_gen_reset_coeffs(&coeffs->phase_gen_coeffs);
+ bw_ringmod_reset_coeffs(&coeffs->ringmod_coeffs);
+}
+
+static inline void bw_trem_reset_state(const bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state) {
+ bw_phase_gen_reset_state(&coeffs->phase_gen_coeffs, &state->phase_gen_state, 0.f);
+}
+
+static inline void bw_trem_update_coeffs_ctrl(bw_trem_coeffs *BW_RESTRICT coeffs) {
+ bw_phase_gen_update_coeffs_ctrl(&coeffs->phase_gen_coeffs);
+ bw_ringmod_update_coeffs_ctrl(&coeffs->ringmod_coeffs);
+}
+
+static inline void bw_trem_update_coeffs_audio(bw_trem_coeffs *BW_RESTRICT coeffs) {
+ bw_phase_gen_update_coeffs_audio(&coeffs->phase_gen_coeffs);
+ bw_ringmod_update_coeffs_audio(&coeffs->ringmod_coeffs);
+}
+
+static inline float bw_trem_process1(const bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state, float x) {
+ float p, pi;
+ bw_phase_gen_process1(&coeffs->phase_gen_coeffs, &state->phase_gen_state, &p, &pi);
+ const float c = bw_osc_sin_process1(p);
+ return bw_ringmod_process1(&coeffs->ringmod_coeffs, x, 1.f + c);
+}
+
+static inline void bw_trem_process(bw_trem_coeffs *BW_RESTRICT coeffs, bw_trem_state *BW_RESTRICT state, const float *x, float *y, int n_samples) {
+ bw_trem_update_coeffs_ctrl(coeffs);
+ for (int i = 0; i < n_samples; i++) {
+ bw_trem_update_coeffs_audio(coeffs);
+ y[i] = bw_trem_process1(coeffs, state, x[i]);
+ }
+}
+
+static inline void bw_trem_set_frequency(bw_trem_coeffs *BW_RESTRICT coeffs, float value) {
+ bw_phase_gen_set_frequency(&coeffs->phase_gen_coeffs, value);
+}
+
+static inline void bw_trem_set_amount(bw_trem_coeffs *BW_RESTRICT coeffs, float value) {
+ bw_ringmod_set_amount(&coeffs->ringmod_coeffs, value);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif