From 98ff576f190b9d04154e584dd711385bd111da28 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Mon, 27 May 2024 08:07:42 +0300 Subject: [PATCH 01/20] WIP: add files --- bytebeat_compiler.py | 142 +++++++++++++++++++---- samples/beeper.c | 5 + samples/cykstep.c | 3 + samples/melody.c | 5 + src/template.c | 270 +++++++++++++++++++++++++++++-------------- 5 files changed, 315 insertions(+), 110 deletions(-) create mode 100644 samples/beeper.c create mode 100644 samples/cykstep.c create mode 100644 samples/melody.c diff --git a/bytebeat_compiler.py b/bytebeat_compiler.py index 1761328..dc9dcb4 100644 --- a/bytebeat_compiler.py +++ b/bytebeat_compiler.py @@ -1,11 +1,15 @@ #!/usr/bin/python3 +if __name__ == "__main__": + print(":: C bytebeat generator: compiler unit") + from argparse import ArgumentParser from os import environ, makedirs from os.path import exists, join as path_join from shlex import split as command_line_split from sys import stdin, stdout, exit from typing import Dict, Union +import re import subprocess # Paths @@ -65,7 +69,7 @@ def read_from_file_or_stdin(path: str) -> str: raise SystemExit def substitute_vars(replacements: Dict[str, Union[bool, str]], text: str, - verbose: bool) -> str: + verbose: bool) -> str: if verbose: print("Substituting values:") for placeholder, replacement in replacements.items(): @@ -89,6 +93,26 @@ OUTPUT_FILE = fetch("OUTPUT_FILE") if extra := fetch("CFLAGS_EXTRA"): CFLAGS += " " + extra +parameter_line_regex = re.compile(r"^\/\/ *RENDER PARAMETERS *: ", re.MULTILINE) + +ALLOWED_ARGUMENTS_FROM_FILE = ( + "sample_rate", + "final_sample_rate", + "bit_depth", + "signed", + "channels", + "no_return", +) + +DEFAULT_ARGS = { + "sample_rate": 8000, + "final_sample_rate": 0, + "bit_depth": 8, + "signed": False, + "channels": 1, + "no_return": False +} + if __name__ == "__main__": parser = ArgumentParser(description=\ "Substitutes supplied C (non-JavaScript!) bytebeat into the template, " @@ -98,37 +122,45 @@ if __name__ == "__main__": parser.add_argument("file", type=str, help="bytebeat formula file (use `-` to read from stdin)") parser.add_argument("-o", "--output", default="output.wav", type=str, - help="specify output file path (default is `output.wav`") - parser.add_argument("-r", "--sample-rate", default=8000, type=int, + help="specify output file path : default is `output.wav`") + parser.add_argument("-r", "--sample-rate", default=None, type=int, help="sample rate (Hz)") parser.add_argument("-p", "--final-sample-rate", default=None, type=int, help="convert the output to a different sample rate (usually one that " "is set in the system, to improve sound quality) during generation " "(not just reinterpretation)") - parser.add_argument("-b", "--bit-depth", default=8, type=int, + parser.add_argument("-b", "--bit-depth", default=None, type=int, help="bit depth") - parser.add_argument("-s", "--signed", default=False, action="store_true", + parser.add_argument("-s", "--signed", default=None, action="store_true", help="is signed?") + parser.add_argument("-u", "--unsigned", default=None, action="store_true", + help="is unsigned? (overrides the 'is signed' parameter)") parser.add_argument("-R", "--precalculate-ratio", default=False, action="store_true", help="precalculate sample ratio to speed up rendering (may produce " - "inaccurate results") + "inaccurate results)") parser.add_argument("-m", "--faster-sample-ratio-math", default=False, action="store_true", help="faster sample ratio math (implies argument -R)") parser.add_argument("-f", "--floating-point", default=False, action="store_true", help="use floating point as the return type") - parser.add_argument("-c", "--channels", default=1, type=int, + parser.add_argument("-c", "--channels", default=None, type=int, help="amount of channels") parser.add_argument("-t", "--seconds", default=None, type=int, help="length in seconds (samples = sample rate * seconds) : " "default = 30 seconds") parser.add_argument("-l", "--samples", default=None, type=int, help="length in samples (adds to `-t`; supports negative numbers) : " - "default = +0 samples") - parser.add_argument("-a", "--no-return", default=False, action="store_true", + "default = seconds + 0 samples") + parser.add_argument("-S", "--skip-first", default=None, type=str, + help="skip first `A` seconds and `B` samples: in format `As`, `B` or " + "`AsB` : default = 0") + parser.add_argument("-k", "--repeat", default=0, type=int, + help="how many times to repeat the bytebeat : " + "default = 0") + parser.add_argument("-a", "--no-return", default=None, action="store_true", help="do not insert return statement before the code") - parser.add_argument("-u", "--mode", default="sequential", type=str, + parser.add_argument("-U", "--mode", default="sequential", type=str, help="mode of writing: `sequential` or `instant` (the latter is not " "recommended, since the whole result would be stored in RAM)") parser.add_argument("-n", "--block-size", default=65536, type=int, @@ -148,7 +180,42 @@ if __name__ == "__main__": if not bytebeat_contents: print("No valid contents") - raise SystemExit + exit(1) + + # - Parse arguments from file + used_parameter_line = False + for line in bytebeat_contents.splitlines(): + if (match := re.search(parameter_line_regex, line)) and \ + not used_parameter_line: + used_parameter_line = True + + parsed_parameters = line[match.start(0):].split(",") + for parameter in parsed_parameters: + kv = [x.strip() for x in parameter.split("=")] + + key = None + value = None + + if len(kv) == 1: + key, value = kv[0], True + elif len(kv) == 2: + key, value = kv[0], int(kv[1]) + else: + break + + # Apply the argument only if it was not used by user yet and is + # allowed to be set + if (key not in args or getattr(args, key) is None) and \ + key in ALLOWED_ARGUMENTS_FROM_FILE: + setattr(args, key, value) + + # - Set default values + for key, value in DEFAULT_ARGS.items(): + if getattr(args, key) is None: + setattr(args, key, value) + + if args.unsigned is True: + args.signed = False # - Compilation makedirs(PATHS["build_dir"], exist_ok=True) @@ -162,7 +229,7 @@ if __name__ == "__main__": final_sample_rate_code = "" if args.faster_sample_ratio_math: args.precalculate_ratio = True - if args.precalculate_ratio and not args.final_sample_rate is None: + if args.precalculate_ratio and args.final_sample_rate != 0: if args.faster_sample_ratio_math: sample_rate_ratio = args.sample_rate / args.final_sample_rate final_sample_rate_code = f"time *= {sample_rate_ratio}L;" @@ -172,7 +239,8 @@ if __name__ == "__main__": args.sample_rate = args.final_sample_rate final_sample_rate = \ - value if (value := args.final_sample_rate) else original_sample_rate + value if (value := args.final_sample_rate) != 0 \ + else original_sample_rate samples = 0 while True: no_seconds = args.seconds is None or args.seconds == 0 @@ -182,7 +250,7 @@ if __name__ == "__main__": if seconds_specified and args.seconds < 0: print("CLI: Count of seconds can't be less than zero.") - raise SystemExit + exit(1) if no_seconds and samples_specified: samples = args.samples @@ -195,27 +263,53 @@ if __name__ == "__main__": continue else: print("CLI: Incorrect seconds/samples length format.") - raise SystemExit + exit(1) break if samples <= 0: print("CLI: Count of samples should be greater than zero.") - raise SystemExit + exit(1) if args.mode != "sequential" and args.mode != "instant": print("Invalid mode '%s'" % args.mode) - raise SystemExit - - gen_length = args.channels * samples + exit(1) ansi_escape_codes_supported = args.color == "auto" and stdout_atty or \ args.color == "always" + actual_sample_rate = \ + value if (value := args.final_sample_rate) else args.sample_rate + + # - Parse the '--skip-first' argument + if not args.skip_first is None: + encountered_s = False + for character in args.skip_first: + if character.isdigit() or character == "s" and not encountered_s: + if character == "s": + encountered_s = True + else: + print(f"Invalid --skip-first format: `{args.skip_first}`") + exit(1) + + skip_first = \ + [int(x) if x.isdigit() else 0 for x in args.skip_first.split("s")] + + skip_first_samples = 0 + if len(skip_first) == 1: + skip_first += [0] + + skip_first_samples = skip_first[0] * actual_sample_rate + skip_first[1] + else: + skip_first_samples = 0 + + length_formula = lambda channels, samples, n: channels * (samples + n) + gen_length = length_formula(args.channels, samples, 0) + loop_end = length_formula(args.channels, samples, skip_first_samples) + rewrite_file(PATHS["substitute"], substitute_vars({ "bytebeat_contents": bytebeat_contents, "output_file": C_str_repr(args.output), - "sample_rate": \ - value if (value := args.final_sample_rate) else args.sample_rate, + "sample_rate": actual_sample_rate, "original_sample_rate": original_sample_rate, "final_sample_rate_code": final_sample_rate_code, "bit_depth": args.bit_depth, @@ -224,7 +318,11 @@ if __name__ == "__main__": "faster_sample_ratio_math": args.precalculate_ratio, "fp_return_type": args.floating_point, "channels": args.channels, - "length": samples, + "running_length": samples, + "loop_end": loop_end, + "loop_end_minus_1": loop_end - 1, + "initial_time": skip_first_samples, + "repeat_times": args.repeat, "wav_product": gen_length * (args.bit_depth // 8), "gen_length": gen_length, "sequential_mode": args.mode == "sequential", diff --git a/samples/beeper.c b/samples/beeper.c new file mode 100644 index 0000000..54034a7 --- /dev/null +++ b/samples/beeper.c @@ -0,0 +1,5 @@ +// RENDER PARAMETERS: sample_rate = 44100, no_return + +bb_counter_t u = t << 1; +SAMPLE_TYPE x = u & u >> 8; +return (x | 127) + 63; diff --git a/samples/cykstep.c b/samples/cykstep.c new file mode 100644 index 0000000..ed3535c --- /dev/null +++ b/samples/cykstep.c @@ -0,0 +1,3 @@ +// RENDER PARAMETERS: sample_rate = 44100, final_sample_rate = 48000, signed + +t/=3,(t*(t+(444+(t/444)))&((t>>9)>4095 ? 4095 : (t>>(9+(3&t>>13)))))>>(3&t>>(5+(3&t>>13))) diff --git a/samples/melody.c b/samples/melody.c new file mode 100644 index 0000000..9c4ba5c --- /dev/null +++ b/samples/melody.c @@ -0,0 +1,5 @@ +// RENDER PARAMETERS: sample_rate = 44100, no_return + +const long double array[] = {1, 1.25, 1.5, 2}; +long double v = array[3 & (t >> 13)]; +return (long double) t * v / 3.1415926535; diff --git a/src/template.c b/src/template.c index 6af8835..c7e0e8e 100644 --- a/src/template.c +++ b/src/template.c @@ -9,6 +9,10 @@ #include "`fwrite_le`" +// typedefs +typedef uintmax_t bb_counter_t; +typedef long double bb_fp_return_t; + // constants #define ANSI_ESCAPE_CODES_SUPPORTED `ansi_escape_codes_supported` @@ -29,20 +33,41 @@ #define BIT_DEPTH `bit_depth` #define IS_SIGNED `is_signed` #define CHANNELS `channels` -#define LENGTH `length` +#define RUNNING_LENGTH `running_length` #if BIT_DEPTH <= 8 +# define ACTUAL_BIT_DEPTH 8 + # define SAMPLE_TYPE uint8_t -#elif BIT_DEPTH >= 16 +#elif BIT_DEPTH <= 16 +# define ACTUAL_BIT_DEPTH 16 + # if IS_SIGNED # define SAMPLE_TYPE int16_t # else # define SAMPLE_TYPE uint16_t # endif +#elif BIT_DEPTH <= 32 +# define ACTUAL_BIT_DEPTH 32 + +# if IS_SIGNED +# define SAMPLE_TYPE int32_t +# else +# define SAMPLE_TYPE uint32_t +# endif +#else +# error "Unsupported bit depth" +# define _ERROR #endif -#define PRODUCT `wav_product` -#define GEN_LENGTH `gen_length` +#ifndef _ERROR + +#define PRODUCT `wav_product`ULL +#define GEN_LENGTH `gen_length`ULL +#define INITIAL_TIME `initial_time` +#define LOOP_END `loop_end`ULL +#define LOOP_END_MINUS_1 `loop_end_minus_1`ULL +#define REPEAT_TIMES `repeat_times`ULL #define FREQUENCY_OF_STATUS_REPORTING 5000 #define SEQUENTIAL_MODE `sequential_mode` @@ -53,8 +78,8 @@ #define FP_RETURN_TYPE `fp_return_type` #define PRECALCULATED_RATIO `precalculated_ratio` -#define BIT_DEPTH_LIMITER ((1 << BIT_DEPTH) - 1) -#define PCM_COEFFICIENT ((1 << (BIT_DEPTH - 1)) - 1) +#define BIT_DEPTH_LIMITER ((1ULL << ACTUAL_BIT_DEPTH) - 1ULL) +#define PCM_COEFFICIENT ((1ULL << (ACTUAL_BIT_DEPTH - 1ULL)) - 1ULL) #define unsigned_to_signed(x) (x - PCM_COEFFICIENT) #define signed_to_unsigned(x) (x + PCM_COEFFICIENT) @@ -78,19 +103,19 @@ // function prototypes #if FP_RETURN_TYPE -long double +bb_fp_return_t #else SAMPLE_TYPE #endif -bytebeat(long double time); +bytebeat(bb_counter_t time); // function implementations #if FP_RETURN_TYPE -long double +bb_fp_return_t #else SAMPLE_TYPE #endif -bytebeat(long double time) +bytebeat(bb_counter_t time) { #if PRECALCULATED_RATIO `final_sample_rate_code` @@ -105,39 +130,10 @@ bytebeat(long double time) `bytebeat_contents`; } -int -main(void) -{ - // * log -> welcome -#if !SILENT_MODE - puts(":: C bytebeat generator runtime unit"); - fflush(stdout); -#endif - -#if !SILENT_MODE - const uintmax_t seconds = LENGTH / SAMPLE_RATE, - samples = LENGTH % SAMPLE_RATE; - - printf( - "\n" - "Sample rate: " INT2STR(SAMPLE_RATE) " Hz\n" - "Channels: " INT2STR(CHANNELS) -#if CHANNELS <= 2 - " (" -# if CHANNELS == 2 - "stereo" -# else - "mono" -# endif - ")" -#endif - "\n" - "Bit depth: " -#if !IS_SIGNED - "un" -#endif - "signed " INT2STR(BIT_DEPTH) "-bit\n" - "Duration: "); +void +print_time(uintmax_t length) { + const uintmax_t seconds = length / SAMPLE_RATE, + samples = length % SAMPLE_RATE; if (seconds > 0) if (seconds >= 3600) @@ -156,6 +152,54 @@ main(void) if (samples > 0) printf("%" PRIuMAX " samples", samples); +} + +int +main(void) +{ + // * log -> welcome +#if !SILENT_MODE + puts(":: C bytebeat generator: runtime unit"); + fflush(stdout); +#endif + +#if !SILENT_MODE + printf( + "\n" + "Sample rate: " INT2STR(SAMPLE_RATE) " Hz\n" + "Channels: " INT2STR(CHANNELS) +#if CHANNELS <= 2 + " (" +# if CHANNELS == 2 + "stereo" +# else + "mono" +# endif + ")" +#endif + "\n" + "Bit depth: " +#if !IS_SIGNED + "un" +#endif + "signed " INT2STR(BIT_DEPTH) "-bit" +#if BIT_DEPTH != ACTUAL_BIT_DEPTH + " -> " INT2STR(ACTUAL_BIT_DEPTH) "-bit" +#endif + "\n" + "Duration: "); + + print_time(RUNNING_LENGTH); + +#if REPEAT_TIMES > 0 + printf(", %llu times -> ", REPEAT_TIMES + 1); + print_time(RUNNING_LENGTH * (REPEAT_TIMES + 1)); +#endif + +#if INITIAL_TIME != 0 + printf("\nStart time: "); + print_time(INITIAL_TIME); +#endif puts( #if VERBOSE_MODE || SEQUENTIAL_MODE @@ -169,39 +213,47 @@ main(void) // * write WAVE headers // 0. log -#if SEQUENTIAL_MODE +#if VERBOSE_MODE puts("Writing WAVE headers..."); #endif // 1. open file - FILE* output_file = fopen(OUTPUT_FILE, "wb"); + FILE* output_file = fopen(OUTPUT_FILE, + "wb" +#if REPEAT_TIMES > 0 + "+" +#endif + ); if (output_file == NULL) { fflush(stdout); perror("fopen"); - return 1; + return EXIT_FAILURE; } // 2. prepare variables - uint32_t buffer_size = PRODUCT, + const uint32_t header_size = + 4 * 4 /* 4 strings of 4 characters */ + + 5 * 4 /* 5 uint32_t values */ + + 4 * 2 /* 4 uint16_t values */; + + uint32_t buffer_size = PRODUCT * (REPEAT_TIMES + 1), file_length = - 4 * 4 /* 4 strings of 4 characters */ + - 5 * 4 /* 4 uint32_t values */ + - 4 * 2 /* 5 uint16_t values */ + - PRODUCT /* sample data */ + header_size + + buffer_size /* sample data */ /* subtract Subchunk2 headers: */ - - 4 /* a 4-character string */ + - 4 /* a string of 4 characters */ - 4 /* a uint32_t value */, fmt_data_length = 16 /* <-- * length of format data before this value * in the file format structure */, sample_rate = SAMPLE_RATE, - byte_rate = (SAMPLE_RATE * BIT_DEPTH * CHANNELS) / 8; + byte_rate = (SAMPLE_RATE * ACTUAL_BIT_DEPTH * CHANNELS) / 8; uint16_t fmt_type = 1, // format type is PCM channels = CHANNELS, - block_align = (BIT_DEPTH * CHANNELS) / 8, - bit_depth = BIT_DEPTH > 8 ? BIT_DEPTH : 8; + block_align = (ACTUAL_BIT_DEPTH * CHANNELS) / 8, + bit_depth = ACTUAL_BIT_DEPTH; // 3. write headers // : : @@ -237,22 +289,23 @@ main(void) size_t calc_block_size = BLOCK_SIZE; ALLOCATE_MEMORY(calc_block_size) #else - ALLOCATE_MEMORY(PRODUCT) + ALLOCATE_MEMORY(GEN_LENGTH) #endif -#if SEQUENTIAL_MODE - const uintmax_t gen_length_minus_1 = GEN_LENGTH - 1, - bit_depth_limiter = BIT_DEPTH_LIMITER + const uintmax_t bit_depth_limiter = BIT_DEPTH_LIMITER #if FP_RETURN_TYPE - + 1 -#endif -#if BIT_DEPTH < 8 - , - bit_depth_stretch = ((long double) BIT_DEPTH) / 8.L + + 1 #endif ; - size_t time = 0; +#if BIT_DEPTH != ACTUAL_BIT_DEPTH + const long double bit_depth_stretch = + ((long double) BIT_DEPTH) / ACTUAL_BIT_DEPTH; +#endif + +#if SEQUENTIAL_MODE + size_t time = INITIAL_TIME; + for (size_t seq = 0; seq < MAX; seq++) { if ((time + BLOCK_SIZE) >= GEN_LENGTH) calc_block_size = GEN_LENGTH - time; @@ -260,34 +313,34 @@ main(void) // * bytebeat generating loop #if SEQUENTIAL_MODE - for (size_t idx = 0; idx < BLOCK_SIZE && time < GEN_LENGTH; idx++, + for (size_t idx = 0; idx < BLOCK_SIZE && time < LOOP_END; idx++, time++) { #else - for (size_t time = 0; time < GEN_LENGTH; time++) { + for (size_t time = INITIAL_TIME; time < LOOP_END; time++) { #endif // 1. generate audio data #if FP_RETURN_TYPE - long double bytebeat_res = - floor(bytebeat(floor((long double) time))); + bb_fp_return_t bytebeat_res = + floor(bytebeat(floor((bb_counter_t) time))); #elif IS_SIGNED intmax_t bytebeat_res = - (intmax_t) bytebeat(floor((long double) time)); + (intmax_t) bytebeat(floor((bb_counter_t) time)); #else uintmax_t bytebeat_res = - (uintmax_t) bytebeat(floor((long double) time)); + (uintmax_t) bytebeat(floor((bb_counter_t) time)); #endif - // 2. if signed, then wrap up to unsigned -#if IS_SIGNED + // 2. if signed and bit depth <= 8, then wrap up to unsigned +#if IS_SIGNED && (BIT_DEPTH <= 8) bytebeat_res = signed_to_unsigned(bytebeat_res); #endif // 3. convert audio data to sample SAMPLE_TYPE sample_res = (SAMPLE_TYPE) #if FP_RETURN_TYPE - fmodl(bytebeat_res, bit_depth_limiter); + fmod(bytebeat_res, BIT_DEPTH_LIMITER); #else - ((uintmax_t) bytebeat_res & bit_depth_limiter); + ((uintmax_t) bytebeat_res & BIT_DEPTH_LIMITER); #endif // 4. if bit depth is less than 8, stretch it @@ -297,25 +350,27 @@ main(void) #endif // 5. save sample into buffer + buffer[ #if SEQUENTIAL_MODE - buffer[idx] = sample_res; + idx #else - buffer[time] = sample_res; + time #endif + ] = sample_res; // 6. log #if VERBOSE_MODE if (time % FREQUENCY_OF_STATUS_REPORTING == 0 || - time >= gen_length_minus_1 /* or if writing last sample */) { + time >= LOOP_END_MINUS_1 /* or if writing last sample */) { printf( - "%sremaining samples = %18" PRIuMAX " (%3.2Lf%% done)" + "%sremaining samples = %18" PRIuMAX " (%6.2Lf%% done)" #if SEQUENTIAL_MODE " (part %" PRIuMAX "/%" PRIuMAX ")" #endif , _ANSI_CLEAR_STRING, - gen_length_minus_1 - time, - ((long double) time * 100) / (long double) GEN_LENGTH + LOOP_END_MINUS_1 - time, + ((long double) time * 100) / (long double) LOOP_END_MINUS_1 #if SEQUENTIAL_MODE , (uintmax_t) seq + 1, (uintmax_t) MAX #endif @@ -330,13 +385,13 @@ main(void) // 5. log #if !(SEQUENTIAL_MODE && VERBOSE_MODE) -#if SEQUENTIAL_MODE +# if SEQUENTIAL_MODE if (seq == 0) -#endif +# endif puts( -#if !SEQUENTIAL_MODE +# if !SEQUENTIAL_MODE "\n" -#endif +# endif "Writing out file " OUTPUT_FILE "..."); #endif fflush(stdout); @@ -347,7 +402,7 @@ main(void) #if SEQUENTIAL_MODE calc_block_size, #else - PRODUCT, + GEN_LENGTH, #endif output_file); #if SEQUENTIAL_MODE @@ -358,6 +413,43 @@ main(void) } #endif +#if REPEAT_TIMES > 0 + // * repeat as much as needed + + puts( +# if SEQUENTIAL_MODE + "\n" +# endif + "Repeating..."); + + for (size_t counter = 0; counter < REPEAT_TIMES; counter++) { +# if SEQUENTIAL_MODE + off_t position_read = header_size; + + calc_block_size = BLOCK_SIZE; + for (size_t seq = 0, time = 0; seq < MAX; seq++, time += BLOCK_SIZE) { + bool end = false; + if ((time + BLOCK_SIZE) >= GEN_LENGTH) { + calc_block_size = GEN_LENGTH - time; + end = true; + } + + fseeko(output_file, position_read, SEEK_SET); + fread(buffer, sizeof(SAMPLE_TYPE), calc_block_size, output_file); + fseeko(output_file, 0, SEEK_END); + fwrite(buffer, sizeof(SAMPLE_TYPE), calc_block_size, output_file); + + if (end) + break; + + position_read += calc_block_size; + } +# else + fwrite_le(buffer, sizeof(SAMPLE_TYPE), GEN_LENGTH, output_file); +# endif + } +#endif + // * free allocated heap free(buffer); @@ -367,11 +459,13 @@ main(void) // * end of program #if !SILENT_MODE puts( -#if SEQUENTIAL_MODE && VERBOSE_MODE +# if SEQUENTIAL_MODE && VERBOSE_MODE && REPEAT_TIMES == 0 "\n" -#endif +# endif "Done!"); #endif return EXIT_SUCCESS; } + +#endif /* _ERROR */ From ed7f2b2e6f11f20e20c3753e574a5c7a18431d88 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Mon, 27 May 2024 08:08:48 +0300 Subject: [PATCH 02/20] README.md: mark as WIP branch --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 03c5e51..f85fd04 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # C-JS-bytebeat-render +> **Warning** +> You're on a Work In Progress branch! + a bytebeat rendering engine in C (no support of JavaScript bytebeat yet) From 01043c8aff4dd710e60e40fa469bea9f22ba5e7e Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 1 Jun 2024 10:01:38 +0300 Subject: [PATCH 03/20] fwrite_le.*: rename `ifeq_u32_ret` to `ifeq_b32_ret` --- include/fwrite_le.h | 2 +- src/fwrite_le.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fwrite_le.h b/include/fwrite_le.h index ec04e87..69e52b1 100644 --- a/include/fwrite_le.h +++ b/include/fwrite_le.h @@ -15,7 +15,7 @@ #define ORDER_NATIVE_U32 0x01234567 #define ORDER_LITTLE_ENDIAN_S4 "\x67\x45\x23\x01" #define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" -#define ifeq_u32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; +#define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; int detect_endianness(void); size_t fwrite_le(void* ptr, size_t size, size_t count, FILE* stream); diff --git a/src/fwrite_le.c b/src/fwrite_le.c index 0fe8ec6..473124c 100644 --- a/src/fwrite_le.c +++ b/src/fwrite_le.c @@ -4,8 +4,8 @@ int detect_endianness(void) { volatile uint32_t native_order_value = ORDER_NATIVE_U32; uint8_t* as_bytes = (uint8_t*)&native_order_value; - ifeq_u32_ret(as_bytes, ORDER_LITTLE_ENDIAN_S4, DETECTED_LITTLE_ENDIAN); - ifeq_u32_ret(as_bytes, ORDER_BIG_ENDIAN_S4, DETECTED_BIG_ENDIAN ); + ifeq_b32_ret(as_bytes, ORDER_LITTLE_ENDIAN_S4, DETECTED_LITTLE_ENDIAN); + ifeq_b32_ret(as_bytes, ORDER_BIG_ENDIAN_S4, DETECTED_BIG_ENDIAN ); return UNSUPPORTED_ENDIANNESS; } From 886d555c71250cbad66f81a434cc860be551874f Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 1 Jun 2024 11:36:33 +0300 Subject: [PATCH 04/20] dual-license under Unlicense and CC0 --- COPYING | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 +- 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 COPYING diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/COPYING @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/README.md b/README.md index f85fd04..b802b7c 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,6 @@ > **Warning** > You're on a Work In Progress branch! -a bytebeat rendering engine in C (no support of JavaScript bytebeat yet) +Dual-licensed under the [Unlicense](http://unlicense.org) (`LICENSE`) or Creative Commons Zero 1.0 Universal (`COPYING`). + +**Description:** a bytebeat rendering engine in C (no support of JavaScript bytebeat yet) From 83046f14435c034bef8cefffc65b71944805d856 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 1 Jun 2024 11:45:27 +0300 Subject: [PATCH 05/20] bytebeat_compiler.py: reformat --- bytebeat_compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bytebeat_compiler.py b/bytebeat_compiler.py index dc9dcb4..25642dc 100644 --- a/bytebeat_compiler.py +++ b/bytebeat_compiler.py @@ -69,7 +69,7 @@ def read_from_file_or_stdin(path: str) -> str: raise SystemExit def substitute_vars(replacements: Dict[str, Union[bool, str]], text: str, - verbose: bool) -> str: + verbose: bool) -> str: if verbose: print("Substituting values:") for placeholder, replacement in replacements.items(): From 755336c1037ff94425739dcb8da937c85e00e1ee Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 2 Jun 2024 14:21:01 +0300 Subject: [PATCH 06/20] template.c: remove string junk: fixup --- src/template.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/template.c b/src/template.c index c7e0e8e..34eb1eb 100644 --- a/src/template.c +++ b/src/template.c @@ -201,12 +201,9 @@ main(void) print_time(INITIAL_TIME); #endif - puts( #if VERBOSE_MODE || SEQUENTIAL_MODE - "\n" + puts("\n"); #endif - "" - ); fflush(stdout); #endif From c6e126f2bdc8277b27f25bb6a163ebb17fbc3a53 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 2 Jun 2024 14:31:18 +0300 Subject: [PATCH 07/20] repeating: use `wb+` mode only in sequential mode --- src/template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/template.c b/src/template.c index 34eb1eb..7e7f341 100644 --- a/src/template.c +++ b/src/template.c @@ -217,7 +217,7 @@ main(void) // 1. open file FILE* output_file = fopen(OUTPUT_FILE, "wb" -#if REPEAT_TIMES > 0 +#if REPEAT_TIMES > 0 && SEQUENTIAL_MODE "+" #endif ); From ca282d20c86b52cc041e284d185eea7fc91c801b Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 2 Jun 2024 19:34:49 +0300 Subject: [PATCH 08/20] bytebeat_compiler.py: search for compiler, fix section names and reformat --- bytebeat_compiler.py | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/bytebeat_compiler.py b/bytebeat_compiler.py index 25642dc..a46376b 100644 --- a/bytebeat_compiler.py +++ b/bytebeat_compiler.py @@ -4,9 +4,10 @@ if __name__ == "__main__": print(":: C bytebeat generator: compiler unit") from argparse import ArgumentParser -from os import environ, makedirs +from os import environ, makedirs, name as os_name from os.path import exists, join as path_join from shlex import split as command_line_split +from shutil import which from sys import stdin, stdout, exit from typing import Dict, Union import re @@ -87,6 +88,18 @@ preprocessor_bool = lambda value: "1" if value else "0" C_str_repr = lambda s: '"' + s.replace("\\", "\\\\").replace(r'"', r'\"') + '"' CC = fetch("CC") + +CC_SEARCH_LIST = [ + "gcc", + "clang", + "tcc" +] +if os_name == "nt": + CC_SEARCH_LIST = [ + "msc", + *CC_SEARCH_LIST + ] + CFLAGS = fetch("CFLAGS") INPUT_FILE = fetch("INPUT_FILE") OUTPUT_FILE = fetch("OUTPUT_FILE") @@ -113,6 +126,9 @@ DEFAULT_ARGS = { "no_return": False } +is_cmd_available = lambda cmd: which(cmd) is not None +is_cmd_unavailable = lambda cmd: which(cmd) is None + if __name__ == "__main__": parser = ArgumentParser(description=\ "Substitutes supplied C (non-JavaScript!) bytebeat into the template, " @@ -333,10 +349,28 @@ if __name__ == "__main__": "ansi_escape_codes_supported": ansi_escape_codes_supported }, read_file(PATHS["template"]), args.show_substituted_values)) - # Compile by invoking the shell script + if is_cmd_unavailable(CC): + print(f"Compiler {CC} not available, searching:") + + still_unavailable = True + for compiler in CC_SEARCH_LIST: + print(f"* Trying CC={compiler}", end="") + if is_cmd_available(compiler): + print(": OK") + CC = compiler + still_unavailable = False + break + else: + print() + + if still_unavailable: + print("Could not find an available compiler. Please specify it by " + "setting\nenvironmental variable CC.") + exit(2) + + # Compile print("Compiling") - # Let the system execute aliases by calling os.system command = [ CC, *command_line_split(CFLAGS), @@ -346,4 +380,5 @@ if __name__ == "__main__": "-I" + PATHS["include_directory"] ] print(" ".join(command), flush=True) + exit(subprocess.run(command).returncode) From 160c40fc11b6c690d4da6afbd212ef148cb40db2 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 2 Jun 2024 23:31:46 +0300 Subject: [PATCH 09/20] template.c: merge exact, neighbor conditional compilation --- src/template.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/template.c b/src/template.c index 7e7f341..efe77fd 100644 --- a/src/template.c +++ b/src/template.c @@ -161,9 +161,7 @@ main(void) #if !SILENT_MODE puts(":: C bytebeat generator: runtime unit"); fflush(stdout); -#endif -#if !SILENT_MODE printf( "\n" "Sample rate: " INT2STR(SAMPLE_RATE) " Hz\n" From 6f99ea37e62aabe5991cb8c01c95cb72ad039a82 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Mon, 3 Jun 2024 00:19:08 +0300 Subject: [PATCH 10/20] template.c: silent mode fixes --- src/template.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/template.c b/src/template.c index efe77fd..0f5ea5a 100644 --- a/src/template.c +++ b/src/template.c @@ -208,7 +208,7 @@ main(void) // * write WAVE headers // 0. log -#if VERBOSE_MODE +#if !SILENT_MODE && VERBOSE_MODE puts("Writing WAVE headers..."); #endif @@ -271,8 +271,10 @@ main(void) size_t BLOCK_SIZE = BLOCK_SIZE_BYTES / (sizeof(SAMPLE_TYPE) / sizeof(uint8_t)); if (BLOCK_SIZE < 1) { +# if !SILENT_MODE printf("The block size " INT2STR(BLOCK_SIZE_BYTES) " is too small, " "should be at least %" PRIuMAX " bytes\n", MINIMUM_BLOCK_SIZE); +# endif return EXIT_FAILURE; } @@ -411,11 +413,13 @@ main(void) #if REPEAT_TIMES > 0 // * repeat as much as needed +# if !SILENT_MODE puts( -# if SEQUENTIAL_MODE +# if SEQUENTIAL_MODE "\n" -# endif +# endif "Repeating..."); +# endif for (size_t counter = 0; counter < REPEAT_TIMES; counter++) { # if SEQUENTIAL_MODE From 505812da6c23b1a5365b859ae046bc454f322fae Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Mon, 3 Jun 2024 00:29:45 +0300 Subject: [PATCH 11/20] template.c: output all errors to STDERR --- src/template.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/template.c b/src/template.c index 0f5ea5a..025b2f3 100644 --- a/src/template.c +++ b/src/template.c @@ -272,8 +272,9 @@ main(void) sizeof(uint8_t)); if (BLOCK_SIZE < 1) { # if !SILENT_MODE - printf("The block size " INT2STR(BLOCK_SIZE_BYTES) " is too small, " - "should be at least %" PRIuMAX " bytes\n", MINIMUM_BLOCK_SIZE); + fprintf(stderr, "The block size " INT2STR(BLOCK_SIZE_BYTES) " is too " + "small, should be at least %" PRIuMAX " bytes\n", + MINIMUM_BLOCK_SIZE); # endif return EXIT_FAILURE; } From 2ddc87b226535ef7efd3749427383445ecc0588d Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Tue, 18 Jun 2024 18:14:05 +0300 Subject: [PATCH 12/20] fwrite_le.h: move `#include`s inside the `#ifdef` block --- include/fwrite_le.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fwrite_le.h b/include/fwrite_le.h index 69e52b1..76127a3 100644 --- a/include/fwrite_le.h +++ b/include/fwrite_le.h @@ -1,11 +1,11 @@ +#ifndef _FWRITE_LE_H +#define _FWRITE_LE_H + #include #include #include #include -#ifndef _FWRITE_LE_H -#define _FWRITE_LE_H - #define FWRITE_LE_NO_MODIFICATION 0 #define DETECTED_LITTLE_ENDIAN 0 From bbb7b2a476618dd9c1b0ce61d7491095b7145a37 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Tue, 18 Jun 2024 18:15:32 +0300 Subject: [PATCH 13/20] fwrite_le.*: make use of `const` for `ptr` --- include/fwrite_le.h | 6 +++++- src/fwrite_le.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/fwrite_le.h b/include/fwrite_le.h index 76127a3..6eb6fd1 100644 --- a/include/fwrite_le.h +++ b/include/fwrite_le.h @@ -18,7 +18,11 @@ #define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; int detect_endianness(void); -size_t fwrite_le(void* ptr, size_t size, size_t count, FILE* stream); +size_t fwrite_le( +#if FWRITE_LE_NO_MODIFICATION + const +#endif + void* ptr, size_t size, size_t count, FILE* stream); void reorder_le_be( #if FWRITE_LE_NO_MODIFICATION uint8_t* dest, uint8_t* src, diff --git a/src/fwrite_le.c b/src/fwrite_le.c index 473124c..e9beb3f 100644 --- a/src/fwrite_le.c +++ b/src/fwrite_le.c @@ -37,7 +37,11 @@ void reorder_le_be( } } -size_t fwrite_le(void* ptr, size_t size, size_t count, FILE* stream) { +size_t fwrite_le( +#if FWRITE_LE_NO_MODIFICATION + const +#endif + void* ptr, size_t size, size_t count, FILE* stream) { /* * warning: this function modifies `void* ptr` by default! * (if FWRITE_LE_NO_MODIFICATION in the header is 0) From 7a107a85de9f898419440176e17417948c238cd6 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Fri, 5 Jul 2024 15:21:01 +0300 Subject: [PATCH 14/20] fwrite_le.h: reduce scope of private macros --- include/fwrite_le.h | 5 ----- src/fwrite_le.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fwrite_le.h b/include/fwrite_le.h index 6eb6fd1..58d6ef6 100644 --- a/include/fwrite_le.h +++ b/include/fwrite_le.h @@ -12,11 +12,6 @@ #define DETECTED_BIG_ENDIAN 1 #define UNSUPPORTED_ENDIANNESS -1 -#define ORDER_NATIVE_U32 0x01234567 -#define ORDER_LITTLE_ENDIAN_S4 "\x67\x45\x23\x01" -#define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" -#define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; - int detect_endianness(void); size_t fwrite_le( #if FWRITE_LE_NO_MODIFICATION diff --git a/src/fwrite_le.c b/src/fwrite_le.c index e9beb3f..4a3b4cc 100644 --- a/src/fwrite_le.c +++ b/src/fwrite_le.c @@ -1,5 +1,10 @@ #include "fwrite_le.h" +#define ORDER_NATIVE_U32 0x01234567 +#define ORDER_LITTLE_ENDIAN_S4 "\x67\x45\x23\x01" +#define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" +#define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; + int detect_endianness(void) { volatile uint32_t native_order_value = ORDER_NATIVE_U32; uint8_t* as_bytes = (uint8_t*)&native_order_value; From 59b29e395274163b81eba13dce26aa674c71993f Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 6 Jul 2024 17:33:56 +0300 Subject: [PATCH 15/20] README.md: reformat --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b802b7c..f5e8e74 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ > **Warning** > You're on a Work In Progress branch! -Dual-licensed under the [Unlicense](http://unlicense.org) (`LICENSE`) or Creative Commons Zero 1.0 Universal (`COPYING`). +Dual-licensed under the [Unlicense](http://unlicense.org) (`LICENSE`) or +Creative Commons Zero 1.0 Universal (`COPYING`). -**Description:** a bytebeat rendering engine in C (no support of JavaScript bytebeat yet) +**Description:** a bytebeat rendering engine in C (no support of JavaScript +bytebeat yet) From 32665b01685527eb9afbcddf44e79790662b3060 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 6 Jul 2024 17:35:27 +0300 Subject: [PATCH 16/20] README.md: improve license information and reformat --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f5e8e74..096259a 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,11 @@ > **Warning** > You're on a Work In Progress branch! -Dual-licensed under the [Unlicense](http://unlicense.org) (`LICENSE`) or -Creative Commons Zero 1.0 Universal (`COPYING`). - **Description:** a bytebeat rendering engine in C (no support of JavaScript bytebeat yet) + +## License + +Dual-licensed under the [Unlicense](http://unlicense.org) +([`LICENSE`](LICENSE)) and Creative Commons Zero 1.0 Universal +([`COPYING`](COPYING)). From 391467806eb411db7aa0a886ddf5a430c28fa5f1 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 13 Jul 2024 22:35:33 +0300 Subject: [PATCH 17/20] template.c: extract `BITS_PER_BYTE` --- src/template.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/template.c b/src/template.c index 025b2f3..86c4f10 100644 --- a/src/template.c +++ b/src/template.c @@ -35,9 +35,9 @@ typedef long double bb_fp_return_t; #define CHANNELS `channels` #define RUNNING_LENGTH `running_length` -#if BIT_DEPTH <= 8 -# define ACTUAL_BIT_DEPTH 8 - +#define BITS_PER_BYTE 8 +#if BIT_DEPTH <= BITS_PER_BYTE +# define ACTUAL_BIT_DEPTH BITS_PER_BYTE # define SAMPLE_TYPE uint8_t #elif BIT_DEPTH <= 16 # define ACTUAL_BIT_DEPTH 16 @@ -244,10 +244,10 @@ main(void) * in the file format structure */, sample_rate = SAMPLE_RATE, - byte_rate = (SAMPLE_RATE * ACTUAL_BIT_DEPTH * CHANNELS) / 8; + byte_rate = (SAMPLE_RATE * ACTUAL_BIT_DEPTH * CHANNELS) / BITS_PER_BYTE; uint16_t fmt_type = 1, // format type is PCM channels = CHANNELS, - block_align = (ACTUAL_BIT_DEPTH * CHANNELS) / 8, + block_align = (ACTUAL_BIT_DEPTH * CHANNELS) / BITS_PER_BYTE, bit_depth = ACTUAL_BIT_DEPTH; // 3. write headers @@ -341,8 +341,8 @@ main(void) ((uintmax_t) bytebeat_res & BIT_DEPTH_LIMITER); #endif - // 4. if bit depth is less than 8, stretch it -#if BIT_DEPTH < 8 + // 4. if bit depth is less than BITS_PER_BYTE, stretch it +#if BIT_DEPTH < BITS_PER_BYTE sample_res = (SAMPLE_TYPE) ((long double) sample_res * bit_depth_stretch); #endif From 17be3d4b7382d58a30331f598ced9df4ce3f9b06 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sat, 13 Jul 2024 22:39:36 +0300 Subject: [PATCH 18/20] template.c: simplify `file_length` calculation --- src/template.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/template.c b/src/template.c index 86c4f10..19b6d3d 100644 --- a/src/template.c +++ b/src/template.c @@ -227,18 +227,12 @@ main(void) // 2. prepare variables const uint32_t header_size = - 4 * 4 /* 4 strings of 4 characters */ + - 5 * 4 /* 5 uint32_t values */ + + 3 * 4 /* 3 strings of 4 characters: "WAVE", "fmt ", "data" */ + + 4 * 4 /* 4 uint32_t values */ + 4 * 2 /* 4 uint16_t values */; uint32_t buffer_size = PRODUCT * (REPEAT_TIMES + 1), - file_length = - header_size + - buffer_size /* sample data */ - - /* subtract Subchunk2 headers: */ - - 4 /* a string of 4 characters */ - - 4 /* a uint32_t value */, + file_length = header_size + buffer_size, fmt_data_length = 16 /* <-- * length of format data before this value * in the file format structure From 178755aa587fea1ecb78917a5e4a682d13233eaf Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 14 Jul 2024 00:11:31 +0300 Subject: [PATCH 19/20] fwrite_le.c: use `malloc` instead of `calloc` --- src/fwrite_le.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fwrite_le.c b/src/fwrite_le.c index 4a3b4cc..748de52 100644 --- a/src/fwrite_le.c +++ b/src/fwrite_le.c @@ -65,9 +65,9 @@ size_t fwrite_le( // case: big-endian size_t bytes_count = size * count; #if FWRITE_LE_NO_MODIFICATION - uint8_t* bytes = calloc(bytes_count, sizeof(uint8_t)); + uint8_t* bytes = malloc(bytes_count, sizeof(uint8_t)); if (bytes == NULL) { - perror("calloc"); + perror("malloc"); exit(EXIT_FAILURE); } memcpy(bytes, ptr, bytes_count); From 74b9bec9c65fdaa7152353b193c5c2d00e7fc4b7 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Sun, 14 Jul 2024 00:13:25 +0300 Subject: [PATCH 20/20] bytebeat_compiler.py: extract `BITS_PER_BYTE` --- bytebeat_compiler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bytebeat_compiler.py b/bytebeat_compiler.py index a46376b..ca2fabb 100644 --- a/bytebeat_compiler.py +++ b/bytebeat_compiler.py @@ -13,6 +13,9 @@ from typing import Dict, Union import re import subprocess +# Definitions +BITS_PER_BYTE = 8 + # Paths PATHS = { "src_dir": "src", @@ -339,7 +342,7 @@ if __name__ == "__main__": "loop_end_minus_1": loop_end - 1, "initial_time": skip_first_samples, "repeat_times": args.repeat, - "wav_product": gen_length * (args.bit_depth // 8), + "wav_product": gen_length * (args.bit_depth // BITS_PER_BYTE), "gen_length": gen_length, "sequential_mode": args.mode == "sequential", "block_size": args.block_size,