Advanced version of bw_phase_gen with hard sync and swing.
In addition to the usual phase and phase increment signals, this module introduces 3 hard sync-specific signals, namely:
char, which is non-0 when a hard sync event occurs between the beginning of the current sample (included) and the beginning of the next samples (excluded);float, which reports an estimate of the time distance, as number of samples, between the last hard sync event and the beginning of the current sample -- valid range: [0.f, INFINITY];float, which reports an estimate of the time distance, as number of samples, between the beginning of the current sample and the next hard sync event -- valid range: (0.f, INFINITY].The presence of a "hard sync do" signal, which is always optional, implicitly indicates whether a phase generator is a hard sync master (has hard sync output), slave (has hard sync input), both, or none. A set of hard sync signals must always contain all 3 signals.
Requires:
We can privately hand you one or more example plugins if you are interested.
Module type: DSP
typedef struct bwp_phase_gen_coeffs bwp_phase_gen_coeffs;
Coefficients and related.
typedef struct bwp_phase_gen_state bwp_phase_gen_state;
Internal state and related.
static inline void bwp_phase_gen_init(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs);
Initializes input parameter values in coeffs.
static inline void bwp_phase_gen_set_sample_rate(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float sample_rate);
Sets the sample_rate (Hz) value in coeffs.
static inline void bwp_phase_gen_reset_coeffs(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs);
Resets coefficients in coeffs to assume their target values.
static inline void bwp_phase_gen_reset_state(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float phase_0,
char is_slave,
float x_sync_low_0,
float x_sync_high_0,
float * BW_RESTRICT y_0,
float * BW_RESTRICT y_inc_0,
float * BW_RESTRICT y_sync_low_0,
float * BW_RESTRICT y_sync_high_0);
Resets the given state to its initial values using the given coeffs and the initial phase value phase_0, an is_slave flag indicating whether the phase generator is a hard sync slave, and x_sync_low_0 and x_sync_high_0 input hard sync signal initial values.
The corresponding initial output and phase increment values are put into y_0 and y_inc_0 respectively, while y_sync_low_0 and y_sync_high_0 will be filled with output hard sync signal initial values, regardless of whether the phase generator is a hard sync master or not.
phase_0 must be in [0.f, 1.f).
If is_slave is 0 then x_sync_low_0 and x_sync_high_0 are ignored.
static inline void bwp_phase_gen_reset_state_multi(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT const * BW_RESTRICT state,
const float * phase_0,
const char * BW_RESTRICT is_slave,
const float * x_sync_low_0,
const float * x_sync_high_0,
float * y_0,
float * y_inc_0,
float * y_sync_low_0,
float * y_sync_high_0,
size_t n_channels);
Resets each of the n_channels states to its initial values using the given coeffs and the corresponding initial phase value in the phase_0 array, flag indicating whether the phase generator is a hard sync slave in the is_slave array, and input hard sync signal initial values in the x_sync_low_0 and x_sync_high_0 arrays.
The corresponding initial output and phase increment values are put into the y_0 and y_inc_0 arrays, respectively, if they are not BW_NULL. The same goes with y_sync_low_0 and y_sync_high_0 which will be filled with output hard sync signal initial values, regardless of whether the phase generators are hard sync master or not, unless they are BW_NULL. y_sync_low_0 must be either both BW_NULL or both not BW_NULL.
Values in phase_0 must be in [0.f, 1.f).
is_slave may be BW_NULL, in which case x_sync_low_0 and x_sync_high_0 are ignored. Otherwise, if any element in is_slave is non-0, then both x_sync_low_0 and x_sync_high_0 are required to be not BW_NULL. Furthermore, if is_slave[i] is 0 then x_sync_low_0[i] and x_sync_high_0[i] are ignored.
static inline void bwp_phase_gen_update_coeffs_ctrl(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs);
Triggers control-rate update of coefficients in coeffs.
static inline void bwp_phase_gen_update_coeffs_audio(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs);
Triggers audio-rate update of coefficients in coeffs.
static inline void bwp_phase_gen_process1(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_mod(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_slave(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_slave_mod(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_master(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_mod(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_slave(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_slave_mod(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_mod_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_slave_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_slave_mod_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc);
static inline void bwp_phase_gen_process1_master_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_mod_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_slave_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
static inline void bwp_phase_gen_process1_master_slave_mod_swing(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float x_mod,
char x_sync_do,
float x_sync_low,
float x_sync_high,
float * BW_RESTRICT y,
float * BW_RESTRICT y_inc,
char * BW_RESTRICT y_sync_do,
float * BW_RESTRICT y_sync_low,
float * BW_RESTRICT y_sync_high);
These functions generate one output sample using coeffs, while using and updating state, putting its value in y and the corresponding phase increment value in y_inc.
In particular:
bwp_phase_gen_process1() does not apply frequency modulation, with the phase generator operating neither as hard sync slave nor master;bwp_phase_gen_process1_mod() applies exponential frequency modulation using x_mod as modulation input, with the phase generator operating neither as hard sync slave nor master;bwp_phase_gen_process1_slave() does not apply frequency modulation, with the phase generator operating as hard sync slave but not master, where x_sync_do, x_sync_low, and x_sync_high are the input hard sync signals;bwp_phase_gen_process1_slave_mod() is like bwp_phase_gen_process1_slave() but applying exponential frequency modulation using x_mod as modulation input;bwp_phase_gen_process1_master() does not apply frequency modulation, with the phase generator operating as hard sync master but not slave, where y_sync_do, y_sync_low, and y_sync_high are the output hard sync signals;bwp_phase_gen_process1_master_mod() is like bwp_phase_gen_process1_master() but applying exponential frequency modulation using x_mod as modulation input;bwp_phase_gen_process1_master_slave() does not apply frequency modulation, with the phase generator operating both as hard sync master and slave, x_sync_do, x_sync_low, and x_sync_high are the input hard sync signals, and y_sync_do, y_sync_low, and y_sync_high are the output hard sync signals;bwp_phase_gen_process1_master_slave_mod() is like bwp_phase_gen_process1_master_slave() but applying exponential frequency modulation using x_mod as modulation input.The functions above assume that swing is set at 50%, while the *_swing() variants do take swing into account, but are computationally heavier.
The modulation scale for x_mod is 1.f/octave.
x_sync_low and x_sync_high are ignored if x_sync_do is 0.
static inline void bwp_phase_gen_process(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
const float * x_mod,
const char * x_sync_do,
const float * x_sync_low,
const float * x_sync_high,
float * y,
float * y_inc,
char * y_sync_do,
float * y_sync_low,
float * y_sync_high,
size_t n_samples);
Generates and fills the first n_samples of the output buffer y, while using and updating both coeffs and state (control and audio rate).
If x_mod is not BW_NULL, it is used as a source of exponential frequency modulation (scale 1.f/octave).
If x_sync_do is not BW_NULL, x_sync_low and x_sync_high must point to different buffers. These buffers represent input hard sync signals.
If y_inc is not BW_NULL, it is filled with phase increment values.
If y_sync_do is not BW_NULL, y_sync_low and y_sync_high must not be BW_NULL either. These buffers will be filled with output hard sync signals.
static inline void bwp_phase_gen_process_multi(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT const * BW_RESTRICT state,
const float * const * x_mod,
const char * const * x_sync_do,
const float * const * x_sync_low,
const float * const * x_sync_high,
float * const * y,
float * const * y_inc,
char * const * y_sync_do,
float * const * y_sync_low,
float * const * y_sync_high,
size_t n_channels,
size_t n_samples);
Generates and fills the first n_samples of the n_channels output buffers y, while using and updating both the common coeffs and each of the n_channels states (control and audio rate).
If x_mod and the channel-specific element are not BW_NULL, this is used as a source of exponential frequency modulation (scale 1.f/octave) for that channel.
If x_sync_do is not BW_NULL, x_sync_low and x_sync_high must point to different arrays. Then, if x_sync_do[i] is not BW_NULL, x_sync_low[i] and x_sync_high[i] must point to different buffers. These buffers represent input hard sync signals.
If y_inc and the channel-specific element are not BW_NULL, this is filled with phase increment values for that channel.
If y_sync_do is not BW_NULL, y_sync_low and y_sync_high must point to different arrays. Then, if y_sync_do[i] is not BW_NULL, y_sync_low[i] and y_sync_high[i] must point to different buffers. These buffers will be filled with output hard sync signals.
static inline void bwp_phase_gen_sync(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT state,
float phase);
Syncs state with an external phase of range [0.f, 1.f), covering two periods of state's own phase (this in order to take swing into account), using coeffs.
coeffs must be in the "reset" state.
static inline void bwp_phase_gen_sync_multi(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
bwp_phase_gen_state * BW_RESTRICT const * BW_RESTRICT state,
const float * BW_RESTRICT phase,
size_t n_channels);
Syncs each of the n_channels states with the external phases of range [0.f, 1.f), covering two periods of each states' phase (this in order to take swing into account), using coeffs.
coeffs must be in the "reset" state.
static inline void bwp_phase_gen_set_frequency(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets the base frequency to value (Hz) in coeffs.
value must be finite.
Default value: 1.f.
static inline void bwp_phase_gen_set_sync_phase(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets which value the phase assumes immediately after a hard sync event when the phase generator is operating as a hard sync slave.
Valid range: [0.f, 1.f).
Default value: 0.f.
static inline void bwp_phase_gen_set_portamento_tau(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets the portamento time constant value (s) in coeffs.
value must be non-negative.
Default value: 0.f.
static inline void bwp_phase_gen_set_phase_inc_min(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets the minimum phase increment value in coeffs.
The algorithm will limit the actual phase increment accordingly, yet if the magnitude of the resulting phase increment is less than 6e-8f, it will be rounded to 0.f and such value will be reported by processing functions.
Valid range: [-INFINITY, INFINITY).
By the time bwp_phase_gen_reset_*(), bwp_phase_gen_update_coeffs_*(), bwp_phase_gen_process*(), or bwp_phase_gen_sync*() is called, phase_inc_min must be less than phase_inc_max.
Default value: -INFINITY.
static inline void bwp_phase_gen_set_phase_inc_max(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets the maximum phase increment value in coeffs.
The algorithm will limit the actual phase increment accordingly, yet if the magnitude of the resulting phase increment is less than 6e-8f, it will be rounded to 0.f and such value will be reported by processing functions.
Valid range: (-INFINITY, INFINITY].
By the time bwp_phase_gen_reset_*(), bwp_phase_gen_update_coeffs_*(), bwp_phase_gen_process*(), or bwp_phase_gen_sync*() is called, phase_inc_min must be less than phase_inc_max.
Default value: INFINITY.
static inline void bwp_phase_gen_set_swing(
bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
float value);
Sets the swing value (%) in coeffs.
This setting controls the duration of two successive periods, so that the duration of the first is value % the duration of the both together, which stays constant.
This parameter is not smoothed (but changing it shouldn't normally cause glitches).
Valid range: [0.f, 100.f].
static inline char bwp_phase_gen_coeffs_is_valid(
const bwp_phase_gen_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 bwp_phase_gen_coeffs.
static inline char bwp_phase_gen_state_is_valid(
const bwp_phase_gen_coeffs * BW_RESTRICT coeffs,
const bwp_phase_gen_state * BW_RESTRICT state);
Tries to determine whether state 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.
If coeffs is not BW_NULL extra cross-checks might be performed (state is supposed to be associated to coeffs).
state must at least point to a readable memory block of size greater than or equal to that of bwp_phase_gen_state.
template<size_t N_CHANNELS = 1>
class PhaseGen {
public:
PhaseGen();
void setSampleRate(
float sampleRate);
void reset(
float phase0 = 0.f,
char isSlave = 0,
float xSyncLow0 = 0.f,
float xSyncHigh0 = 0.f,
float * BW_RESTRICT y0 = BW_NULL,
float * BW_RESTRICT yInc0 = BW_NULL,
float * BW_RESTRICT ySyncLow0 = BW_NULL,
float * BW_RESTRICT ySyncHigh0 = BW_NULL);
# ifndef BW_CXX_NO_ARRAY
void reset(
float phase0,
char isSlave,
float xSyncLow0,
float xSyncHigh0,
std::array<float, N_CHANNELS> * BW_RESTRICT y0,
std::array<float, N_CHANNELS> * BW_RESTRICT yInc0,
std::array<float, N_CHANNELS> * BW_RESTRICT ySyncLow0,
std::array<float, N_CHANNELS> * BW_RESTRICT ySyncHigh0);
# endif
void reset(
const float * phase0,
const char * BW_RESTRICT isSlave,
const float * xSyncLow0,
const float * xSyncHigh0,
float * y0 = BW_NULL,
float * yInc0 = BW_NULL,
float * ySyncLow0 = BW_NULL,
float * ySyncHigh0 = BW_NULL);
# ifndef BW_CXX_NO_ARRAY
void reset(
std::array<float, N_CHANNELS> phase0,
std::array<char, N_CHANNELS> isSlave,
std::array<float, N_CHANNELS> xSyncLow0,
std::array<float, N_CHANNELS> xSyncHigh0,
std::array<float, N_CHANNELS> * BW_RESTRICT y0 = BW_NULL,
std::array<float, N_CHANNELS> * BW_RESTRICT yInc0 = BW_NULL,
std::array<float, N_CHANNELS> * BW_RESTRICT ySyncLow0 = BW_NULL,
std::array<float, N_CHANNELS> * BW_RESTRICT ySyncHigh0 = BW_NULL);
# endif
void process(
const float * const * xMod,
const char * const * xSyncDo,
const float * const * xSyncLow,
const float * const * xSyncHigh,
float * const * y,
float * const * yInc,
char * const * ySyncDo,
float * const * ySyncLow,
float * const * ySyncHigh,
size_t nSamples);
# ifndef BW_CXX_NO_ARRAY
void process(
std::array<const float *, N_CHANNELS> xMod,
std::array<const char *, N_CHANNELS> xSyncDo,
std::array<const float *, N_CHANNELS> xSyncLow,
std::array<const float *, N_CHANNELS> xSyncHigh,
std::array<float *, N_CHANNELS> y,
std::array<float *, N_CHANNELS> yInc,
std::array<char *, N_CHANNELS> ySyncDo,
std::array<float *, N_CHANNELS> ySyncLow,
std::array<float *, N_CHANNELS> ySyncHigh,
size_t nSamples);
# endif
void sync(
size_t channel,
float phase);
void sync(
const float * BW_RESTRICT phase);
# ifndef BW_CXX_NO_ARRAY
void sync(
std::array<float, N_CHANNELS> phase);
# endif
void setFrequency(
float value);
void setSyncPhase(
float value);
void setPortamentoTau(
float value);
void setPhaseIncMin(
float value);
void setPhaseIncMax(
float value);
void setSwing(
float value);
...
}
bwp_phase_gen_process1_*swing(), bwp_phase_gen_sync*(), and swing parameter.N_CHANNELS in C++ API.bwp_phase_gen_set_phase_inc_*().bwp_phase_gen_set_phase_inc_*().BW_NULL in the C++ API and implementation.