diff --git a/ptulsconv/__init__.py b/ptulsconv/__init__.py index 409bee3..ecb95e6 100644 --- a/ptulsconv/__init__.py +++ b/ptulsconv/__init__.py @@ -1,2 +1,3 @@ from .ptuls_grammar import protools_text_export_grammar from .ptuls_parser_visitor import DictionaryParserVisitor +from .transformations import TimecodeInterpreter \ No newline at end of file diff --git a/ptulsconv/commands.py b/ptulsconv/commands.py new file mode 100644 index 0000000..965ecfb --- /dev/null +++ b/ptulsconv/commands.py @@ -0,0 +1,21 @@ +import ptulsconv +import json +import sys + +def convert(input_file, convert_times, apply_session_start, output=sys.stdout): + parsed = dict() + with open(input_file, 'r') as file: + ast = ptulsconv.protools_text_export_grammar.parse(file.read()) + dict_parser = ptulsconv.DictionaryParserVisitor() + parsed = dict_parser.visit(ast) + + if convert_times: + xform = ptulsconv.transformations.TimecodeInterpreter() + xform.apply_session_start = apply_session_start + parsed = xform.transform(parsed) + + json.dump(parsed, output) + + + + diff --git a/ptulsconv/ptuls_parser_visitor.py b/ptulsconv/ptuls_parser_visitor.py index 11308c2..c537d4c 100644 --- a/ptulsconv/ptuls_parser_visitor.py +++ b/ptulsconv/ptuls_parser_visitor.py @@ -83,7 +83,6 @@ class DictionaryParserVisitor(NodeVisitor): states = [] for next_state in visited_children: states.append(next_state[0][0].text) - return states def visit_track_clip_state(self, node, visited_children): diff --git a/ptulsconv/transformations.py b/ptulsconv/transformations.py new file mode 100644 index 0000000..be9d4d0 --- /dev/null +++ b/ptulsconv/transformations.py @@ -0,0 +1,66 @@ +from timecode import Timecode, TimecodeError + +class Transformation: + def transform(self, input_dict) -> dict: + return input_dict + + +class TimecodeInterpreter(Transformation): + + def __init__(self): + self.apply_session_start = False + + def transform(self, input_dict: dict) -> dict: + retval = super().transform(input_dict) + rate = input_dict['header']['timecode_format'] + start_tc = self.convert_time(input_dict['header']['start_timecode'], + rate, offset=None) + + retval['header']['start_timecode_decoded'] = start_tc + convert_start_tc = None + if self.apply_session_start is True: + convert_start_tc = Timecode(framerate=input_dict['header']['timecode_format'], + start_timecode=input_dict['header']['start_timecode']) + + retval['tracks'] = self.convert_tracks(input_dict['tracks'], timecode_rate=rate, + session_start=convert_start_tc) + + + for marker in retval['markers']: + marker['location_decoded'] = self.convert_time(marker['location'], rate, + convert_start_tc) + return retval + + def convert_tracks(self, tracks, timecode_rate, session_start): + for track in tracks: + new_clips = [] + for clip in track['clips']: + new_clips.append( self.convert_clip( clip , + timecode_rate= timecode_rate, + session_start=session_start )) + + track['clips'] = new_clips + return tracks + + def convert_clip(self, clip, timecode_rate, session_start): + time_fields = ['start_time', 'end_time', 'duration', 'timestamp'] + + for time_field in time_fields: + if clip[time_field] is not None: + if time_field == 'duration': + clip[time_field + "_decoded"] = self.convert_time(clip[time_field], + framerate=timecode_rate, offset=None) + else: + clip[time_field + "_decoded"] = self.convert_time(clip[time_field], + framerate=timecode_rate, offset=session_start) + + return clip + + def convert_time(self, time_string, framerate, offset= None): + tc = Timecode(framerate=framerate, start_timecode=time_string) + if offset is not None: + tc = tc - offset + + return dict(frames=tc.frames, framrate= framerate, seconds= (float(tc.frames) / float(tc.framerate))) + + diff --git a/tests/test_robinhood1.py b/tests/test_robinhood1.py index 9c5d9d6..ebb9ff8 100644 --- a/tests/test_robinhood1.py +++ b/tests/test_robinhood1.py @@ -90,6 +90,21 @@ class TestRobinHood1(unittest.TestCase): self.assertEqual(parsed['markers'][0]['time_reference'], 0) self.assertEqual(parsed['markers'][0]['units'], "Samples") + def test_transform_timecode(self): + parsed = dict() + with open(self.path, 'r') as f: + visitor = ptulsconv.DictionaryParserVisitor() + result = ptulsconv.protools_text_export_grammar.parse(f.read()) + parsed = visitor.visit(result) + + xformer = ptulsconv.TimecodeInterpreter() + xformer.apply_session_start = True + + xformed = xformer.transform(parsed) + + pprint.pprint(xformed) + + if __name__ == '__main__':