finalized bw_{ring_mod,osc_sin}, bw_dry_wet (untested) + new fx(pp)_ring_mod + cosmetics

This commit is contained in:
Stefano D'Angelo 2023-09-18 17:04:11 +02:00
parent baf440a171
commit dc93bd675b
27 changed files with 1248 additions and 105 deletions

View File

@ -0,0 +1,6 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fx_ring_mod
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_ring_mod.c
include ${ROOT_DIR}/../../common/android/android.mk

View File

@ -0,0 +1,7 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TARGET = bw_example_fx_ring_mod
C_SOURCES += ${ROOT_DIR}/../src/bw_example_fx_ring_mod.c
include ${ROOT_DIR}/../../common/daisy-seed/daisy-seed.mk

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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

View File

@ -0,0 +1,6 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fx_ring_mod
SOURCE := ${NAME}.c
include ${ROOT_DIR}/../../common/ios/ios.mk

View File

@ -0,0 +1,62 @@
/*
* Brickworks
*
* Copyright (C) 2022, 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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#include "bw_example_fx_ring_mod.h"
#include <bw_osc_sin.h>
void bw_example_fx_ring_mod_init(bw_example_fx_ring_mod *instance) {
bw_phase_gen_init(&instance->phase_gen_coeffs);
bw_ring_mod_init(&instance->ring_mod_coeffs);
}
void bw_example_fx_ring_mod_set_sample_rate(bw_example_fx_ring_mod *instance, float sample_rate) {
bw_phase_gen_set_sample_rate(&instance->phase_gen_coeffs, sample_rate);
bw_ring_mod_set_sample_rate(&instance->ring_mod_coeffs, sample_rate);
}
void bw_example_fx_ring_mod_reset(bw_example_fx_ring_mod *instance) {
bw_phase_gen_reset_coeffs(&instance->phase_gen_coeffs);
float v, v_inc;
bw_phase_gen_reset_state(&instance->phase_gen_coeffs, &instance->phase_gen_state, 0.f, &v, &v_inc);
bw_ring_mod_reset_coeffs(&instance->ring_mod_coeffs);
}
void bw_example_fx_ring_mod_process(bw_example_fx_ring_mod *instance, const float** x, float** y, int n_samples) {
bw_phase_gen_process(&instance->phase_gen_coeffs, &instance->phase_gen_state, NULL, y[0], NULL, n_samples);
bw_osc_sin_process(y[0], y[0], n_samples);
bw_ring_mod_process(&instance->ring_mod_coeffs, x[0], y[0], y[0], n_samples);
}
void bw_example_fx_ring_mod_set_parameter(bw_example_fx_ring_mod *instance, int index, float value) {
instance->params[index] = value;
switch (index) {
case p_freq:
bw_phase_gen_set_frequency(&instance->phase_gen_coeffs, 100.f + (1000.f - 100.f) * value * value * value);
break;
case p_amount:
bw_ring_mod_set_amount(&instance->ring_mod_coeffs, -1.f + 2.f * value);
break;
}
}
float bw_example_fx_ring_mod_get_parameter(bw_example_fx_ring_mod *instance, int index) {
return instance->params[index];
}

View File

@ -0,0 +1,61 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#ifndef _BW_EXAMPLE_FX_RING_MOD_H
#define _BW_EXAMPLE_FX_RING_MOD_H
#include "platform.h"
#include <bw_ring_mod.h>
#include <bw_phase_gen.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
p_freq,
p_amount,
p_n
};
struct _bw_example_fx_ring_mod {
// Sub-components
bw_phase_gen_coeffs phase_gen_coeffs;
bw_phase_gen_state phase_gen_state;
bw_ring_mod_coeffs ring_mod_coeffs;
// Parameters
float params[p_n];
};
typedef struct _bw_example_fx_ring_mod bw_example_fx_ring_mod;
void bw_example_fx_ring_mod_init(bw_example_fx_ring_mod *instance);
void bw_example_fx_ring_mod_set_sample_rate(bw_example_fx_ring_mod *instance, float sample_rate);
void bw_example_fx_ring_mod_reset(bw_example_fx_ring_mod *instance);
void bw_example_fx_ring_mod_process(bw_example_fx_ring_mod *instance, const float** x, float** y, int n_samples);
void bw_example_fx_ring_mod_set_parameter(bw_example_fx_ring_mod *instance, int index, float value);
float bw_example_fx_ring_mod_get_parameter(bw_example_fx_ring_mod *instance, int index);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,88 @@
/*
* Brickworks
*
* Copyright (C) 2022, 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 <http://www.gnu.org/licenses/>.
*
* 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_ring_mod"
#define PLUGIN_VERSION "1.0.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] = {
{ "Frequency", "Freq", "Hz", 0, 0, 0, 0.5f },
{ "Amount", "Amount", "", 0, 0, 0, 1.0f },
};
// Internal API
#include "bw_example_fx_ring_mod.h"
#define P_TYPE bw_example_fx_ring_mod
#define P_INIT bw_example_fx_ring_mod_init
#define P_SET_SAMPLE_RATE bw_example_fx_ring_mod_set_sample_rate
#define P_RESET bw_example_fx_ring_mod_reset
#define P_PROCESS bw_example_fx_ring_mod_process
#define P_SET_PARAMETER bw_example_fx_ring_mod_set_parameter
#define P_GET_PARAMETER bw_example_fx_ring_mod_get_parameter
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
var buses = [
{
stereo: false,
output: false
},
{
stereo: false,
output: true
}
];
var parameters = [
{
name: "Frequency",
output: false,
defaultValue: 0.5
},
{
name: "Amount",
output: false,
defaultValue: 1.0
}
];

View File

@ -0,0 +1,9 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fx_ring_mod
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_ring_mod.c
include ${ROOT_DIR}/../../common/vst3/vst3.mk
CXXFLAGS += -DRELEASE=1 -DNDEBUG -DBW_NO_DEBUG
#CXXFLAGS += -DDEVELOPMENT=1 -DBW_DEBUG_DEEP

View File

@ -0,0 +1,36 @@
/*
* Brickworks
*
* Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
*
* File authors: Stefano D'Angelo, Paolo Marrone
*/
#ifndef _VST3_CONFIG_H
#define _VST3_CONFIG_H
#define PLUGIN_SUBCATEGORY "Fx"
#define PLUGIN_GUID_1 0x2680121d
#define PLUGIN_GUID_2 0x4e0b47fa
#define PLUGIN_GUID_3 0xb213e6e7
#define PLUGIN_GUID_4 0xd13cde60
#define CTRL_GUID_1 0xc747bf7a
#define CTRL_GUID_2 0x90ac41d0
#define CTRL_GUID_3 0xb53d3df9
#define CTRL_GUID_4 0x2c81a74d
#endif

View File

@ -0,0 +1,4 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_ring_mod.c
include ${ROOT_DIR}/../../common/web/web.mk

View File

@ -0,0 +1,6 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fxpp_ring_mod
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fxpp_ring_mod.cpp
include ${ROOT_DIR}/../../common/android/android.mk

View File

@ -0,0 +1,7 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TARGET = bw_example_fxpp_ring_mod
CPP_SOURCES_EXTRA = ${ROOT_DIR}/../src/bw_example_fxpp_ring_mod.cpp
include ${ROOT_DIR}/../../common/daisy-seed/daisy-seed.mk

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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

View File

@ -0,0 +1,6 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fxpp_ring_mod
SOURCE := ${NAME}.cpp
include ${ROOT_DIR}/../../common/ios/ios.mk

View File

@ -0,0 +1,59 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#include "bw_example_fxpp_ring_mod.h"
#include <bw_osc_sin.h>
void bw_example_fxpp_ring_mod_init(bw_example_fxpp_ring_mod *instance) {
(void)instance;
}
void bw_example_fxpp_ring_mod_set_sample_rate(bw_example_fxpp_ring_mod *instance, float sample_rate) {
instance->phaseGen.setSampleRate(sample_rate);
instance->ringMod.setSampleRate(sample_rate);
}
void bw_example_fxpp_ring_mod_reset(bw_example_fxpp_ring_mod *instance) {
instance->phaseGen.reset();
instance->ringMod.reset();
}
void bw_example_fxpp_ring_mod_process(bw_example_fxpp_ring_mod *instance, const float** x, float** y, int n_samples) {
instance->phaseGen.process({}, {y[0]}, {}, n_samples);
oscSinProcess<1>({y[0]}, {y[0]}, n_samples);
instance->ringMod.process({x[0]}, {y[0]}, {y[0]}, n_samples);
}
void bw_example_fxpp_ring_mod_set_parameter(bw_example_fxpp_ring_mod *instance, int index, float value) {
instance->params[index] = value;
switch (index) {
case p_freq:
instance->phaseGen.setFrequency(100.f + (1000.f - 100.f) * value * value * value);
break;
case p_amount:
instance->ringMod.setAmount(-1.f + 2.f * value);
break;
}
}
float bw_example_fxpp_ring_mod_get_parameter(bw_example_fxpp_ring_mod *instance, int index) {
return instance->params[index];
}

View File

@ -0,0 +1,58 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#ifndef _BW_EXAMPLE_FXPP_WAH_H
#define _BW_EXAMPLE_FXPP_WAH_H
#include "platform.h"
#include <bw_ring_mod.h>
#include <bw_phase_gen.h>
using namespace Brickworks;
extern "C" {
enum {
p_freq,
p_amount,
p_n
};
struct _bw_example_fxpp_ring_mod {
// Sub-components
PhaseGen<1> phaseGen;
RingMod<1> ringMod;
// Parameters
float params[p_n];
};
typedef struct _bw_example_fxpp_ring_mod bw_example_fxpp_ring_mod;
void bw_example_fxpp_ring_mod_init(bw_example_fxpp_ring_mod *instance);
void bw_example_fxpp_ring_mod_set_sample_rate(bw_example_fxpp_ring_mod *instance, float sample_rate);
void bw_example_fxpp_ring_mod_reset(bw_example_fxpp_ring_mod *instance);
void bw_example_fxpp_ring_mod_process(bw_example_fxpp_ring_mod *instance, const float** x, float** y, int n_samples);
void bw_example_fxpp_ring_mod_set_parameter(bw_example_fxpp_ring_mod *instance, int index, float value);
float bw_example_fxpp_ring_mod_get_parameter(bw_example_fxpp_ring_mod *instance, int index);
}
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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_fxpp_ring_mod"
#define PLUGIN_VERSION "1.0.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] = {
{ "Frequency", "Freq", "Hz", 0, 0, 0, 0.5f },
{ "Amount", "Amount", "", 0, 0, 0, 1.0f },
};
// Internal API
#include "bw_example_fxpp_ring_mod.h"
#define P_TYPE bw_example_fxpp_ring_mod
#define P_INIT bw_example_fxpp_ring_mod_init
#define P_SET_SAMPLE_RATE bw_example_fxpp_ring_mod_set_sample_rate
#define P_RESET bw_example_fxpp_ring_mod_reset
#define P_PROCESS bw_example_fxpp_ring_mod_process
#define P_SET_PARAMETER bw_example_fxpp_ring_mod_set_parameter
#define P_GET_PARAMETER bw_example_fxpp_ring_mod_get_parameter
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
var buses = [
{
stereo: false,
output: false
},
{
stereo: false,
output: true
}
];
var parameters = [
{
name: "Frequency",
output: false,
defaultValue: 0.5
},
{
name: "Amount",
output: false,
defaultValue: 1.0
}
];

View File

@ -0,0 +1,9 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_fxpp_ring_mod
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fxpp_ring_mod.cpp
include ${ROOT_DIR}/../../common/vst3/vst3.mk
CXXFLAGS += -DRELEASE=1 -DNDEBUG -DBW_NO_DEBUG
#CXXFLAGS += -DDEVELOPMENT=1 -DBW_DEBUG_DEEP

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* File authors: Stefano D'Angelo, Paolo Marrone
*/
#ifndef _VST3_CONFIG_H
#define _VST3_CONFIG_H
#define PLUGIN_SUBCATEGORY "Fx"
#define PLUGIN_GUID_1 0xf4737471
#define PLUGIN_GUID_2 0xb94c4c95
#define PLUGIN_GUID_3 0x8f4091ce
#define PLUGIN_GUID_4 0x5da09fa8
#define CTRL_GUID_1 0x1e8f7e86
#define CTRL_GUID_2 0xc29447c1
#define CTRL_GUID_3 0x91f175ce
#define CTRL_GUID_4 0x220b5635
#endif

View File

@ -39,6 +39,8 @@
* <li>Added overloaded C++ <code>process()</code> function taking
* C-style arrays as arguments.</li>
* <li>Removed usage of reserved identifiers.</li>
* <li>Clearly specified parameter validity ranges.</li>
* <li>Added debugging code.</li>
* </ul>
* </li>
* <li>Version <strong>0.6.0</strong>:
@ -73,44 +75,58 @@ typedef struct bw_dry_wet_coeffs bw_dry_wet_coeffs;
*
* #### bw_dry_wet_init()
* ```>>> */
static inline void bw_dry_wet_init(bw_dry_wet_coeffs *BW_RESTRICT coeffs);
static inline void bw_dry_wet_init(
bw_dry_wet_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Initializes input parameter values in `coeffs`.
*
* #### bw_dry_wet_set_sample_rate()
* ```>>> */
static inline void bw_dry_wet_set_sample_rate(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float sample_rate);
static inline void bw_dry_wet_set_sample_rate(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float sample_rate);
/*! <<<```
* Sets the `sample_rate` (Hz) value in `coeffs`.
*
* #### bw_dry_wet_reset_coeffs()
* ```>>> */
static inline void bw_dry_wet_reset_coeffs(bw_dry_wet_coeffs *BW_RESTRICT coeffs);
static inline void bw_dry_wet_reset_coeffs(
bw_dry_wet_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Resets coefficients in `coeffs` to assume their target values.
*
* #### bw_dry_wet_update_coeffs_ctrl()
* ```>>> */
static inline void bw_dry_wet_update_coeffs_ctrl(bw_dry_wet_coeffs *BW_RESTRICT coeffs);
static inline void bw_dry_wet_update_coeffs_ctrl(
bw_dry_wet_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Triggers control-rate update of coefficients in `coeffs`.
*
* #### bw_dry_wet_update_coeffs_audio()
* ```>>> */
static inline void bw_dry_wet_update_coeffs_audio(bw_dry_wet_coeffs *BW_RESTRICT coeffs);
static inline void bw_dry_wet_update_coeffs_audio(
bw_dry_wet_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Triggers audio-rate update of coefficients in `coeffs`.
*
* #### bw_dry_wet_process1()
* ```>>> */
static inline float bw_dry_wet_process1(const bw_dry_wet_coeffs *BW_RESTRICT coeffs, float x_dry, float x_wet);
static inline float bw_dry_wet_process1(
const bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float x_dry,
float x_wet);
/*! <<<```
* Processes one dry input sample `x_dry` and one wet input sample `x_wet`
* using `coeffs` and returns the corresponding output sample.
*
* #### bw_dry_wet_process()
* ```>>> */
static inline void bw_dry_wet_process(bw_dry_wet_coeffs *BW_RESTRICT coeffs, const float *x_dry, const float *x_wet, float *y, size_t n_samples);
static inline void bw_dry_wet_process(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
const float * x_dry,
const float * x_wet,
float * y,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the dry input buffer `x_dry` and of the
* wet input buffer `x_wet` and fills the first `n_samples` of the output
@ -118,7 +134,13 @@ static inline void bw_dry_wet_process(bw_dry_wet_coeffs *BW_RESTRICT coeffs, con
*
* #### bw_dry_wet_process_multi()
* ```>>> */
static inline void bw_dry_wet_process_multi(bw_dry_wet_coeffs *BW_RESTRICT coeffs, const float * const *x_dry, const float * const *x_wet, float * const *y, size_t n_channels, size_t n_samples);
static inline void bw_dry_wet_process_multi(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
const float * const * x_dry,
const float * const * x_wet,
float * const * y,
size_t n_channels,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the `n_channels` dry input buffers
* `x_dry` and of the `n_channels` wet input buffers `x_wet`, and fills the
@ -127,19 +149,39 @@ static inline void bw_dry_wet_process_multi(bw_dry_wet_coeffs *BW_RESTRICT coeff
*
* #### bw_dry_wet_set_wet()
* ```>>> */
static inline void bw_dry_wet_set_wet(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float value);
static inline void bw_dry_wet_set_wet(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float value);
/*! <<<```
* Sets the wet gain parameter to the given `value` (linear gain) in `coeffs`.
*
* Valid range: [`0.f`, `1.f`].
*
* Default value: `1.f`.
*
* #### bw_dry_wet_set_smooth_tau()
* ```>>> */
static inline void bw_dry_wet_set_smooth_tau(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float value);
static inline void bw_dry_wet_set_smooth_tau(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float value);
/*! <<<```
* Sets the smoothing time constant `value` (s) in `coeffs`.
*
* `value` must be non-negative.
*
* Default value: `0.05f`.
*
* #### bw_dry_wet_coeffs_is_valid()
* ```>>> */
static inline char bw_dry_wet_coeffs_is_valid(
const bw_dry_wet_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Tries to determine whether `coeffs` is valid and returns non-`0` if it
* seems to be the case and `0` if it is certainly not. False positives are
* possible, false negatives are not.
*
* `coeffs` must at least point to a readable memory block of size greater
* than or equal to that of `bw_dry_wet_coeffs`.
* }}} */
#ifdef __cplusplus
@ -157,58 +199,207 @@ static inline void bw_dry_wet_set_smooth_tau(bw_dry_wet_coeffs *BW_RESTRICT coef
extern "C" {
#endif
#ifdef BW_DEBUG_DEEP
enum bw_dry_wet_coeffs_state {
bw_dry_wet_coeffs_state_invalid,
bw_dry_wet_coeffs_state_init,
bw_dry_wet_coeffs_state_set_sample_rate,
bw_dry_wet_coeffs_state_reset_coeffs
};
#endif
struct bw_dry_wet_coeffs {
#ifdef BW_DEBUG_DEEP
uint32_t hash;
enum bw_dry_wet_coeffs_state state;
#endif
// Sub-components
bw_gain_coeffs gain_coeffs;
bw_gain_coeffs gain_coeffs;
};
static inline void bw_dry_wet_init(bw_dry_wet_coeffs *BW_RESTRICT coeffs) {
static inline void bw_dry_wet_init(
bw_dry_wet_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
bw_gain_init(&coeffs->gain_coeffs);
#ifdef BW_DEBUG_DEEP
coeffs->hash = bw_hash_sdbm("bw_dry_wet_coeffs");
coeffs->state = bw_dry_wet_coeffs_state_init;
#endif
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_dry_wet_coeffs_state_init);
}
static inline void bw_dry_wet_set_sample_rate(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float sample_rate) {
static inline void bw_dry_wet_set_sample_rate(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float sample_rate) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_init);
BW_ASSERT(bw_is_finite(sample_rate) && sample_rate > 0.f);
bw_gain_set_sample_rate(&coeffs->gain_coeffs, sample_rate);
#ifdef BW_DEBUG_DEEP
coeffs->state = bw_dry_wet_coeffs_state_set_sample_rate;
#endif
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_dry_wet_coeffs_state_set_sample_rate);
}
static inline void bw_dry_wet_reset_coeffs(bw_dry_wet_coeffs *BW_RESTRICT coeffs) {
static inline void bw_dry_wet_reset_coeffs(
bw_dry_wet_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_set_sample_rate);
bw_gain_reset_coeffs(&coeffs->gain_coeffs);
#ifdef BW_DEBUG_DEEP
coeffs->state = bw_dry_wet_coeffs_state_reset_coeffs;
#endif
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_dry_wet_coeffs_state_reset_coeffs);
}
static inline void bw_dry_wet_update_coeffs_ctrl(bw_dry_wet_coeffs *BW_RESTRICT coeffs) {
static inline void bw_dry_wet_update_coeffs_ctrl(
bw_dry_wet_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
bw_gain_update_coeffs_ctrl(&coeffs->gain_coeffs);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
}
static inline void bw_dry_wet_update_coeffs_audio(bw_dry_wet_coeffs *BW_RESTRICT coeffs) {
static inline void bw_dry_wet_update_coeffs_audio(
bw_dry_wet_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
bw_gain_update_coeffs_audio(&coeffs->gain_coeffs);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
}
static inline float bw_dry_wet_process1(const bw_dry_wet_coeffs *BW_RESTRICT coeffs, float x_dry, float x_wet) {
return bw_gain_process1(&coeffs->gain_coeffs, x_wet - x_dry) + x_dry;
static inline float bw_dry_wet_process1(
const bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float x_dry,
float x_wet) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
BW_ASSERT(bw_is_finite(x_dry));
BW_ASSERT(bw_is_finite(x_wet));
const float y = bw_gain_process1(&coeffs->gain_coeffs, x_wet - x_dry) + x_dry;
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
BW_ASSERT(bw_is_finite(*y));
return y;
}
static inline void bw_dry_wet_process(bw_dry_wet_coeffs *BW_RESTRICT coeffs, const float *x_dry, const float *x_wet, float *y, size_t n_samples) {
static inline void bw_dry_wet_process(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
const float * x_dry,
const float * x_wet,
float * y,
size_t n_samples) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
BW_ASSERT(x_dry != NULL);
BW_ASSERT_DEEP(bw_has_only_finite(x_dry, n_samples));
BW_ASSERT(x_wet != NULL);
BW_ASSERT_DEEP(bw_has_only_finite(x_wet, n_samples));
BW_ASSERT(y != NULL);
bw_dry_wet_update_coeffs_ctrl(coeffs);
for (size_t i = 0; i < n_samples; i++) {
bw_dry_wet_update_coeffs_audio(coeffs);
y[i] = bw_dry_wet_process1(coeffs, x_dry[i], x_wet[i]);
}
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
BW_ASSERT_DEEP(bw_has_only_finite(y, n_samples));
}
static inline void bw_dry_wet_process_multi(bw_dry_wet_coeffs *BW_RESTRICT coeffs, const float * const *x_dry, const float * const *x_wet, float * const *y, size_t n_channels, size_t n_samples) {
static inline void bw_dry_wet_process_multi(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
const float * const * x_dry,
const float * const * x_wet,
float * const * y,
size_t n_channels,
size_t n_samples) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
BW_ASSERT(x_dry != NULL);
BW_ASSERT(x_wet != NULL);
BW_ASSERT(y != NULL);
bw_dry_wet_update_coeffs_ctrl(coeffs);
for (size_t i = 0; i < n_samples; i++) {
bw_dry_wet_update_coeffs_audio(coeffs);
for (size_t j = 0; j < n_channels; j++)
y[j][i] = bw_dry_wet_process1(coeffs, x_dry[j][i], x_wet[j][i]);
}
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_reset_coeffs);
}
static inline void bw_dry_wet_set_wet(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float value) {
static inline void bw_dry_wet_set_wet(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float value) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_init);
BW_ASSERT(bw_is_finite(value));
BW_ASSERT(value >= 0.f && value <= 1.f);
bw_gain_set_gain_lin(&coeffs->gain_coeffs, value);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_init);
}
static inline void bw_dry_wet_set_smooth_tau(bw_dry_wet_coeffs *BW_RESTRICT coeffs, float value) {
static inline void bw_dry_wet_set_smooth_tau(
bw_dry_wet_coeffs * BW_RESTRICT coeffs,
float value) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_init);
BW_ASSERT(bw_is_finite(value));
BW_ASSERT(value >= 0.f);
bw_gain_set_smooth_tau(&coeffs->gain_coeffs, value);
BW_ASSERT_DEEP(bw_dry_wet_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_dry_wet_coeffs_state_init);
}
static inline char bw_dry_wet_coeffs_is_valid(
const bw_dry_wet_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
#ifdef BW_DEBUG_DEEP
if (coeffs->hash != bw_hash_sdbm("bw_dry_wet_coeffs"))
return 0;
if (coeffs->state < bw_dry_wet_coeffs_state_init || coeffs->state > bw_dry_wet_coeffs_state_reset_coeffs)
return 0;
#endif
return bw_gain_coeffs_is_valid(&coeffs->gain_coeffs);
}
#ifdef __cplusplus
@ -241,8 +432,28 @@ public:
std::array<float *, N_CHANNELS> y,
size_t nSamples);
void setWet(float value);
void setSmoothTau(float value);
void setSampleRate(
float sampleRate);
void reset();
void process(
const float * const * xDry,
const float * const * xWet,
float * const * y,
size_t nSamples);
void process(
std::array<const float *, N_CHANNELS> xDry,
std::array<const float *, N_CHANNELS> xWet,
std::array<float *, N_CHANNELS> y,
size_t nSamples);
void setWet(
float value);
void setSmoothTau(
float value);
/*! <<<...
* }
* ```
@ -254,7 +465,7 @@ public:
* change at any time in future versions. Please, do not use it directly. */
private:
bw_dry_wet_coeffs coeffs;
bw_dry_wet_coeffs coeffs;
};
template<size_t N_CHANNELS>
@ -263,7 +474,8 @@ inline DryWet<N_CHANNELS>::DryWet() {
}
template<size_t N_CHANNELS>
inline void DryWet<N_CHANNELS>::setSampleRate(float sampleRate) {
inline void DryWet<N_CHANNELS>::setSampleRate(
float sampleRate) {
bw_dry_wet_set_sample_rate(&coeffs, sampleRate);
}
@ -274,29 +486,31 @@ inline void DryWet<N_CHANNELS>::reset() {
template<size_t N_CHANNELS>
inline void DryWet<N_CHANNELS>::process(
const float * const *x_dry,
const float * const *x_wet,
float * const *y,
size_t nSamples) {
bw_dry_wet_process_multi(&coeffs, x_dry, x_wet, y, N_CHANNELS, nSamples);
const float * const * xDry,
const float * const * xWet,
float * const * y,
size_t nSamples) {
bw_dry_wet_process_multi(&coeffs, xDry, xWet, y, N_CHANNELS, nSamples);
}
template<size_t N_CHANNELS>
inline void DryWet<N_CHANNELS>::process(
std::array<const float *, N_CHANNELS> x_dry,
std::array<const float *, N_CHANNELS> x_wet,
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
process(x_dry.data(), x_wet.data(), y.data(), nSamples);
std::array<const float *, N_CHANNELS> xDry,
std::array<const float *, N_CHANNELS> xWet,
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
process(xDry.data(), xWet.data(), y.data(), nSamples);
}
template<size_t N_CHANNELS>
inline void DryWet<N_CHANNELS>::setWet(float value) {
inline void DryWet<N_CHANNELS>::setWet(
float value) {
bw_dry_wet_set_wet(&coeffs, value);
}
template<size_t N_CHANNELS>
inline void DryWet<N_CHANNELS>::setSmoothTau(float value) {
inline void DryWet<N_CHANNELS>::setSmoothTau(
float value) {
bw_dry_wet_set_smooth_tau(&coeffs, value);
}

View File

@ -131,7 +131,7 @@ static inline void bw_osc_pulse_update_coeffs_audio(bw_osc_pulse_coeffs *BW_REST
static inline float bw_osc_pulse_process1(const bw_osc_pulse_coeffs *BW_RESTRICT coeffs, float x);
static inline float bw_osc_pulse_process1_antialias(const bw_osc_pulse_coeffs *BW_RESTRICT coeffs, float x, float x_phase_inc);
/*! <<<```
* These function process one input sample `x`, indicating the normalized
* These function process one input sample `x`, representing the normalized
* phase, using `coeffs`. They return the corresponding output sample.
*
* In particular:

View File

@ -106,7 +106,7 @@ static inline void bw_osc_saw_init(bw_osc_saw_coeffs *BW_RESTRICT coeffs);
static inline float bw_osc_saw_process1(const bw_osc_saw_coeffs *BW_RESTRICT coeffs, float x);
static inline float bw_osc_saw_process1_antialias(const bw_osc_saw_coeffs *BW_RESTRICT coeffs, float x, float x_phase_inc);
/*! <<<```
* These function process one input sample `x`, indicating the normalized
* These function process one input sample `x`, representing the normalized
* phase, using `coeffs`. They return the corresponding output sample.
*
* In particular:

View File

@ -41,6 +41,7 @@
* <li>Added overloaded C++ <code>oscSinProcess()</code> function taking
* C-style arrays as arguments.</li>
* <li>Removed usage of reserved identifiers.</li>
* <li>Added debugging code.</li>
* </ul>
* </li>
* <li>Version <strong>0.6.0</strong>:
@ -80,15 +81,18 @@ extern "C" {
/*! api {{{
* #### bw_osc_sin_process1()
* ```>>> */
static inline float bw_osc_sin_process1(float x);
static inline float bw_osc_sin_process1(
float x);
/*! <<<```
* Processes one input sample `x`, indicating the normalized phase, and
* returns the corresponding output
* sample.
* Processes one input sample `x`, representing the normalized phase, and
* returns the corresponding output sample.
*
* #### bw_osc_sin_process()
* ```>>> */
static inline void bw_osc_sin_process(const float *x, float *y, size_t n_samples);
static inline void bw_osc_sin_process(
const float * x,
float * y,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the input buffer `x`, containing the
* normalized phase signal, and fills the first `n_samples` of the output
@ -96,7 +100,11 @@ static inline void bw_osc_sin_process(const float *x, float *y, size_t n_samples
*
* #### bw_osc_sin_process_multi()
* ```>>> */
static inline void bw_osc_sin_process_multi(const float * const *x, float * const *y, size_t n_channels, size_t n_samples);
static inline void bw_osc_sin_process_multi(
const float * const * x,
float * const * y,
size_t n_channels,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the `n_channels` input buffers `x`,
* containing the normalized phase signals, and fills the first `n_samples`
@ -118,16 +126,39 @@ static inline void bw_osc_sin_process_multi(const float * const *x, float * cons
extern "C" {
#endif
static inline float bw_osc_sin_process1(float x) {
return bw_sin2pif(x);
static inline float bw_osc_sin_process1(
float x) {
BW_ASSERT(bw_is_finite(x));
const float y = bw_sin2pif(x);
BW_ASSERT(bw_is_finite(y));
return y;
}
static inline void bw_osc_sin_process(const float *x, float *y, size_t n_samples) {
static inline void bw_osc_sin_process(
const float * x,
float * y,
size_t n_samples) {
BW_ASSERT(x != NULL);
BW_ASSERT_DEEP(bw_has_only_finite(x, n_samples));
BW_ASSERT(y != NULL);
for (size_t i = 0; i < n_samples; i++)
y[i] = bw_osc_sin_process1(x[i]);
BW_ASSERT_DEEP(bw_has_only_finite(y, n_samples));
}
static inline void bw_osc_sin_process_multi(const float * const *x, float * const *y, size_t n_channels, size_t n_samples) {
static inline void bw_osc_sin_process_multi(
const float * const * x,
float * const * y,
size_t n_channels,
size_t n_samples) {
BW_ASSERT(x != NULL);
BW_ASSERT(y != NULL);
for (size_t i = 0; i < n_channels; i++)
bw_osc_sin_process(x[i], y[i], n_samples);
}
@ -146,15 +177,15 @@ namespace Brickworks {
* ```>>> */
template<size_t N_CHANNELS>
void oscSinProcess(
const float * const *x,
float * const *y,
size_t nSamples);
const float * const * x,
float * const * y,
size_t nSamples);
template<size_t N_CHANNELS>
void oscSinProcess(
std::array<const float *, N_CHANNELS> x,
std::array<float *, N_CHANNELS> y,
size_t nSamples);
std::array<float *, N_CHANNELS> y,
size_t nSamples);
/*! <<<```
* }}} */
@ -165,17 +196,17 @@ void oscSinProcess(
template<size_t N_CHANNELS>
inline void oscSinProcess(
const float * const *x,
float * const *y,
size_t nSamples) {
const float * const * x,
float * const * y,
size_t nSamples) {
bw_osc_sin_process_multi(x, y, N_CHANNELS, nSamples);
}
template<size_t N_CHANNELS>
inline void oscSinProcess(
std::array<const float *, N_CHANNELS> x,
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
oscSinProcess<N_CHANNELS>(x.data(), y.data(), nSamples);
}

View File

@ -133,7 +133,7 @@ static inline void bw_osc_tri_update_coeffs_audio(bw_osc_tri_coeffs *BW_RESTRICT
static inline float bw_osc_tri_process1(const bw_osc_tri_coeffs *BW_RESTRICT coeffs, float x);
static inline float bw_osc_tri_process1_antialias(const bw_osc_tri_coeffs *BW_RESTRICT coeffs, float x, float x_phase_inc);
/*! <<<```
* These function process one input sample `x`, indicating the normalized
* These function process one input sample `x`, representing the normalized
* phase, using `coeffs`. They return the corresponding output sample.
*
* In particular:

View File

@ -39,6 +39,9 @@
* <li>Added overloaded C++ <code>process()</code> function taking
* C-style arrays as arguments.</li>
* <li>Removed usage of reserved identifiers.</li>
* <li>Fixed inverted-polarity modulation (for real this time).</li>
* <li>Clearly specified parameter validity ranges.</li>
* <li>Added debugging code.</li>
* </ul>
* </li>
* <li>Version <strong>0.6.0</strong>:
@ -81,44 +84,58 @@ typedef struct bw_ring_mod_coeffs bw_ring_mod_coeffs;
*
* #### bw_ring_mod_init()
* ```>>> */
static inline void bw_ring_mod_init(bw_ring_mod_coeffs *BW_RESTRICT coeffs);
static inline void bw_ring_mod_init(
bw_ring_mod_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Initializes input parameter values in `coeffs`.
*
* #### bw_ring_mod_set_sample_rate()
* ```>>> */
static inline void bw_ring_mod_set_sample_rate(bw_ring_mod_coeffs *BW_RESTRICT coeffs, float sample_rate);
static inline void bw_ring_mod_set_sample_rate(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
float sample_rate);
/*! <<<```
* Sets the `sample_rate` (Hz) value in `coeffs`.
*
* #### bw_ring_mod_reset_coeffs()
* ```>>> */
static inline void bw_ring_mod_reset_coeffs(bw_ring_mod_coeffs *BW_RESTRICT coeffs);
static inline void bw_ring_mod_reset_coeffs(
bw_ring_mod_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Resets coefficients in `coeffs` to assume their target values.
*
* #### bw_ring_mod_update_coeffs_ctrl()
* ```>>> */
static inline void bw_ring_mod_update_coeffs_ctrl(bw_ring_mod_coeffs *BW_RESTRICT coeffs);
static inline void bw_ring_mod_update_coeffs_ctrl(
bw_ring_mod_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Triggers control-rate update of coefficients in `coeffs`.
*
* #### bw_ring_mod_update_coeffs_audio()
* ```>>> */
static inline void bw_ring_mod_update_coeffs_audio(bw_ring_mod_coeffs *BW_RESTRICT coeffs);
static inline void bw_ring_mod_update_coeffs_audio(
bw_ring_mod_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Triggers audio-rate update of coefficients in `coeffs`.
*
* #### bw_ring_mod_process1()
* ```>>> */
static inline float bw_ring_mod_process1(const bw_ring_mod_coeffs *BW_RESTRICT coeffs, float x_mod, float x_car);
static inline float bw_ring_mod_process1(
const bw_ring_mod_coeffs * BW_RESTRICT coeffs,
float x_mod,
float x_car);
/*! <<<```
* Processes one modulation input sample `x_mod` and one carrier input sample
* `x_car` using `coeffs` and returns the corresponding output sample.
*
* #### bw_ring_mod_process()
* ```>>> */
static inline void bw_ring_mod_process(bw_ring_mod_coeffs *BW_RESTRICT coeffs, const float *x_mod, const float *x_car, float *y, size_t n_samples);
static inline void bw_ring_mod_process(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
const float * x_mod,
const float * x_car,
float * y,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the modulation input buffer `x_mod` and
* of the carrier input buffer `x_car` and fills the first `n_samples` of the
@ -127,7 +144,13 @@ static inline void bw_ring_mod_process(bw_ring_mod_coeffs *BW_RESTRICT coeffs, c
*
* #### bw_ring_mod_process_multi()
* ```>>> */
static inline void bw_ring_mod_process_multi(bw_ring_mod_coeffs *BW_RESTRICT coeffs, const float * const *x_mod, const float * const *x_car, float * const *y, size_t n_channels, size_t n_samples);
static inline void bw_ring_mod_process_multi(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
const float * const * x_mod,
const float * const * x_car,
float * const * y,
size_t n_channels,
size_t n_samples);
/*! <<<```
* Processes the first `n_samples` of the `n_channels` modulation input
* buffers `x_mod` and of the `n_channels` carrier input buffers `x_car`, and
@ -136,13 +159,30 @@ static inline void bw_ring_mod_process_multi(bw_ring_mod_coeffs *BW_RESTRICT coe
*
* #### bw_ring_mod_set_amount()
* ```>>> */
static inline void bw_ring_mod_set_amount(bw_ring_mod_coeffs *BW_RESTRICT coeffs, float value);
static inline void bw_ring_mod_set_amount(
bw_ring_mod_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
* inverted polarity) in `coeffs`.
*
* Valid range: [`-1.f` (full modulation with inverted polarity),
* `1.f` (full modulation)].
*
* Default value: `1.f`.
*
* #### bw_ring_mod_coeffs_is_valid()
* ```>>> */
static inline char bw_ring_mod_coeffs_is_valid(
const bw_ring_mod_coeffs * BW_RESTRICT coeffs);
/*! <<<```
* Tries to determine whether `coeffs` is valid and returns non-`0` if it
* seems to be the case and `0` if it is certainly not. False positives are
* possible, false negatives are not.
*
* `coeffs` must at least point to a readable memory block of size greater
* than or equal to that of `bw_ring_mod_coeffs`.
* }}} */
#ifdef __cplusplus
@ -161,60 +201,206 @@ static inline void bw_ring_mod_set_amount(bw_ring_mod_coeffs *BW_RESTRICT coeffs
extern "C" {
#endif
#ifdef BW_DEBUG_DEEP
enum bw_ring_mod_coeffs_state {
bw_ring_mod_coeffs_state_invalid,
bw_ring_mod_coeffs_state_init,
bw_ring_mod_coeffs_state_set_sample_rate,
bw_ring_mod_coeffs_state_reset_coeffs
};
#endif
struct bw_ring_mod_coeffs {
#ifdef BW_DEBUG_DEEP
uint32_t hash;
enum bw_ring_mod_coeffs_state state;
#endif
// Sub-components
bw_one_pole_coeffs smooth_coeffs;
bw_one_pole_state smooth_state;
bw_one_pole_coeffs smooth_coeffs;
bw_one_pole_state smooth_state;
// Parameters
float mod_amount;
float mod_amount;
};
static inline void bw_ring_mod_init(bw_ring_mod_coeffs *BW_RESTRICT coeffs) {
static inline void bw_ring_mod_init(
bw_ring_mod_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
bw_one_pole_init(&coeffs->smooth_coeffs);
bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f);
coeffs->mod_amount = 1.f;
#ifdef BW_DEBUG_DEEP
coeffs->hash = bw_hash_sdbm("bw_ring_mod_coeffs");
coeffs->state = bw_ring_mod_coeffs_state_init;
#endif
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_ring_mod_coeffs_state_init);
}
static inline void bw_ring_mod_set_sample_rate(bw_ring_mod_coeffs *BW_RESTRICT coeffs, float sample_rate) {
static inline void bw_ring_mod_set_sample_rate(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
float sample_rate) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_init);
BW_ASSERT(bw_is_finite(sample_rate) && sample_rate > 0.f);
bw_one_pole_set_sample_rate(&coeffs->smooth_coeffs, sample_rate);
bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs);
#ifdef BW_DEBUG_DEEP
coeffs->state = bw_ring_mod_coeffs_state_set_sample_rate;
#endif
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_ring_mod_coeffs_state_set_sample_rate);
}
static inline void bw_ring_mod_reset_coeffs(bw_ring_mod_coeffs *BW_RESTRICT coeffs) {
static inline void bw_ring_mod_reset_coeffs(
bw_ring_mod_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_set_sample_rate);
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->mod_amount);
#ifdef BW_DEBUG_DEEP
coeffs->state = bw_ring_mod_coeffs_state_reset_coeffs;
#endif
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state == bw_ring_mod_coeffs_state_reset_coeffs);
}
static inline void bw_ring_mod_update_coeffs_ctrl(bw_ring_mod_coeffs *BW_RESTRICT coeffs) {
static inline void bw_ring_mod_update_coeffs_ctrl(
bw_ring_mod_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
(void)coeffs;
}
static inline void bw_ring_mod_update_coeffs_audio(bw_ring_mod_coeffs *BW_RESTRICT coeffs) {
static inline void bw_ring_mod_update_coeffs_audio(
bw_ring_mod_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->mod_amount);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
}
static inline float bw_ring_mod_process1(const bw_ring_mod_coeffs *BW_RESTRICT coeffs, float x_mod, float x_car) {
static inline float bw_ring_mod_process1(
const bw_ring_mod_coeffs * BW_RESTRICT coeffs,
float x_mod,
float x_car) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
BW_ASSERT(bw_is_finite(x_mod));
BW_ASSERT(bw_is_finite(x_car));
const float k = bw_one_pole_get_y_z1(&coeffs->smooth_state);
return k * x_car * x_mod + bw_absf(1.f - k) * x_mod;
const float y = (k * x_car - bw_absf(k)) * x_mod + x_mod;
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
BW_ASSERT(bw_is_finite(y));
return y;
}
static inline void bw_ring_mod_process(bw_ring_mod_coeffs *BW_RESTRICT coeffs, const float *x_mod, const float *x_car, float *y, size_t n_samples) {
static inline void bw_ring_mod_process(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
const float * x_mod,
const float * x_car,
float * y,
size_t n_samples) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
BW_ASSERT(x_mod != NULL);
BW_ASSERT_DEEP(bw_has_only_finite(x_mod, n_samples));
BW_ASSERT(x_car != NULL);
BW_ASSERT_DEEP(bw_has_only_finite(x_car, n_samples));
BW_ASSERT(y != NULL);
for (size_t i = 0; i < n_samples; i++) {
bw_ring_mod_update_coeffs_audio(coeffs);
y[i] = bw_ring_mod_process1(coeffs, x_mod[i], x_car[i]);
}
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
BW_ASSERT_DEEP(bw_has_only_finite(y, n_samples));
}
static inline void bw_ring_mod_process_multi(bw_ring_mod_coeffs *BW_RESTRICT coeffs, const float * const *x_mod, const float * const *x_car, float * const *y, size_t n_channels, size_t n_samples) {
static inline void bw_ring_mod_process_multi(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
const float * const * x_mod,
const float * const * x_car,
float * const * y,
size_t n_channels,
size_t n_samples) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
BW_ASSERT(x_mod != NULL);
BW_ASSERT(x_car != NULL);
BW_ASSERT(y != NULL);
for (size_t i = 0; i < n_samples; i++) {
bw_ring_mod_update_coeffs_audio(coeffs);
for (size_t j = 0; j < n_channels; j++)
y[j][i] = bw_ring_mod_process1(coeffs, x_mod[j][i], x_car[j][i]);
}
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs);
}
static inline void bw_ring_mod_set_amount(bw_ring_mod_coeffs *BW_RESTRICT coeffs, float value) {
static inline void bw_ring_mod_set_amount(
bw_ring_mod_coeffs * BW_RESTRICT coeffs,
float value) {
BW_ASSERT(coeffs != NULL);
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_init);
BW_ASSERT(bw_is_finite(value));
BW_ASSERT(value >= -1.f && value <= 1.f);
coeffs->mod_amount = value;
BW_ASSERT_DEEP(bw_ring_mod_coeffs_is_valid(coeffs));
BW_ASSERT_DEEP(coeffs->state >= bw_ring_mod_coeffs_state_init);
}
static inline char bw_ring_mod_coeffs_is_valid(
const bw_ring_mod_coeffs * BW_RESTRICT coeffs) {
BW_ASSERT(coeffs != NULL);
#ifdef BW_DEBUG_DEEP
if (coeffs->hash != bw_hash_sdbm("bw_ring_mod_coeffs"))
return 0;
if (coeffs->state < bw_ring_mod_coeffs_state_init || coeffs->state > bw_ring_mod_coeffs_state_reset_coeffs)
return 0;
#endif
if (!bw_is_finite(coeffs->mod_amount) || coeffs->mod_amount < -1.f || coeffs->mod_amount > 1.f)
return 0;
if (!bw_one_pole_coeffs_is_valid(&coeffs->smooth_coeffs))
return 0;
#ifdef BW_DEBUG_DEEP
if (coeffs->state >= bw_ring_mod_coeffs_state_reset_coeffs && !bw_one_pole_state_is_valid(&coeffs->smooth_coeffs, &coeffs->smooth_state))
return 0;
#endif
return 1;
}
#ifdef __cplusplus
@ -234,18 +420,22 @@ class RingMod {
public:
RingMod();
void setSampleRate(float sampleRate);
void setSampleRate(
float sampleRate);
void reset();
void process(
const float * const *x_mod,
const float * const *x_car,
float * const *y,
size_t nSamples);
const float * const * xMod,
const float * const * xCar,
float * const * y,
size_t nSamples);
void process(
std::array<const float *, N_CHANNELS> x_mod,
std::array<const float *, N_CHANNELS> x_car,
std::array<float *, N_CHANNELS> y,
size_t nSamples);
std::array<const float *, N_CHANNELS> xMod,
std::array<const float *, N_CHANNELS> xCar,
std::array<float *, N_CHANNELS> y,
size_t nSamples);
void setAmount(float value);
/*! <<<...
@ -259,7 +449,7 @@ public:
* change at any time in future versions. Please, do not use it directly. */
private:
bw_ring_mod_coeffs coeffs;
bw_ring_mod_coeffs coeffs;
};
template<size_t N_CHANNELS>
@ -268,7 +458,8 @@ inline RingMod<N_CHANNELS>::RingMod() {
}
template<size_t N_CHANNELS>
inline void RingMod<N_CHANNELS>::setSampleRate(float sampleRate) {
inline void RingMod<N_CHANNELS>::setSampleRate(
float sampleRate) {
bw_ring_mod_set_sample_rate(&coeffs, sampleRate);
}
@ -279,24 +470,25 @@ inline void RingMod<N_CHANNELS>::reset() {
template<size_t N_CHANNELS>
inline void RingMod<N_CHANNELS>::process(
const float * const *x_mod,
const float * const *x_car,
float * const *y,
size_t nSamples) {
bw_ring_mod_process_multi(&coeffs, x_mod, x_car, y, N_CHANNELS, nSamples);
const float * const * xMod,
const float * const * xCar,
float * const * y,
size_t nSamples) {
bw_ring_mod_process_multi(&coeffs, xMod, xCar, y, N_CHANNELS, nSamples);
}
template<size_t N_CHANNELS>
inline void RingMod<N_CHANNELS>::process(
std::array<const float *, N_CHANNELS> x_mod,
std::array<const float *, N_CHANNELS> x_car,
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
process(x_mod.data(), x_car.data(), y.data(), nSamples);
std::array<const float *, N_CHANNELS> xMod,
std::array<const float *, N_CHANNELS> xCar,
std::array<float *, N_CHANNELS> y,
size_t nSamples) {
process(xMod.data(), xCar.data(), y.data(), nSamples);
}
template<size_t N_CHANNELS>
inline void RingMod<N_CHANNELS>::setAmount(float value) {
inline void RingMod<N_CHANNELS>::setAmount(
float value) {
bw_ring_mod_set_amount(&coeffs, value);
}