diff --git a/bytebeat_compiler.py b/bytebeat_compiler.py index bd018b0..57d9097 100644 --- a/bytebeat_compiler.py +++ b/bytebeat_compiler.py @@ -124,6 +124,11 @@ if __name__ == "__main__": "default = +0 samples") parser.add_argument("-a", "--no-return", default=False, action="store_true", help="do not insert return statement before the code") + 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, + help="sequential mode only: block size of each sequence, bytes") parser.add_argument("-q", "--silent", default=False, action="store_true", help="do not output anything during generation") parser.add_argument("-v", "--verbose", default=False, action="store_true", @@ -186,6 +191,9 @@ if __name__ == "__main__": print("CLI: Count of samples should be greater than zero.") raise SystemExit + if args.mode != "sequential" and args.mode != "instant": + print("Invalid mode '%s'" % args.mode) + rewrite_file(PATHS["substitute"], substitute_vars({ "bytebeat_contents": bytebeat_contents, "output_file": C_str_repr(args.output), @@ -199,6 +207,8 @@ if __name__ == "__main__": "fp_return_type": args.floating_point, "channels": args.channels, "length": samples, + "sequential_mode": args.mode == "sequential", + "block_size": args.block_size, "silent_mode": args.silent, "verbose_mode": args.verbose and not args.silent, "fwrite_le": "../" + PATHS["fwrite_le_header"] diff --git a/src/template.c b/src/template.c index 07ffe37..0b88c7a 100644 --- a/src/template.c +++ b/src/template.c @@ -41,6 +41,9 @@ const char* ANSI_CLEAR = __ANSI_CLEAR_STRING; #define PRODUCT (LENGTH * CHANNELS) #define FREQUENCY_OF_STATUS_REPORTING 5000 +#define SEQUENTIAL_MODE `sequential_mode` +#define BLOCK_SIZE_BYTES `block_size` + #define FP_RETURN_TYPE `fp_return_type` #define PRECALCULATED_RATIO `precalculated_ratio` @@ -71,8 +74,12 @@ bytebeat(long double w) { #if PRECALCULATED_RATIO `final_sample_rate_code` -#else +#elif ORIGINAL_SAMPLE_RATE != SAMPLE_RATE +# if SAMPLE_RATE > ORIGINAL_SAMPLE_RATE w /= ((long double) SAMPLE_RATE) / ((long double) ORIGINAL_SAMPLE_RATE); +# else + w *= ((long double) ORIGINAL_SAMPLE_RATE / ((long double) SAMPLE_RATE)); +# endif #endif uintmax_t t = (uintmax_t) w; `bytebeat_contents`; @@ -122,7 +129,7 @@ main(void) printf("%" PRIuMAX " samples", samples); printf( -#if VERBOSE_MODE +#if VERBOSE_MODE || SEQUENTIAL_MODE "\n" #endif "\n" @@ -132,6 +139,11 @@ main(void) #endif // * write WAVE headers + // 0. log +#if SEQUENTIAL_MODE + printf("Writing WAVE headers...\n"); +#endif + // 1. open file FILE* output_file = fopen(OUTPUT_FILE, "wb"); if (output_file == NULL) { @@ -146,10 +158,10 @@ main(void) 5 * 4 /* 4 uint32_t values */ + 4 * 2 /* 5 uint16_t values */ + PRODUCT /* sample data */, - fmt_data_length = 16 /* - * length of format data before this value - * in the file format structure - */, + 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; uint16_t fmt_type = 1, // format type is PCM @@ -174,93 +186,155 @@ main(void) fwrite_le(&buffer_size, 4, 1, output_file); // L : Subchunk2Size : 4 // 4. write sample data - // * allocate heap for sample data - SAMPLE_TYPE* buffer = calloc(PRODUCT, sizeof(SAMPLE_TYPE)); - - if (buffer == NULL) { - perror("calloc"); - return 1; +#if SEQUENTIAL_MODE + const size_t BLOCK_SIZE = BLOCK_SIZE_BYTES / (sizeof(SAMPLE_TYPE) / + sizeof(uint8_t)); + if (BLOCK_SIZE < 1) { + printf("The block size %" PRIuMAX " is too small, should be at least " + "%" PRIuMAX " bytes\n", (uintmax_t) BLOCK_SIZE_BYTES, + (uintmax_t) (sizeof(SAMPLE_TYPE) / sizeof(uint8_t))); + exit(EXIT_FAILURE); } + const size_t MAX = (PRODUCT + (BLOCK_SIZE - 1)) / BLOCK_SIZE; - // * bytebeat generating loop - const uintmax_t product_minus_1 = PRODUCT - 1, - 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 -#endif - ; - - for (size_t w = 0; w < PRODUCT; w++) { - // 1. generate audio data -#if FP_RETURN_TYPE - long double bytebeat_res = floor(bytebeat((long double) floor(w))); -#elif IS_SIGNED - intmax_t bytebeat_res = (intmax_t) bytebeat(floor((long double) w)); + size_t w = 0; + for (size_t seq = 0; seq < MAX; seq++) { #else - uintmax_t bytebeat_res = (uintmax_t) bytebeat(floor((long double) w)); + do { #endif + size_t calc_block_size = BLOCK_SIZE; + if ((w + BLOCK_SIZE) >= PRODUCT) + calc_block_size = PRODUCT - w; - // 2. if signed, then wrap up into unsigned -#if IS_SIGNED - 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); + // * allocate heap for sample data + SAMPLE_TYPE* buffer = calloc( +#if SEQUENTIAL_MODE + calc_block_size, #else - ((uintmax_t) bytebeat_res & bit_depth_limiter); + PRODUCT, #endif + sizeof(SAMPLE_TYPE)); - // 4. if bit depth is less than 8, stretch it -#if BIT_DEPTH < 8 - sample_res = (SAMPLE_TYPE) - ((long double) sample_res * bit_depth_stretch); -#endif - - // 5. save sample into buffer - buffer[w] = sample_res; - - // 6. log -#if VERBOSE_MODE - if (w % FREQUENCY_OF_STATUS_REPORTING == 0 || - w >= product_minus_1 /* or if writing last sample */) { - printf( - "%sremaining samples = %18" PRIuMAX " (%.2Lf%% done)", - ANSI_CLEAR, - product_minus_1 - w, - ((long double) w * 100) / (long double) PRODUCT); - fflush(stdout); + if (buffer == NULL) { + perror("calloc"); + return 1; } + + // * bytebeat generating loop + const uintmax_t product_minus_1 = PRODUCT - 1, + 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 +#endif + ; + +#if SEQUENTIAL_MODE + size_t idx = 0; + for (; idx < BLOCK_SIZE && w < PRODUCT; idx++, w++) { +#else + for (size_t w = 0; w < PRODUCT; w++) { +#endif + // 1. generate audio data +#if FP_RETURN_TYPE + long double bytebeat_res = floor(bytebeat((long double) floor(w))); +#elif IS_SIGNED + intmax_t bytebeat_res = (intmax_t) bytebeat(floor((long double) w)); +#else + uintmax_t bytebeat_res = (uintmax_t) bytebeat(floor((long double) w)); +#endif + + // 2. if signed, then wrap up into unsigned +#if IS_SIGNED + 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); +#else + ((uintmax_t) bytebeat_res & bit_depth_limiter); +#endif + + // 4. if bit depth is less than 8, stretch it +#if BIT_DEPTH < 8 + sample_res = (SAMPLE_TYPE) + ((long double) sample_res * bit_depth_stretch); +#endif + + // 5. save sample into buffer +#if SEQUENTIAL_MODE + buffer[idx] = sample_res; +#else + buffer[w] = sample_res; +#endif + + // 6. log +#if VERBOSE_MODE + if (w % FREQUENCY_OF_STATUS_REPORTING == 0 || + w >= product_minus_1 /* or if writing last sample */) { + printf( + "%sremaining samples = %18" PRIuMAX " (%.2Lf%% done)", + ANSI_CLEAR, + product_minus_1 - w, + ((long double) w * 100) / (long double) PRODUCT); + fflush(stdout); + } +#endif + } #if !SILENT_MODE - printf("%s", ANSI_CLEAR); + printf("%s", ANSI_CLEAR); - // 5. log - printf("\nWriting out file " OUTPUT_FILE "...\n"); - fflush(stdout); + // 5. log +#if SEQUENTIAL_MODE + printf("Writing out file " OUTPUT_FILE " (part %" PRIuMAX "/%" + PRIuMAX ", %.2Lf%%)...\n", (uintmax_t) seq + 1, + (uintmax_t) MAX, + ((long double) seq * 100.L) / ((long double) MAX)); +#else + printf("\nWriting out file " OUTPUT_FILE "...\n"); +#endif + fflush(stdout); #endif - // * save the sample data into the file - fwrite_le(buffer, sizeof(SAMPLE_TYPE), buffer_size, output_file); + // * save the sample data into the file + fwrite_le(buffer, sizeof(SAMPLE_TYPE), +#if SEQUENTIAL_MODE + calc_block_size, +#else + PRODUCT, +#endif + output_file); +#if SEQUENTIAL_MODE + fflush(output_file); +#endif + +#if SEQUENTIAL_MODE + // * free allocated heap + free(buffer); +#endif + } +#if !SEQUENTIAL_MODE + while (0); +#endif // 6. close file fclose(output_file); +#if !SEQUENTIAL_MODE + // * free allocated heap + free(buffer); +#endif + // * end of program #if !SILENT_MODE printf("Done!\n"); #endif - // * free allocated heap - free(buffer); - return 0; }