1
0
C-bytebeat-render/bytebeat_compiler.py

100 lines
3.3 KiB
Python
Raw Normal View History

2023-11-17 00:31:41 +05:30
#!/usr/bin/python3
DEFAULT_PARAMETERS = {
"CC": "gcc",
"CC_FLAGS": "-Os -Wall -Werror -Wpedantic",
"INPUT_FILES": ["engine.c", "formula_substituted.c"],
"OUTPUT_FILE": "render_bytebeat"
}
from os.path import exists
from os import system, environ
from argparse import ArgumentParser
from sys import stdin
import subprocess
def fetch(name: str):
return res if (res := environ.get(name)) else DEFAULT_PARAMETERS[name]
def read_file(path: str) -> str:
return open(path, "r", encoding="utf-8-sig").read()
def rewrite_file(path: str, content: str):
return open(path, "w", encoding="utf-8-sig").write(content)
def read_from_file_or_stdin(path: str) -> str:
if path == "-":
return "\n".join(stdin)
elif exists(path):
return read_file(path)
else:
print("The specified file doesn't exist")
raise SystemExit
def substitute_value(placeholder: str, replacement, text: str) -> str:
return text.replace(f"`{placeholder}`", str(replacement))
CC = fetch("CC")
CC_FLAGS = fetch("CC_FLAGS")
INPUT_FILES = fetch("INPUT_FILES")
OUTPUT_FILE = fetch("OUTPUT_FILE")
if __name__ == "__main__":
print("Bytebeat compiler")
parser = ArgumentParser(description=\
"Substitutes supplied C (non-JavaScript!) bytebeat into the template, "
"then attempts to compile the instance of the template. Uses "
"environmental variables `CC`, `CC_FLAGS`, `INPUT_FILES`, "
"`OUTPUT_FILE`.")
parser.add_argument("file", type=str,
help="bytebeat formula file")
parser.add_argument("-r", "--sample-rate", default=8000, type=int,
help="sample rate (Hz)")
parser.add_argument("-b", "--bit-depth", default=8, type=int,
help="bit depth")
parser.add_argument("-s", "--signed", default=False, action="store_true",
help="is signed?")
parser.add_argument("-c", "--channels", default=1, type=int,
help="amount of channels")
parser.add_argument("-t", "--seconds", default=30, type=int,
help="length (seconds)")
parser.add_argument("-a", "--no-return", default=False, action="store_true",
help="do not insert return statement before the code")
args = parser.parse_args()
bytebeat_contents = read_from_file_or_stdin(args.file).strip()
if not bytebeat_contents:
print("No valid contents")
raise SystemExit
# Substitute all placeholders in formula_template.c -> formula_substitute.c
if not args.no_return: # Insert return statement
bytebeat_contents = f"\treturn\n\n{bytebeat_contents}"
substitute_c = read_file("formula_template.c")
substitute_c = substitute_value("bytebeat_contents",
bytebeat_contents, substitute_c)
rewrite_file("formula_substituted.c", substitute_c)
# Substitute all placeholders in formula_template.h -> formula_substitute.h
substitute_h = read_file("formula_template.h")
substitute_h = substitute_value("sample_rate",
args.sample_rate, substitute_h)
substitute_h = substitute_value("bit_depth",
args.bit_depth, substitute_h)
substitute_h = substitute_value("is_signed",
"1" if args.signed else "0", substitute_h)
substitute_h = substitute_value("channels",
args.channels, substitute_h)
substitute_h = substitute_value("seconds",
args.seconds, substitute_h)
rewrite_file("formula_substituted.h", substitute_h)
# Compile by invoking the shell script
print("Compiling")
# Let system execute aliases by calling os.system
system(" ".join([CC, CC_FLAGS, *INPUT_FILES, "-o", OUTPUT_FILE]))