1
0
C-bytebeat-render/engine.c

182 lines
4.0 KiB
C

#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "formula_substituted.h"
#if defined(_WIN32)
#define __ANSI_CLEAR_STRING "\r"
#elif defined(__unix__) || defined(__linux__)
#define __ANSI_CLEAR_STRING "\x1B[2K\r"
#else
#define __ANSI_CLEAR_STRING "\n"
#endif
const char* ANSI_CLEAR = __ANSI_CLEAR_STRING;
#define PRODUCT (SAMPLE_RATE * SECONDS * CHANNELS)
#define FREQUENCY_OF_STATUS_REPORTING 5000
#define BIT_DEPTH_LIMITER ((1 << BIT_DEPTH) - 1)
#define PCM_COEFFICIENT ((1 << (BIT_DEPTH - 1)) - 1)
#define unsigned_to_signed(x) (x - PCM_COEFFICIENT)
#define signed_to_unsigned(x) (x + PCM_COEFFICIENT)
unsigned int dbgpnt_counter = 0;
const char* dbgpnt_labels[3] = { "memory allocation",
"bytebeat generation",
"writing file" };
#define dbgpnt_labels_size \
(unsigned int)(sizeof(dbgpnt_labels) / sizeof(dbgpnt_labels[0]))
bool silent_mode = 0;
bool debug_mode = 0;
void
debug_print(void)
{
if (!debug_mode)
return;
int has_label = dbgpnt_counter <= dbgpnt_labels_size;
printf("[OK] ");
if (has_label)
printf("%s", dbgpnt_labels[dbgpnt_counter++]);
else
printf("debug point %d", ++dbgpnt_counter);
return;
}
long double
random(void)
{
static int initialized = 0;
if (!initialized) {
srand(time(NULL));
initialized = 1;
}
return (long double)rand() / RAND_MAX;
}
int
main(int argc, char** argv)
{
silent_mode = argc > 1 && argv[1] != NULL &&
(!strcmp(argv[1], "-s") || !strcmp(argv[1], "--silent"));
debug_mode = argc > 1 && argv[1] != NULL &&
(!strcmp(argv[1], "-d") || !strcmp(argv[1], "--debug"));
printf(":: C bytebeat generator runtime unit\n");
fflush(stdout);
if (!silent_mode) {
printf(
"\n"
"Sample rate: %d Hz\n"
"Channels: %d%s\n"
"Bit depth: %ssigned %d-bit\n"
"Duration: ",
SAMPLE_RATE,
CHANNELS,
CHANNELS == 1 ? " (mono)" : (CHANNELS > 2 ? "" : " (stereo)"),
IS_SIGNED ? "" : "un",
BIT_DEPTH);
if (SECONDS >= 3600)
printf(
"%d:%02d:%02d",
SECONDS / 3600,
(SECONDS / 60) % 60,
SECONDS % 60);
else if (SECONDS >= 60)
printf("%d:%02d", SECONDS / 60, SECONDS % 60);
else
printf("%d seconds", SECONDS);
printf("\n\n");
fflush(stdout);
}
SAMPLE_TYPE* q = calloc(PRODUCT, sizeof(SAMPLE_TYPE));
if (q == NULL)
return 1;
debug_print();
for (uintmax_t w = 0; w < PRODUCT; w++) {
long double res = bytebeat((long double)w);
if (IS_SIGNED)
q[w] = (SAMPLE_TYPE)signed_to_unsigned(res) & BIT_DEPTH_LIMITER;
else
q[w] = (SAMPLE_TYPE)res & BIT_DEPTH_LIMITER;
#if BIT_DEPTH < 8
q[(size_t)w] = (SAMPLE_TYPE)((long double)q[(size_t)w] *
((long double)BIT_DEPTH / 8.0));
#endif
if (
!silent_mode &&
(w % FREQUENCY_OF_STATUS_REPORTING == 0 || w >= PRODUCT - 1)) {
printf(
"%sremaining samples = %18" PRIuMAX " (%.2Lf%% done)",
ANSI_CLEAR,
PRODUCT - w - 1,
(long double)w * 100 / (long double)PRODUCT);
fflush(stdout);
}
}
printf("%s", ANSI_CLEAR);
debug_print();
printf("\nWriting out file output.wav...\n");
fflush(stdout);
FILE* r = fopen("output.wav", "wb");
if (r == NULL || !r)
return 1;
fwrite("RIFF", 1, 4, r);
uint32_t t = PRODUCT;
fwrite(&t, sizeof(t), 1, r);
fwrite("WAVE", 1, 4, r);
fwrite("fmt ", 1, 4, r);
uint32_t y = 16; // what? 16-bit depth? or [something else]?
fwrite(&y, sizeof(y), 1, r);
uint16_t u = 1; // 1 what? 1 = unsigned?
fwrite(&u, sizeof(u), 1, r);
uint16_t i = CHANNELS;
fwrite(&i, sizeof(i), 1, r);
uint32_t o = SAMPLE_RATE;
fwrite(&o, sizeof(o), 1, r);
uint32_t s = SAMPLE_RATE * i;
fwrite(&s, sizeof(s), 1, r);
uint16_t p = i;
fwrite(&p, sizeof(p), 1, r);
uint16_t a = BIT_DEPTH >= 8 ? BIT_DEPTH : 8;
fwrite(&a, sizeof(a), 1, r);
fwrite("data", 1, 4, r);
fwrite(&t, sizeof(t), 1, r);
fwrite(q, sizeof(uint8_t), PRODUCT, r);
fclose(r);
debug_print();
free(q);
printf("Done!\n");
return 0;
}