Skip to content

Commit

Permalink
Merge branch 'jamie'
Browse files Browse the repository at this point in the history
  • Loading branch information
iluvcapra committed Dec 29, 2018
2 parents 44f751f + ce31cbb commit 23667fb
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 338 deletions.
7 changes: 4 additions & 3 deletions pycmx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
__version__ = '0.8'
__author__ = 'Jamie Hardt'

from .parse_cmx_events import parse_cmx3600, Transition, Event, Edit
from . import parse_cmx_events

from .parse_cmx_events import parse_cmx3600
from .transition import Transition
from .event import Event
from .edit import Edit
4 changes: 2 additions & 2 deletions pycmx/channel_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
from re import (compile, match)

class ChannelMap:

"""
Represents a set of all the channels to which an event applies.
"""

_chan_map = { "V" : (True, False, False),
_chan_map = {
"V" : (True, False, False),
"A" : (False, True, False),
"A2" : (False, False, True),
"AA" : (False, True, True),
Expand Down
126 changes: 126 additions & 0 deletions pycmx/edit.py
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


61 changes: 61 additions & 0 deletions pycmx/edit_list.py
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)

97 changes: 97 additions & 0 deletions pycmx/event.py
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)


Loading

0 comments on commit 23667fb

Please sign in to comment.