diff --git a/auto_editor/analyze.py b/auto_editor/analyze.py index 03d53acea..4f6a3db70 100644 --- a/auto_editor/analyze.py +++ b/auto_editor/analyze.py @@ -149,16 +149,14 @@ def obj_tag(tag: str, tb: Fraction, obj: dict[str, Any]) -> str: return key +@dataclass class Levels: - def __init__( - self, ensure: Ensure, src: FileInfo, tb: Fraction, bar: Bar, temp: str, log: Log - ): - self.ensure = ensure - self.src = src - self.tb = tb - self.bar = bar - self.temp = temp - self.log = log + ensure: Ensure + src: FileInfo + tb: Fraction + bar: Bar + temp: str + log: Log @property def media_length(self) -> int: @@ -167,9 +165,7 @@ def media_length(self) -> int: return len(arr) sr, samples = read( - self.ensure.audio( - f"{self.src.path.resolve()}", self.src.label, stream=0 - ) + self.ensure.audio(f"{self.src.path.resolve()}", self.src.label, 0) ) samp_count = len(samples) del samples diff --git a/auto_editor/lang/palet.py b/auto_editor/lang/palet.py index 2b64efadb..0d0401358 100644 --- a/auto_editor/lang/palet.py +++ b/auto_editor/lang/palet.py @@ -49,7 +49,7 @@ class ClosingError(MyError): LPAREN, RPAREN, LBRAC, RBRAC, LCUR, RCUR, EOF = "(", ")", "[", "]", "{", "}", "EOF" VAL, QUOTE, SEC, DB, DOT, VLIT = "VAL", "QUOTE", "SEC", "DB", "DOT", "VLIT" SEC_UNITS = ("s", "sec", "secs", "second", "seconds") -METHODS = ("audio:", "motion:", "pixeldiff:", "subtitle:", "none:", "all/e:") +METHODS = ("audio:", "motion:", "pixeldiff:", "subtitle:") brac_pairs = {LPAREN: RPAREN, LBRAC: RBRAC, LCUR: RCUR} str_escape = { @@ -1334,6 +1334,20 @@ def attr(env: Env, node: list) -> Any: return my_eval(env, [node[2], node[1]]) +def edit_none() -> np.ndarray: + if "@levels" not in env: + raise MyError("Can't use `none` if there's no input media") + + return env["@levels"].none() + + +def edit_all() -> np.ndarray: + if "@levels" not in env: + raise MyError("Can't use `all/e` if there's no input media") + + return env["@levels"].all() + + def my_eval(env: Env, node: object) -> Any: if type(node) is Sym: val = env.get(node.val) @@ -1392,6 +1406,9 @@ def my_eval(env: Env, node: object) -> Any: "true": True, "false": False, "all": Sym("all"), + # edit procedures + "none": Proc("none", edit_none, (0, 0)), + "all/e": Proc("all/e", edit_all, (0, 0)), # syntax "lambda": Syntax(syn_lambda), "λ": Syntax(syn_lambda), diff --git a/auto_editor/make_layers.py b/auto_editor/make_layers.py index 7e334eaea..c33c54149 100644 --- a/auto_editor/make_layers.py +++ b/auto_editor/make_layers.py @@ -6,7 +6,7 @@ import numpy as np -from auto_editor.analyze import FileSetup +from auto_editor.analyze import FileSetup, Levels from auto_editor.ffwrapper import FFmpeg, FileInfo from auto_editor.lang.palet import Lexer, Parser, env, interpret, is_boolarr from auto_editor.lib.data_structs import print_str @@ -90,31 +90,40 @@ def make_av( return vtl, atl -def run_interpreter( - text: str, - filesetup: FileSetup, - log: Log, +def run_interpreter_for_edit_option( + text: str, filesetup: FileSetup ) -> NDArray[np.bool_]: + ensure = filesetup.ensure + src = filesetup.src + tb = filesetup.tb + bar = filesetup.bar + temp = filesetup.temp + log = filesetup.log + try: parser = Parser(Lexer("`--edit`", text)) if log.is_debug: log.debug(f"edit: {parser}") env["timebase"] = filesetup.tb + env["@levels"] = Levels(ensure, src, tb, bar, temp, log) env["@filesetup"] = filesetup results = interpret(env, parser) - except (MyError, ZeroDivisionError) as e: - log.error(e) - if len(results) == 0: - log.error("Expression in --edit must return a bool-array, got nothing") + if len(results) == 0: + raise MyError("Expression in --edit must return a bool-array, got nothing") - result = results[-1] - if not is_boolarr(result): - log.error( - f"Expression in --edit must return a bool-array, got {print_str(result)}" - ) + result = results[-1] + if callable(result): + result = result() + + if not is_boolarr(result): + raise MyError( + f"Expression in --edit must return a bool-array, got {print_str(result)}" + ) + except MyError as e: + log.error(e) assert isinstance(result, np.ndarray) return result @@ -276,7 +285,7 @@ def mut_set_range(arr: NDArray, _ranges: list[list[str]], index: Any) -> None: for i in map(str, inputs): filesetup = FileSetup(sources[i], ensure, len(inputs) < 2, tb, bar, temp, log) - has_loud = run_interpreter(method, filesetup, log) + has_loud = run_interpreter_for_edit_option(method, filesetup) if len(mark_loud) > 0: mut_set_range(has_loud, mark_loud, loud_speed) diff --git a/auto_editor/subcommands/repl.py b/auto_editor/subcommands/repl.py index 9e5b9ef48..af49fa4f5 100644 --- a/auto_editor/subcommands/repl.py +++ b/auto_editor/subcommands/repl.py @@ -5,7 +5,7 @@ from fractions import Fraction import auto_editor -from auto_editor.analyze import FileSetup +from auto_editor.analyze import FileSetup, Levels from auto_editor.ffwrapper import FFmpeg, FileInfo from auto_editor.lang.palet import ClosingError, Lexer, Parser, env, interpret from auto_editor.lib.data_structs import print_str @@ -77,9 +77,10 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None: src = sources["0"] tb = src.get_fps() if args.timebase is None else args.timebase ensure = Ensure(ffmpeg, src.get_sr(), temp, log) - filesetup = FileSetup(src, ensure, strict, tb, Bar("none"), temp, log) + bar = Bar("none") env["timebase"] = tb - env["@filesetup"] = filesetup + env["@levels"] = Levels(ensure, src, tb, bar, temp, log) + env["@filesetup"] = FileSetup(src, ensure, strict, tb, bar, temp, log) print(f"Auto-Editor {auto_editor.version} ({auto_editor.__version__})") text = None