/** * TAV Encoder - Utilities Library * * Common utility functions and helpers used across the encoder. * Includes math utilities, clamping, filename generation, etc. * * Extracted from encoder_tav.c as part of library refactoring. */ #define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include // ============================================================================= // Math Utilities // ============================================================================= /** * Clamp integer value to range [min, max]. */ int tav_clamp_int(int x, int min, int max) { return x < min ? min : (x > max ? max : x); } /** * Clamp float value to range [min, max]. */ float tav_clamp_float(float x, float min, float max) { return x < min ? min : (x > max ? max : x); } /** * Clamp double value to range [min, max]. */ double tav_clamp_double(double x, double min, double max) { return x < min ? min : (x > max ? max : x); } /** * Round double to nearest integer. */ int tav_iround(double v) { return (int)floor(v + 0.5); } /** * Linear interpolation between two values. * @param a Start value (when t=0) * @param b End value (when t=1) * @param t Interpolation factor (0.0 to 1.0) * @return Interpolated value */ float tav_lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; } /** * Double precision linear interpolation. */ double tav_lerp_double(double a, double b, double t) { return a * (1.0 - t) + b * t; } /** * Get minimum of two integers. */ int tav_min_int(int a, int b) { return a < b ? a : b; } /** * Get maximum of two integers. */ int tav_max_int(int a, int b) { return a > b ? a : b; } /** * Get minimum of two floats. */ float tav_min_float(float a, float b) { return a < b ? a : b; } /** * Get maximum of two floats. */ float tav_max_float(float a, float b) { return a > b ? a : b; } /** * Compute absolute value of integer. */ int tav_abs_int(int x) { return x < 0 ? -x : x; } /** * Compute absolute value of float. */ float tav_abs_float(float x) { return x < 0.0f ? -x : x; } /** * Sign function: returns -1, 0, or 1. */ int tav_sign(int x) { return (x > 0) - (x < 0); } /** * Check if integer is power of 2. */ int tav_is_power_of_2(int x) { return x > 0 && (x & (x - 1)) == 0; } /** * Round up to next power of 2. */ int tav_next_power_of_2(int x) { if (x <= 0) return 1; x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1; } /** * Compute floor of log2(x). * Returns -1 for x <= 0. */ int tav_floor_log2(int x) { if (x <= 0) return -1; int log = 0; while (x > 1) { x >>= 1; log++; } return log; } /** * Compute ceil of log2(x). * Returns -1 for x <= 0. */ int tav_ceil_log2(int x) { if (x <= 0) return -1; if (x == 1) return 0; int log = tav_floor_log2(x); // Check if x is power of 2 if ((1 << log) == x) { return log; } return log + 1; } // ============================================================================= // Random Filename Generation // ============================================================================= /** * Generate a random temporary filename with .mp2 extension. * Format: /tmp/[32 random chars].mp2 * * @param filename Output buffer (must be at least 42 bytes) */ void tav_generate_random_filename(char *filename) { static int seeded = 0; if (!seeded) { srand(time(NULL)); seeded = 1; } const char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int charset_size = sizeof(charset) - 1; // Start with the prefix strcpy(filename, "/tmp/"); // Generate 32 random characters for (int i = 0; i < 32; i++) { filename[5 + i] = charset[rand() % charset_size]; } // Add the .mp2 extension strcpy(filename + 37, ".mp2"); filename[41] = '\0'; // Null terminate } /** * Generate a random temporary filename with custom extension. * Format: /tmp/[32 random chars].[ext] * * @param filename Output buffer (must be large enough for path + extension) * @param ext File extension (without leading dot, e.g., "tmp", "wav") */ void tav_generate_random_filename_ext(char *filename, const char *ext) { static int seeded = 0; if (!seeded) { srand(time(NULL)); seeded = 1; } const char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int charset_size = sizeof(charset) - 1; // Start with the prefix strcpy(filename, "/tmp/"); // Generate 32 random characters for (int i = 0; i < 32; i++) { filename[5 + i] = charset[rand() % charset_size]; } // Add the extension filename[37] = '.'; strcpy(filename + 38, ext); } // ============================================================================= // Memory Utilities // ============================================================================= /** * Safe malloc with error checking. * Exits program on allocation failure. */ void *tav_malloc(size_t size) { void *ptr = malloc(size); if (!ptr && size > 0) { fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", size); exit(1); } return ptr; } /** * Safe calloc with error checking. * Exits program on allocation failure. */ void *tav_calloc(size_t count, size_t size) { void *ptr = calloc(count, size); if (!ptr && count > 0 && size > 0) { fprintf(stderr, "ERROR: Failed to allocate %zu elements of %zu bytes\n", count, size); exit(1); } return ptr; } /** * Safe realloc with error checking. * Exits program on allocation failure. */ void *tav_realloc(void *ptr, size_t size) { void *new_ptr = realloc(ptr, size); if (!new_ptr && size > 0) { fprintf(stderr, "ERROR: Failed to reallocate to %zu bytes\n", size); exit(1); } return new_ptr; } /** * Allocate aligned memory. * Returns NULL on failure. */ void *tav_aligned_alloc(size_t alignment, size_t size) { // Ensure alignment is power of 2 if (!tav_is_power_of_2(alignment)) { fprintf(stderr, "ERROR: Alignment must be power of 2, got %zu\n", alignment); return NULL; } #ifdef _WIN32 return _aligned_malloc(size, alignment); #else void *ptr = NULL; if (posix_memalign(&ptr, alignment, size) != 0) { return NULL; } return ptr; #endif } /** * Free aligned memory. */ void tav_aligned_free(void *ptr) { #ifdef _WIN32 _aligned_free(ptr); #else free(ptr); #endif } // ============================================================================= // Array Utilities // ============================================================================= /** * Fill integer array with constant value. */ void tav_array_fill_int(int *array, size_t count, int value) { for (size_t i = 0; i < count; i++) { array[i] = value; } } /** * Fill float array with constant value. */ void tav_array_fill_float(float *array, size_t count, float value) { for (size_t i = 0; i < count; i++) { array[i] = value; } } /** * Copy integer array. */ void tav_array_copy_int(int *dst, const int *src, size_t count) { memcpy(dst, src, count * sizeof(int)); } /** * Copy float array. */ void tav_array_copy_float(float *dst, const float *src, size_t count) { memcpy(dst, src, count * sizeof(float)); } /** * Find maximum value in integer array. */ int tav_array_max_int(const int *array, size_t count) { if (count == 0) return 0; int max_val = array[0]; for (size_t i = 1; i < count; i++) { if (array[i] > max_val) { max_val = array[i]; } } return max_val; } /** * Find minimum value in integer array. */ int tav_array_min_int(const int *array, size_t count) { if (count == 0) return 0; int min_val = array[0]; for (size_t i = 1; i < count; i++) { if (array[i] < min_val) { min_val = array[i]; } } return min_val; } /** * Find maximum absolute value in float array. */ float tav_array_max_abs_float(const float *array, size_t count) { if (count == 0) return 0.0f; float max_abs = fabsf(array[0]); for (size_t i = 1; i < count; i++) { float abs_val = fabsf(array[i]); if (abs_val > max_abs) { max_abs = abs_val; } } return max_abs; } /** * Compute sum of integer array. */ long long tav_array_sum_int(const int *array, size_t count) { long long sum = 0; for (size_t i = 0; i < count; i++) { sum += array[i]; } return sum; } /** * Compute sum of float array. */ double tav_array_sum_float(const float *array, size_t count) { double sum = 0.0; for (size_t i = 0; i < count; i++) { sum += array[i]; } return sum; } /** * Compute mean of float array. */ float tav_array_mean_float(const float *array, size_t count) { if (count == 0) return 0.0f; return (float)(tav_array_sum_float(array, count) / count); } /** * Swap two integer values. */ void tav_swap_int(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /** * Swap two float values. */ void tav_swap_float(float *a, float *b) { float temp = *a; *a = *b; *b = temp; } /** * Swap two pointer values. */ void tav_swap_ptr(void **a, void **b) { void *temp = *a; *a = *b; *b = temp; }