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?
* bw_buf invert src dest order?
* check unititialized warnings
* voice alloc mode -> voice alloc priority
build system:
* single header generation

View File

@ -167,7 +167,7 @@ void bw_example_synth_poly_process(bw_example_synth_poly *instance, const float*
(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];
for (int i = 0; i < N_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;
}
#include <stdio.h>
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...
// 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;
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];
for (int i = 0; i < N_VOICES; i++)
voices[i] = (void *)(instance->voices + i);

View File

@ -23,9 +23,10 @@
* version {{{ 0.5.0 }}}
* requires {{{ bw_common bw_config }}}
* 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 {{{
* <ul>
@ -55,6 +56,10 @@ typedef struct {
float velocity; // negative = unknown / not available
} 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
* ```>>> */
typedef struct {
@ -63,6 +68,12 @@ typedef struct {
char went_off;
} 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
* ```>>> */
typedef struct {
@ -72,18 +83,39 @@ typedef struct {
unsigned char n_pressed;
} 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()
* ```>>> */
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()
* ```>>> */
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()
* ```>>> */
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 ***/

View File

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

View File

@ -23,9 +23,7 @@
* version {{{ 0.5.0 }}}
* requires {{{ bw_common bw_config bw_note_queue }}}
* description {{{
* Basic voice allocator.
*
* ...
* Basic voice allocator with low/high note priority.
* }}}
* changelog {{{
* <ul>
@ -49,17 +47,21 @@ extern "C" {
#include <bw_note_queue.h>
/*! api {{{
* #### bw_voice_alloc_mode
* #### bw_voice_alloc_priority
* ```>>> */
typedef enum {
bw_voice_alloc_mode_low,
bw_voice_alloc_mode_high
} bw_voice_alloc_mode;
bw_voice_alloc_priority_low,
bw_voice_alloc_priority_high
} 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
* ```>>> */
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_off)(void *BW_RESTRICT voice, float velocity);
@ -67,10 +69,27 @@ typedef struct {
char (*is_free)(void *BW_RESTRICT voice);
} 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()
* ```>>> */
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 ***/
@ -101,7 +120,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
int v = ev->note;
for (int j = 0; j < n_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;
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++) {
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;
k = j;
}