/** * Copyright (C) 2023 Skylar Widulski * * This file is part of Yammer. * * Yammer is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * Yammer is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Yammer. If not, see . * * @file yammer.c * @brief C library for Yammer * @details Library that wraps around other C libraries for easier access in * Guile. */ #include "yammer.h" #include #include #ifdef USE_FFTW /** * @brief Initializes the FFTW plan * @details This function initializes the FFTW plan for the DFT. It allocates * memory for the input and output pointers, and creates the plan. * @param vsize The size of the input pointer * @return The FFTW plan * @note The caller is responsible for freeing the plan */ fftw_plan init_plan(int vsize) { // Allocate memory for the input and output arrays double* in = fftw_malloc(sizeof(double) * vsize); fftw_complex* out = fftw_malloc(sizeof(fftw_complex) * vsize); // Create the FFTW plan fftw_plan p = fftw_plan_dft_r2c_1d(vsize, in, out, FFTW_ESTIMATE); // Free the input and output arrays as they are not needed anymore // The plan has already been created and it's the only thing we need to keep fftw_free(in); fftw_free(out); // Return the plan return p; } /** * @brief Performs the DFT * @details This function performs the DFT on the input pointer. It allocates * memory for the output pointer, and then copies the result of the DFT into it. * @param plan The FFTW plan * @param ins The input pointer * @param len The length of the input pointer * @return The output pointer * @note The caller is responsible for freeing the output pointer */ short int* do_dft(fftw_plan plan, short int* ins, int len) { // Calculate the length of the result int result_len = len / 2 + 1; // Allocate memory for the input and output arrays double* in = fftw_malloc(sizeof(double) * len); short int* outs = malloc(sizeof(short int) * result_len); fftw_complex* out = fftw_malloc(sizeof(fftw_complex) * result_len); // Copy the input data to the input array for (int i = 0; i < len; i++) { in[i] = (double)ins[i]; } // Execute the FFTW plan fftw_execute_dft_r2c(plan, in, out); // Calculate the magnitude of the DFT and store it in the output array for (int i = 0; i < result_len; i++) { outs[i] = (short int)sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]); // Apply a scaling factor to the output outs[i] *= (log2(2 + i) * (100.0 / result_len)); } // Free the input and output arrays as they are not needed anymore fftw_free(in); fftw_free(out); // Return the output array return outs; } #endif // USE_FFTW #ifdef USE_PULSE pa_simple* make_pa_simple(unsigned int bitrate, char* dev, int latency) { pa_sample_spec ss = { .format = PA_SAMPLE_S16NE, .channels = 2, .rate = bitrate }; pa_buffer_attr attr; attr.maxlength = (uint32_t) -1; attr.tlength = (uint32_t) -1; attr.prebuf = (uint32_t) -1; attr.minreq = (uint32_t) -1; attr.fragsize = latency; return pa_simple_new(NULL, "Yammer", PA_STREAM_RECORD, dev, "Audio Visualizer", &ss, NULL, &attr, NULL); } short int* read_from_pa(pa_simple* s, size_t bytes) { short int* buf = malloc(sizeof(short int) * bytes); pa_simple_read(s, buf, sizeof(short int) * bytes, NULL); return buf; } #endif // USE_PULSE