Here is the LIVE DEMO video of the CW AUDIO BANDpass filter in action
chatGPT wrote its c CODE:
(see attached txt file)
COMPILEd by this command:
gcc -o bandpassfilter3 bandpassfilter3.c -ljack -lm
runs by command line
./bandpassfilter3 192000 1024 800 5
arguments are
sample rate of sound card
buffer frames of the jack audio connection kit
CW pitch
"Q" of the bandpass filter
c code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <jack/jack.h>
#include <math.h>
#include <signal.h>
#include <unistd.h>
#define PI 3.14159265358979323846
jack_port_t *input_port, *output_port;
jack_client_t *client;
typedef struct {
double x1, x2, y1, y2;
} BiquadState;
typedef struct {
double b0, b1, b2;
double a0, a1, a2;
BiquadState state;
} BiquadCoeffs;
BiquadCoeffs g_coeffs[2]; // Filter coefficients for a cascaded biquad filter
// Global variables for sample rate and running flag
int SAMPLE_RATE;
int running = 1; // Flag to control the main loop
// Signal handler for graceful termination
void signal_handler(int signum) {
if (signum == SIGINT) {
running = 0; // Set the flag to stop processing
}
}
// Calculate filter coefficients
void calculate_coefficients(double f0, double Q) {
double omega0 = 2.0 * PI * f0 / SAMPLE_RATE;
double alpha = sin(omega0) / (2.0 * Q);
double cos_omega0 = cos(omega0);
// Low-pass filter coefficients (First biquad section)
g_coeffs[0].b0 = (1 - cos_omega0) / 2;
g_coeffs[0].b1 = 1 - cos_omega0;
g_coeffs[0].b2 = (1 - cos_omega0) / 2;
g_coeffs[0].a0 = 1 + alpha;
g_coeffs[0].a1 = -2 * cos_omega0;
g_coeffs[0].a2 = 1 - alpha;
// High-pass filter coefficients (Second biquad section)
g_coeffs[1].b0 = (1 + cos_omega0) / 2;
g_coeffs[1].b1 = -(1 + cos_omega0);
g_coeffs[1].b2 = (1 + cos_omega0) / 2;
g_coeffs[1].a0 = 1 + alpha;
g_coeffs[1].a1 = -2 * cos_omega0;
g_coeffs[1].a2 = 1 - alpha;
// Initialize state variables
g_coeffs[0].state.x1 = g_coeffs[0].state.x2 = g_coeffs[0].state.y1 = g_coeffs[0].state.y2 = 0.0;
g_coeffs[1].state.x1 = g_coeffs[1].state.x2 = g_coeffs[1].state.y1 = g_coeffs[1].state.y2 = 0.0;
// Debugging: Print coefficients
printf("Coefficients for filter:\n");
printf("First Biquad Section (Low-pass):\n");
printf("b0: %f, b1: %f, b2: %f\n", g_coeffs[0].b0, g_coeffs[0].b1, g_coeffs[0].b2);
printf("a0: %f, a1: %f, a2: %f\n", g_coeffs[0].a0, g_coeffs[0].a1, g_coeffs[0].a2);
printf("Second Biquad Section (High-pass):\n");
printf("b0: %f, b1: %f, b2: %f\n", g_coeffs[1].b0, g_coeffs[1].b1, g_coeffs[1].b2);
printf("a0: %f, a1: %f, a2: %f\n", g_coeffs[1].a0, g_coeffs[1].a1, g_coeffs[1].a2);
}
// Filter a single sample
double filter_sample(double sample) {
// Apply the first biquad section (Low-pass)
double y0 = (g_coeffs[0].b0 * sample + g_coeffs[0].b1 * g_coeffs[0].state.x1 + g_coeffs[0].b2 * g_coeffs[0].state.x2
- g_coeffs[0].a1 * g_coeffs[0].state.y1 - g_coeffs[0].a2 * g_coeffs[0].state.y2) / g_coeffs[0].a0;
// Update state variables for the first biquad section
g_coeffs[0].state.x2 = g_coeffs[0].state.x1;
g_coeffs[0].state.x1 = sample;
g_coeffs[0].state.y2 = g_coeffs[0].state.y1;
g_coeffs[0].state.y1 = y0;
// Apply the second biquad section (High-pass)
double y1 = (g_coeffs[1].b0 * y0 + g_coeffs[1].b1 * g_coeffs[1].state.x1 + g_coeffs[1].b2 * g_coeffs[1].state.x2
- g_coeffs[1].a1 * g_coeffs[1].state.y1 - g_coeffs[1].a2 * g_coeffs[1].state.y2) / g_coeffs[1].a0;
// Update state variables for the second biquad section
g_coeffs[1].state.x2 = g_coeffs[1].state.x1;
g_coeffs[1].state.x1 = y0;
g_coeffs[1].state.y2 = g_coeffs[1].state.y1;
g_coeffs[1].state.y1 = y1;
return y1;
}
// JACK process callback function
int process(jack_nframes_t nframes, void *arg) {
jack_default_audio_sample_t *in, *out;
in = (jack_default_audio_sample_t *)jack_port_get_buffer(input_port, nframes);
out = (jack_default_audio_sample_t *)jack_port_get_buffer(output_port, nframes);
for (int i = 0; i < nframes; i++) {
out[i] = filter_sample(in[i]);
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: %s <sample_rate> <buffer_size> <center_freq> [Q]\n", argv[0]);
return 1;
}
SAMPLE_RATE = atoi(argv[1]);
int buffer_size = atoi(argv[2]);
double f0 = atof(argv[3]); // Center frequency
double Q = (argc == 5) ? atof(argv[4]) : 8.0; // Quality factor, default to 8.0 if not provided
if (SAMPLE_RATE <= 0 || buffer_size <= 0 || f0 <= 0 || Q <= 0) {
fprintf(stderr, "Invalid arguments. Sample rate, buffer size, center frequency, and Q must be positive numbers.\n");
return 1;
}
jack_status_t status;
client = jack_client_open("bandpass_filter", JackNoStartServer, &status);
if (client == NULL) {
fprintf(stderr, "Failed to open JACK client\n");
return 1;
}
if (status & JackServerStarted) {
fprintf(stderr, "JACK server started\n");
}
if (status & JackNameNotUnique) {
const char *client_name = jack_get_client_name(client);
fprintf(stderr, "Unique name `%s' assigned\n", client_name);
}
input_port = jack_port_register(client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
output_port = jack_port_register(client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if (input_port == NULL || output_port == NULL) {
fprintf(stderr, "Failed to register JACK ports\n");
jack_client_close(client);
return 1;
}
calculate_coefficients(f0, Q);
jack_set_process_callback(client, process, 0);
if (jack_activate(client)) {
fprintf(stderr, "Failed to activate JACK client\n");
jack_client_close(client);
return 1;
}
// Set up signal handler for graceful termination
signal(SIGINT, signal_handler);
printf("Press Ctrl+C to quit...\n");
while (running) {
// Main loop can be filled with additional logic if needed
// For now, it just waits for the signal to terminate
sleep(1);
}
// Attempt to close the JACK client gracefully
if (jack_client_close(client)) {
fprintf(stderr, "Error closing JACK client\n");
return 1;
}
return 0;
}