From 229f6d646b0bbca099f42c16f47671f43d5fa4d6 Mon Sep 17 00:00:00 2001 From: Jamie Hardt Date: Tue, 16 Dec 2025 12:37:16 -0800 Subject: [PATCH] FRMT implementation --- pycmx/edit.py | 11 +++++++++-- pycmx/event.py | 7 ++++++- pycmx/parse_cmx_statements.py | 3 +-- tests/test_parse.py | 18 +++++++++++++++++- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/pycmx/edit.py b/pycmx/edit.py index 992f952..57bd7a5 100644 --- a/pycmx/edit.py +++ b/pycmx/edit.py @@ -1,7 +1,7 @@ # pycmx # (c) 2018 Jamie Hardt -from pycmx.statements import StmtCdlSat, StmtCdlSop +from pycmx.statements import StmtCdlSat, StmtCdlSop, StmtFrmc from .transition import Transition from .channel_map import ChannelMap @@ -26,7 +26,7 @@ class Edit: self.trans_name_statement = trans_name_statement self.asc_sop_statement: Optional[StmtCdlSop] = asc_sop_statement self.asc_sat_statement: Optional[StmtCdlSat] = asc_sat_statement - self.frmc_statement = frmc_statement + self.frmc_statement: Optional[StmtFrmc] = frmc_statement @property def line_number(self) -> int: @@ -150,3 +150,10 @@ class Edit: Get ASC CDL saturation value for clip, if present """ return self.asc_sat_statement + + @property + def frmc(self) -> Optional[StmtFrmc]: + """ + Get FRMC data + """ + return self.frmc_statement diff --git a/pycmx/event.py b/pycmx/event.py index c9d0437..57f97e2 100644 --- a/pycmx/event.py +++ b/pycmx/event.py @@ -1,6 +1,7 @@ # pycmx # (c) 2023 Jamie Hardt +from pycmx.statements import StmtFrmc from .parse_cmx_statements import ( StmtEvent, StmtClipName, StmtSourceFile, StmtAudioExt, StmtUnrecognized, StmtEffectsName, StmtCdlSop, StmtCdlSat) @@ -76,7 +77,8 @@ class Event: source_file_statement=s1, trans_name_statement=u1, asc_sop_statement=self._asc_sop_statement(), - asc_sat_statement=self._asc_sat_statement()) + asc_sat_statement=self._asc_sat_statement(), + frmc_statement=self._frmc_statement()) for (e1, n1, s1, u1) in zip(*the_zip)] @property @@ -116,3 +118,6 @@ class Event: def _asc_sat_statement(self) -> Optional[StmtCdlSat]: return next((s for s in self.statements if type(s) is StmtCdlSat), None) + + def _frmc_statement(self) -> Optional[StmtFrmc]: + return next((s for s in self.statements if type(s) is StmtFrmc), None) diff --git a/pycmx/parse_cmx_statements.py b/pycmx/parse_cmx_statements.py index 73bcf63..ee96ed9 100644 --- a/pycmx/parse_cmx_statements.py +++ b/pycmx/parse_cmx_statements.py @@ -136,8 +136,7 @@ def _parse_remark(line, line_number) -> object: elif line.startswith("FRMC"): match = re.match( r'^FRMC START:\s*(\d+)\s+FRMC END:\s*(\d+)' - r'\s+FRMC DURATION:\s*(\d+)', - line) + r'\s+FRMC DURATION:\s*(\d+)', line, re.IGNORECASE) if match is None: return StmtRemark(line, line_number) diff --git a/tests/test_parse.py b/tests/test_parse.py index 2ba4e9a..598e0d7 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -159,4 +159,20 @@ class TestParse(TestCase): edl = pycmx.parse_cmx3600(f) for event in edl.events: if event.number == 1: - ... + frmc = event.edits[0].frmc_statement + self.assertIsNotNone(frmc) + assert frmc + self.assertEqual(frmc.start, "1001") + self.assertEqual(frmc.end, "1102") + self.assertEqual(frmc.duration, "102") + + with open("tests/edls/cdl_frmc_example02.edl", "r") as f: + edl = pycmx.parse_cmx3600(f) + for event in edl.events: + if event.number == 6: + frmc = event.edits[0].frmc_statement + self.assertIsNotNone(frmc) + assert frmc + self.assertEqual(frmc.start, "1001") + self.assertEqual(frmc.end, "1486") + self.assertEqual(frmc.duration, "486")