mirror of
https://github.com/iluvcapra/pycmx.git
synced 2025-12-31 08:50:54 +00:00
172 lines
5.1 KiB
Python
172 lines
5.1 KiB
Python
# pycmx
|
|
# (c) 2018-2025 Jamie Hardt
|
|
|
|
from pycmx.cdl import AscSopComponents, FramecountTriple, Rgb
|
|
from pycmx.statements import StmtCdlSat, StmtCdlSop, StmtFrmc
|
|
from .transition import Transition
|
|
from .channel_map import ChannelMap
|
|
|
|
from typing import Optional
|
|
|
|
|
|
class Edit:
|
|
"""
|
|
An individual source-to-record operation, with a source roll, source and
|
|
recorder timecode in and out, a transition and channels.
|
|
"""
|
|
|
|
def __init__(self, edit_statement, audio_ext_statement,
|
|
clip_name_statement, source_file_statement,
|
|
trans_name_statement=None, asc_sop_statement=None,
|
|
asc_sat_statement=None, frmc_statement=None):
|
|
|
|
self._edit_statement = edit_statement
|
|
self._audio_ext = audio_ext_statement
|
|
self._clip_name_statement = clip_name_statement
|
|
self._source_file_statement = source_file_statement
|
|
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: Optional[StmtFrmc] = frmc_statement
|
|
|
|
@property
|
|
def line_number(self) -> int:
|
|
"""
|
|
Get the line number for the "standard form" statement associated with
|
|
this edit. Line numbers a zero-indexed, such that the
|
|
"TITLE:" record is line zero.
|
|
"""
|
|
return self._edit_statement.line_number
|
|
|
|
@property
|
|
def channels(self) -> ChannelMap:
|
|
"""
|
|
Get the :obj:`ChannelMap` object associated with this Edit.
|
|
"""
|
|
cm = ChannelMap()
|
|
cm._append_event(self._edit_statement.channels)
|
|
if self._audio_ext is not None:
|
|
cm._append_ext(self._audio_ext)
|
|
return cm
|
|
|
|
@property
|
|
def transition(self) -> Transition:
|
|
"""
|
|
Get the :obj:`Transition` object associated with this edit.
|
|
"""
|
|
if self._trans_name_statement:
|
|
return Transition(self._edit_statement.trans,
|
|
self._edit_statement.trans_op,
|
|
self._trans_name_statement.name)
|
|
else:
|
|
return Transition(self._edit_statement.trans,
|
|
self._edit_statement.trans_op, None)
|
|
|
|
@property
|
|
def source_in(self) -> str:
|
|
"""
|
|
Get the source in timecode.
|
|
"""
|
|
return self._edit_statement.source_in
|
|
|
|
@property
|
|
def source_out(self) -> str:
|
|
"""
|
|
Get the source out timecode.
|
|
"""
|
|
|
|
return self._edit_statement.source_out
|
|
|
|
@property
|
|
def record_in(self) -> str:
|
|
"""
|
|
Get the record in timecode.
|
|
"""
|
|
|
|
return self._edit_statement.record_in
|
|
|
|
@property
|
|
def record_out(self) -> str:
|
|
"""
|
|
Get the record out timecode.
|
|
"""
|
|
|
|
return self._edit_statement.record_out
|
|
|
|
@property
|
|
def source(self) -> str:
|
|
"""
|
|
Get the source column. This is the 8, 32 or 128-character string on the
|
|
event record line, this usually references the tape name of the source.
|
|
"""
|
|
return self._edit_statement.source
|
|
|
|
@property
|
|
def black(self) -> bool:
|
|
"""
|
|
Black video or silence should be used as the source for this event.
|
|
"""
|
|
return self.source == "BL"
|
|
|
|
@property
|
|
def aux_source(self) -> bool:
|
|
"""
|
|
An auxiliary source is the source of this event.
|
|
"""
|
|
return self.source == "AX"
|
|
|
|
@property
|
|
def source_file(self) -> Optional[str]:
|
|
"""
|
|
Get the source file, as attested by a "* SOURCE FILE" remark on the
|
|
EDL. This will return None if the information is not present.
|
|
"""
|
|
if self._source_file_statement is None:
|
|
return None
|
|
else:
|
|
return self._source_file_statement.filename
|
|
|
|
@property
|
|
def clip_name(self) -> Optional[str]:
|
|
"""
|
|
Get the clip name, as attested by a "* FROM CLIP NAME" or "* TO CLIP
|
|
NAME" remark on the EDL. This will return None if the information is
|
|
not present.
|
|
"""
|
|
if self._clip_name_statement is None:
|
|
return None
|
|
else:
|
|
return self._clip_name_statement.name
|
|
|
|
@property
|
|
def asc_sop(self) -> Optional[AscSopComponents[float]]:
|
|
"""
|
|
Get ASC CDL Slope-Offset-Power transfer function for clip, if present
|
|
"""
|
|
if self._asc_sop_statement is None:
|
|
return None
|
|
|
|
return self._asc_sop_statement.cdl_sop
|
|
|
|
@property
|
|
def asc_sat(self) -> Optional[float]:
|
|
"""
|
|
Get ASC CDL saturation value for clip, if present
|
|
"""
|
|
if self._asc_sat_statement is None:
|
|
return None
|
|
|
|
return self._asc_sat_statement.value
|
|
|
|
@property
|
|
def frmc(self) -> Optional[FramecountTriple]:
|
|
"""
|
|
Get FRMC data
|
|
"""
|
|
if not self._frmc_statement:
|
|
return None
|
|
|
|
return FramecountTriple(start=self._frmc_statement.start,
|
|
end=self._frmc_statement.end,
|
|
duration=self._frmc_statement.duration)
|