Beautiful Bleep

Audio-thread functions

typedef struct bb_block_info {
    uint32_t struct_size;          /* BB_BLOCK_INFO_INIT */
    uint32_t num_samples;          /* 1..4096 */
    int64_t  transport_sample_pos; /* host position of the first sample */
    double   sample_rate;
    uint32_t flags;                /* BB_BLOCK_PLAYING */
    uint64_t host_time_ns;         /* 0 = library clock */
} bb_block_info;

bb_begin_block

void bb_begin_block(bb_endpoint* ep, const bb_block_info* info);

Starts a block. [RT] Split host blocks larger than BB_MAX_BLOCK_SAMPLES into sub-blocks and advance transport_sample_pos for each. Set BB_BLOCK_PLAYING whenever the transport runs, offline export included. The deterministic timing rule depends on it.

bb_write_output

void bb_write_output(bb_output* out, const float* samples, uint32_t num_samples);

Publishes this block's samples. [RT] A shorter write holds its last sample to the end of the block. A second call in the same block overwrites. Outputs you don't write publish zeros.

bb_read_input

uint32_t bb_read_input(bb_input* in, float* dest, uint32_t num_samples);

Fills dest with Σ (source × amount) over all cables. [RT] Returns the number of cables whose source is present. Use it to tell "unpatched" from "patched but zero".

Each source arrives one block late (see Concepts). If the source has no suitable block, its last value is held.

bb_end_block

void bb_end_block(bb_endpoint* ep);

Ends the block. [RT]

bb_block_info b = BB_BLOCK_INFO_INIT;
b.num_samples = n; b.sample_rate = sr;
b.transport_sample_pos = pos; b.flags = playing ? BB_BLOCK_PLAYING : 0;
bb_begin_block(ep, &b);
bb_read_input(rate_in, rate_mod, n);
render_lfo(lfo, rate_mod, n);
bb_write_output(lfo_out, lfo, n);
bb_end_block(ep);