Source browser

examples/shaders/signal_biquad.cpp

Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.

File fingerprint
1// Transposed direct-form II biquad, one sequential channel per invocation.
2#ifdef __cplusplus // Enable this block only for the indicated compilation environment.
3#include "shdr.h" // Use the same header for CPU and GPU resource wiring.
4#endif // Finish the conditional compilation block.
5layout(local_size_x = 64) in; // Process up to 64 independent invocations in each work group.
6layout(std430, binding = 0) readonly buffer Inputs { // Read channel-major input samples through this storage binding.
7    float input_values[]; // Store input samples in channel-major order.
8}; // Finish this shader storage declaration.
9layout(std430, binding = 1) writeonly buffer Outputs { // Write one filtered sample to the matching output position.
10    float output_values[]; // Store filtered samples in matching channel-major order.
11}; // Finish this shader storage declaration.
12layout(std430, binding = 2) readonly buffer Coefficients { // Read the shared filter coefficients from this storage binding.
13    float coefficients[]; // Store the finite filter coefficients.
14}; // Finish this shader storage declaration.
15layout(std430, binding = 3) buffer State { // Read and update one recurrence pair per channel.
16    vec2 state[]; // Keep z1 and z2 together for each channel.
17}; // Finish this shader storage declaration.
18uniform uint count; // Receive the sample count for each channel in this block.
19uniform uint channels; // Receive the number of independent signal channels.
20void main() { // Filter this channel's temporal block using its retained state.
21    uint channel = gl_GlobalInvocationID.x; // Give this invocation one independent channel.
22    if (channel >= channels) // Ignore unused invocations outside the channel count.
23        return; // Finish invocations beyond the configured signal range.
24    vec2 previous = state[channel]; // Load both recurrence values from the previous block.
25    float z1 = previous.x, z2 = previous.y; // Keep the channel recurrence values in private registers.
26    float b0 = coefficients[0], b1 = coefficients[1], b2 = coefficients[2]; // Load the three normalized feed-forward coefficients.
27    float a1 = coefficients[3], a2 = coefficients[4]; // Load the two normalized feedback coefficients.
28    for (uint position = 0u; position < count; ++position) { // Process the channel samples in temporal order.
29        uint index = channel * count + position; // Find the sample handled by this invocation.
30        float x = input_values[index], y = b0 * x + z1; // Read the current sample and compute its filtered output.
31        z1 = b1 * x - a1 * y + z2; // Advance the first transposed recurrence value.
32        z2 = b2 * x - a2 * y; // Advance the second transposed recurrence value.
33        output_values[index] = y; // Store the result at the matching sample position.
34    } // Finish this channel, sample or feature pass.
35    state[channel] = vec2(z1, z2); // Keep both recurrence values for the next block.
36} // Finish the main operation.