bw_voice_alloc_mode -> bw_voice_alloc_priority + finished C doc

This commit is contained in:
Stefano D'Angelo 2023-07-12 10:52:16 +02:00
parent 73185217e7
commit bd3a6367e0
6 changed files with 67 additions and 16 deletions

1
TODO
View File

@ -63,6 +63,7 @@ code:
* c++ get coeffs/state? or public? src nIn/OutSamples case (array vs single value), delay read/write, process1? process single? * c++ get coeffs/state? or public? src nIn/OutSamples case (array vs single value), delay read/write, process1? process single?
* bw_buf invert src dest order? * bw_buf invert src dest order?
* check unititialized warnings * check unititialized warnings
* voice alloc mode -> voice alloc priority
build system: build system:
* single header generation * single header generation

View File

@ -167,7 +167,7 @@ void bw_example_synth_poly_process(bw_example_synth_poly *instance, const float*
(void)x; (void)x;
static bw_voice_alloc_opts alloc_opts = { bw_voice_alloc_mode_low, note_on, note_off, get_note, is_free }; static bw_voice_alloc_opts alloc_opts = { bw_voice_alloc_priority_low, note_on, note_off, get_note, is_free };
void *voices[N_VOICES]; void *voices[N_VOICES];
for (int i = 0; i < N_VOICES; i++) for (int i = 0; i < N_VOICES; i++)
voices[i] = (void *)(instance->voices + i); voices[i] = (void *)(instance->voices + i);

View File

@ -132,7 +132,6 @@ static char is_free(void *BW_RESTRICT voice) {
return !v->gate && phase == bw_env_gen_phase_off; return !v->gate && phase == bw_env_gen_phase_off;
} }
#include <stdio.h>
void bw_example_synthpp_poly_process(bw_example_synthpp_poly *instance, const float** x, float** y, int n_samples) { void bw_example_synthpp_poly_process(bw_example_synthpp_poly *instance, const float** x, float** y, int n_samples) {
// FIXME: control-rate modulations are asynchronous here... // FIXME: control-rate modulations are asynchronous here...
// it's all good as long as hosts gives us buffers whose length is a multiple of 32, // it's all good as long as hosts gives us buffers whose length is a multiple of 32,
@ -140,7 +139,7 @@ void bw_example_synthpp_poly_process(bw_example_synthpp_poly *instance, const fl
(void)x; (void)x;
static bw_voice_alloc_opts alloc_opts = { bw_voice_alloc_mode_low, note_on, note_off, get_note, is_free }; static bw_voice_alloc_opts alloc_opts = { bw_voice_alloc_priority_low, note_on, note_off, get_note, is_free };
void *voices[N_VOICES]; void *voices[N_VOICES];
for (int i = 0; i < N_VOICES; i++) for (int i = 0; i < N_VOICES; i++)
voices[i] = (void *)(instance->voices + i); voices[i] = (void *)(instance->voices + i);

View File

@ -23,9 +23,10 @@
* version {{{ 0.5.0 }}} * version {{{ 0.5.0 }}}
* requires {{{ bw_common bw_config }}} * requires {{{ bw_common bw_config }}}
* description {{{ * description {{{
* Note queue. * Simple data structure that helps keeping track of note on/off events and
* pressed key status.
* *
* ... * It is not concerned with timing.
* }}} * }}}
* changelog {{{ * changelog {{{
* <ul> * <ul>
@ -55,6 +56,10 @@ typedef struct {
float velocity; // negative = unknown / not available float velocity; // negative = unknown / not available
} bw_note_queue_status; } bw_note_queue_status;
/*! <<<``` /*! <<<```
* Note status:
* * `pressed`: whether the note is pressed (non-`0`) or not (`0`);
* * `velocity`: velocity in [`0.f`, `1.f`].
*
* #### bw_note_queue_event * #### bw_note_queue_event
* ```>>> */ * ```>>> */
typedef struct { typedef struct {
@ -63,6 +68,12 @@ typedef struct {
char went_off; char went_off;
} bw_note_queue_event; } bw_note_queue_event;
/*! <<<``` /*! <<<```
* Note on/off event:
* * `note`: note number in [`0`, `127`];
* * `status`: note status;
* * `went_off`: whether a note off event fired on the same note (non-`0`)
* or not (`0`) -- see `bw_note_queue`.
*
* #### bw_note_queue * #### bw_note_queue
* ```>>> */ * ```>>> */
typedef struct { typedef struct {
@ -72,18 +83,39 @@ typedef struct {
unsigned char n_pressed; unsigned char n_pressed;
} bw_note_queue; } bw_note_queue;
/*! <<<``` /*! <<<```
* Note on/off event queue and pressed key status:
* * `events`: events since the reset/clear -- the order is not meaningful
* and it contains maximum one event per note number, so that the last
* event added for a given note overwrites the previous if it exists;
* `went_off` is set to non-`0` in case of a note off event or when
* overwriting an event whose `went_off` was already non-`0`;
* * `n_events`: number of elements in `events`;
* * `status`: current status of all notes;
* * `n_pressed`: number of currently pressed keys.
*
* #### bw_note_queue_reset() * #### bw_note_queue_reset()
* ```>>> */ * ```>>> */
static inline void bw_note_queue_reset(bw_note_queue *BW_RESTRICT queue); static inline void bw_note_queue_reset(bw_note_queue *BW_RESTRICT queue);
/*! <<<``` /*! <<<```
* Clear both the event queue (no events) and the note statuses (all notes
* off, all velocities `0.f`) in `queue`.
*
* #### bw_note_queue_clear() * #### bw_note_queue_clear()
* ```>>> */ * ```>>> */
static inline void bw_note_queue_clear(bw_note_queue *BW_RESTRICT queue); static inline void bw_note_queue_clear(bw_note_queue *BW_RESTRICT queue);
/*! <<<``` /*! <<<```
* Clears the event queue (no events) in `queue` without affecting the note
* statuses.
*
* #### bw_note_queue_add() * #### bw_note_queue_add()
* ```>>> */ * ```>>> */
static inline void bw_note_queue_add(bw_note_queue *BW_RESTRICT queue, unsigned char note, char pressed, float velocity, char force_went_off); static inline void bw_note_queue_add(bw_note_queue *BW_RESTRICT queue, unsigned char note, char pressed, float velocity, char force_went_off);
/*! <<<``` /*! <<<```
* Adds a new event to `queue` with the specified `note` number, `pressed`
* value, and `velocity`.
*
* If `force_went_off` is set to non-`0`, `went_off` is always set to
* non-`0`.
* }}} */ * }}} */
/*** Implementation ***/ /*** Implementation ***/

View File

@ -86,7 +86,7 @@ typedef enum {
* Distance metrics for sticky behavior: * Distance metrics for sticky behavior:
* * `bw_one_pole_sticky_mode_abs`: absolute difference (|`out` - `in`|); * * `bw_one_pole_sticky_mode_abs`: absolute difference (|`out` - `in`|);
* * `bw_one_pole_sticky_mode_rel`: relative difference with respect to * * `bw_one_pole_sticky_mode_rel`: relative difference with respect to
* input (|`out` - `in`| / |`in`|); * input (|`out` - `in`| / |`in`|).
* *
* #### bw_one_pole_init() * #### bw_one_pole_init()
* ```>>> */ * ```>>> */

View File

@ -23,9 +23,7 @@
* version {{{ 0.5.0 }}} * version {{{ 0.5.0 }}}
* requires {{{ bw_common bw_config bw_note_queue }}} * requires {{{ bw_common bw_config bw_note_queue }}}
* description {{{ * description {{{
* Basic voice allocator. * Basic voice allocator with low/high note priority.
*
* ...
* }}} * }}}
* changelog {{{ * changelog {{{
* <ul> * <ul>
@ -49,17 +47,21 @@ extern "C" {
#include <bw_note_queue.h> #include <bw_note_queue.h>
/*! api {{{ /*! api {{{
* #### bw_voice_alloc_mode * #### bw_voice_alloc_priority
* ```>>> */ * ```>>> */
typedef enum { typedef enum {
bw_voice_alloc_mode_low, bw_voice_alloc_priority_low,
bw_voice_alloc_mode_high bw_voice_alloc_priority_high
} bw_voice_alloc_mode; } bw_voice_alloc_priority;
/*! <<<``` /*! <<<```
* Note priority:
* * `bw_voice_alloc_priority_low`: low note priority;
* * `bw_voice_alloc_priority_high`: high note priority.
*
* #### bw_voice_alloc_opts * #### bw_voice_alloc_opts
* ```>>> */ * ```>>> */
typedef struct { typedef struct {
bw_voice_alloc_mode mode; bw_voice_alloc_priority priority;
void (*note_on)(void *BW_RESTRICT voice, unsigned char note, float velocity); void (*note_on)(void *BW_RESTRICT voice, unsigned char note, float velocity);
void (*note_off)(void *BW_RESTRICT voice, float velocity); void (*note_off)(void *BW_RESTRICT voice, float velocity);
@ -67,10 +69,27 @@ typedef struct {
char (*is_free)(void *BW_RESTRICT voice); char (*is_free)(void *BW_RESTRICT voice);
} bw_voice_alloc_opts; } bw_voice_alloc_opts;
/*! <<<``` /*! <<<```
* Voice allocation options:
* * `priority`: note priority;
* * `note_on`: note on callback, where `voice` is an opaque pointer to the
* chosen voice, `note` is the note number, and `velocity` is the note
* velocity in [`0.f`, `1.f`];
* * `note_off`: note off callback, where `voice` is an opaque pointer to
* the chosen voice and `velocity` is the note velocity in [`0.f`, `1.f`];
* * `get_note`: callback that returns the note number associated to the
* given `voice`;
* * `is_free`: callback that returns whether the given `voice` is free
* (non-`0`) or not (`0`);
*
* #### bw_voice_alloc() * #### bw_voice_alloc()
* ```>>> */ * ```>>> */
void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *BW_RESTRICT queue, void **BW_RESTRICT voices, int n_voices); void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *BW_RESTRICT queue, void **BW_RESTRICT voices, int n_voices);
/*! <<<``` /*! <<<```
* It performs voice allocation according to `opts` and using the events in
* `queue`.
*
* `voices` is the array of opaque voice pointers and `n_voices` indicates
* the number of elements in `voices`.
* }}} */ * }}} */
/*** Implementation ***/ /*** Implementation ***/
@ -101,7 +120,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
int v = ev->note; int v = ev->note;
for (int j = 0; j < n_voices; j++) { for (int j = 0; j < n_voices; j++) {
int n = opts->get_note(voices[j]); int n = opts->get_note(voices[j]);
if (!queue->status[n].pressed && (k < 0 || (opts->mode == bw_voice_alloc_mode_low ? n > v : n < v))) { if (!queue->status[n].pressed && (k < 0 || (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v))) {
v = n; v = n;
k = j; k = j;
} }
@ -113,7 +132,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
for (int j = 0; j < n_voices; j++) { for (int j = 0; j < n_voices; j++) {
int n = opts->get_note(voices[j]); int n = opts->get_note(voices[j]);
if (opts->mode == bw_voice_alloc_mode_low ? n > v : n < v) { if (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v) {
v = n; v = n;
k = j; k = j;
} }