182 lines
4.0 KiB
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;
|
|
}
|