mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
442 lines
9.4 KiB
C
442 lines
9.4 KiB
C
/**
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
|
|
// =============================================================================
|
|
// 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;
|
|
}
|