bwp_phase_gen

Advanced version of bw_phase_gen with hard sync.

In addition to the usual phase and phase increment signals, this module introduces 3 hard sync-specific signals, namely:

  • a "hard sync do" signal, of type 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);
  • a "hard sync low" signal of type 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];
  • a "hard sync high" signal of type 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.

Examples

We can privately hand you one or more example plugins if you are interested.

Contact us

API

Module type: DSP

bwp_phase_gen_coeffs

typedef struct bwp_phase_gen_coeffs bwp_phase_gen_coeffs;

Coefficients and related.

bwp_phase_gen_state

typedef struct bwp_phase_gen_state bwp_phase_gen_state;

Internal state and related.

bwp_phase_gen_init()

static inline void bwp_phase_gen_init(
	bwp_phase_gen_coeffs * BW_RESTRICT coeffs);

Initializes input parameter values in coeffs.

bwp_phase_gen_set_sample_rate()

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.

bwp_phase_gen_reset_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.

bwp_phase_gen_reset_state()

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.

bwp_phase_gen_reset_state_multi()

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.

bwp_phase_gen_update_coeffs_ctrl()

static inline void bwp_phase_gen_update_coeffs_ctrl(
	bwp_phase_gen_coeffs * BW_RESTRICT coeffs);

Triggers control-rate update of coefficients in coeffs.

bwp_phase_gen_update_coeffs_audio()

static inline void bwp_phase_gen_update_coeffs_audio(
	bwp_phase_gen_coeffs * BW_RESTRICT coeffs);

Triggers audio-rate update of coefficients in coeffs.

bwp_phase_gen_process1*()

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);

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 modulation scale for x_mod is 1.f/octave.

x_sync_low and x_sync_high are ignored if x_sync_do is 0.

bwp_phase_gen_process()

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.

bwp_phase_gen_process_multi()

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.

bwp_phase_gen_set_frequency()

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.

bwp_phase_gen_set_sync_phase()

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.

bwp_phase_gen_set_portamento_tau()

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.

bwp_phase_gen_set_phase_inc_min()

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_\*(), or bwp_peak_process\*() is called, phase_inc_min must be less than phase_inc_max.

Default value: -INFINITY.

bwp_phase_gen_set_phase_inc_max()

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_\*(), or bwp_peak_process\*() is called, phase_inc_min must be less than phase_inc_max.

Default value: INFINITY.

bwp_phase_gen_coeffs_is_valid()

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.

bwp_phase_gen_state_is_valid()

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.

C++ wrapper

BrickworksPro::PhaseGen
template<size_t N_CHANNELS>
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 setFrequency(
		float value);

	void setSyncPhase(
		float value);

	void setPortamentoTau(
		float value);

	void setPhaseIncMin(
		float value);

	void setPhaseIncMax(
		float value);
...
}

Changelog

  • Verison 1.0.1:
    • Now using BW_NULL in the C++ API and implementation.
    • Updated dependencies in the distribution.
  • Version 1.0.0:
    • First release.