-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
386 additions
and
338 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# pycmx | ||
# (c) 2018 Jamie Hardt | ||
|
||
from .transition import Transition | ||
from .channel_map import ChannelMap | ||
from .parse_cmx_statements import StmtEffectsName | ||
|
||
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): | ||
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 | ||
|
||
@property | ||
def line_number(self): | ||
""" | ||
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): | ||
""" | ||
Get the :obj:`ChannelMap` object associated with this Edit. | ||
""" | ||
cm = ChannelMap() | ||
cm._append_event(self.edit_statement.channels) | ||
if self.audio_ext != None: | ||
cm._append_ext(self.audio_ext) | ||
return cm | ||
|
||
@property | ||
def transition(self): | ||
""" | ||
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): | ||
""" | ||
Get the source in timecode. | ||
""" | ||
return self.edit_statement.source_in | ||
|
||
@property | ||
def source_out(self): | ||
""" | ||
Get the source out timecode. | ||
""" | ||
|
||
return self.edit_statement.source_out | ||
|
||
@property | ||
def record_in(self): | ||
""" | ||
Get the record in timecode. | ||
""" | ||
|
||
return self.edit_statement.record_in | ||
|
||
@property | ||
def record_out(self): | ||
""" | ||
Get the record out timecode. | ||
""" | ||
|
||
return self.edit_statement.record_out | ||
|
||
@property | ||
def source(self): | ||
""" | ||
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): | ||
""" | ||
Black video or silence should be used as the source for this event. | ||
""" | ||
return self.source == "BL" | ||
|
||
@property | ||
def aux_source(self): | ||
""" | ||
An auxiliary source is the source of this event. | ||
""" | ||
return self.source == "AX" | ||
|
||
@property | ||
def source_file(self): | ||
""" | ||
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): | ||
""" | ||
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 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# pycmx | ||
# (c) 2018 Jamie Hardt | ||
|
||
from .parse_cmx_statements import (StmtUnrecognized, StmtFCM, StmtEvent) | ||
from .event import Event | ||
|
||
class EditList: | ||
""" | ||
Represents an entire edit decision list as returned by `parse_cmx3600()`. | ||
""" | ||
def __init__(self, statements): | ||
self.title_statement = statements[0] | ||
self.event_statements = statements[1:] | ||
|
||
@property | ||
def title(self): | ||
""" | ||
The title of this edit list, as attensted by the 'TITLE:' statement on | ||
the first line. | ||
""" | ||
'The title of the edit list' | ||
return self.title_statement.title | ||
|
||
|
||
@property | ||
def unrecognized_statements(self): | ||
""" | ||
A generator for all the unrecognized statements in the list. | ||
""" | ||
for s in self.event_statements: | ||
if type(s) is StmtUnrecognized: | ||
yield s | ||
|
||
|
||
@property | ||
def events(self): | ||
'A generator for all the events in the edit list' | ||
is_drop = None | ||
current_event_num = None | ||
event_statements = [] | ||
for stmt in self.event_statements: | ||
if type(stmt) is StmtFCM: | ||
is_drop = stmt.drop | ||
elif type(stmt) is StmtEvent: | ||
if current_event_num is None: | ||
current_event_num = stmt.event | ||
event_statements.append(stmt) | ||
else: | ||
if current_event_num != stmt.event: | ||
yield Event(statements=event_statements) | ||
event_statements = [stmt] | ||
current_event_num = stmt.event | ||
else: | ||
event_statements.append(stmt) | ||
|
||
else: | ||
event_statements.append(stmt) | ||
|
||
yield Event(statements=event_statements) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# pycmx | ||
# (c) 2018 Jamie Hardt | ||
|
||
from .parse_cmx_statements import (StmtEvent, StmtClipName, StmtSourceFile, StmtAudioExt, StmtUnrecognized, StmtEffectsName) | ||
from .edit import Edit | ||
|
||
class Event: | ||
""" | ||
Represents a collection of :class:`Edit`s, all with the same event number. | ||
""" | ||
|
||
def __init__(self, statements): | ||
self.statements = statements | ||
|
||
@property | ||
def number(self): | ||
""" | ||
Return the event number. | ||
""" | ||
return int(self._edit_statements()[0].event) | ||
|
||
@property | ||
def edits(self): | ||
""" | ||
Returns the edits. Most events will have a single edit, a single event | ||
will have multiple edits when a dissolve, wipe or key transition needs | ||
to be performed. | ||
""" | ||
edits_audio = list( self._statements_with_audio_ext() ) | ||
clip_names = self._clip_name_statements() | ||
source_files= self._source_file_statements() | ||
|
||
the_zip = [edits_audio] | ||
|
||
if len(edits_audio) == 2: | ||
cn = [None, None] | ||
for clip_name in clip_names: | ||
if clip_name.affect == 'from': | ||
cn[0] = clip_name | ||
elif clip_name.affect == 'to': | ||
cn[1] = clip_name | ||
|
||
the_zip.append(cn) | ||
else: | ||
if len(edits_audio) == len(clip_names): | ||
the_zip.append(clip_names) | ||
else: | ||
the_zip.append([None] * len(edits_audio) ) | ||
|
||
if len(edits_audio) == len(source_files): | ||
the_zip.append(source_files) | ||
elif len(source_files) == 1: | ||
the_zip.append( source_files * len(edits_audio) ) | ||
else: | ||
the_zip.append([None] * len(edits_audio) ) | ||
|
||
# attach trans name to last event | ||
try: | ||
trans_statement = self._trans_name_statements()[0] | ||
trans_names = [None] * (len(edits_audio) - 1) | ||
trans_names.append(trans_statement) | ||
the_zip.append(trans_names) | ||
except IndexError: | ||
the_zip.append([None] * len(edits_audio) ) | ||
|
||
|
||
return [ Edit(e1[0],e1[1],n1,s1,u1) for (e1,n1,s1,u1) in zip(*the_zip) ] | ||
|
||
@property | ||
def unrecognized_statements(self): | ||
""" | ||
A generator for all the unrecognized statements in the event. | ||
""" | ||
for s in self.statements: | ||
if type(s) is StmtUnrecognized: | ||
yield s | ||
|
||
def _trans_name_statements(self): | ||
return [s for s in self.statements if type(s) is StmtEffectsName] | ||
|
||
def _edit_statements(self): | ||
return [s for s in self.statements if type(s) is StmtEvent] | ||
|
||
def _clip_name_statements(self): | ||
return [s for s in self.statements if type(s) is StmtClipName] | ||
|
||
def _source_file_statements(self): | ||
return [s for s in self.statements if type(s) is StmtSourceFile] | ||
|
||
def _statements_with_audio_ext(self): | ||
for (s1, s2) in zip(self.statements, self.statements[1:]): | ||
if type(s1) is StmtEvent and type(s2) is StmtAudioExt: | ||
yield (s1,s2) | ||
elif type(s1) is StmtEvent: | ||
yield (s1, None) | ||
|
||
|
Oops, something went wrong.