diff --git a/ptulsconv/ptuls_grammar.py b/ptulsconv/ptuls_grammar.py index db89262..200d3bc 100644 --- a/ptulsconv/ptuls_grammar.py +++ b/ptulsconv/ptuls_grammar.py @@ -6,8 +6,8 @@ protools_text_export_grammar = Grammar( header = "SESSION NAME:" fs string_value rs "SAMPLE RATE:" fs float_value rs "BIT DEPTH:" fs integer_value "-bit" rs - "SESSION START TIMECODE:" fs timecode_value rs - "TIMECODE FORMAT:" fs float_value " Frame" rs + "SESSION START TIMECODE:" fs string_value rs + "TIMECODE FORMAT:" fs float_value " Drop"? " Frame" rs "# OF AUDIO TRACKS:" fs integer_value rs "# OF AUDIO CLIPS:" fs integer_value rs "# OF AUDIO FILES:" fs integer_value rs block_ending @@ -38,7 +38,7 @@ protools_text_export_grammar = Grammar( "COMMENTS:" fs string_value rs "USER DELAY:" fs integer_value " Samples" rs "STATE: " track_state_list rs - "PLUG-INS: " ( fs string_value )* rs + ("PLUG-INS: " ( fs string_value )* rs)? "CHANNEL " fs "EVENT " fs "CLIP NAME " fs "START TIME " fs "END TIME " fs "DURATION " fs ("TIMESTAMP " fs)? "STATE" rs @@ -50,7 +50,7 @@ protools_text_export_grammar = Grammar( track_clip_entry = integer_value isp fs integer_value isp fs string_value fs - timecode_value fs timecode_value fs timecode_value fs (timecode_value fs)? + string_value fs string_value fs string_value fs (string_value fs)? track_clip_state rs track_clip_state = ("Muted" / "Unmuted") @@ -60,14 +60,13 @@ protools_text_export_grammar = Grammar( markers_column_header = "# " fs "LOCATION " fs "TIME REFERENCE " fs "UNITS " fs "NAME " fs "COMMENTS" rs - marker_record = integer_value isp fs timecode_value fs integer_value isp fs + marker_record = integer_value isp fs string_value fs integer_value isp fs string_value fs string_value fs string_value rs fs = "\t" rs = "\n" block_ending = rs rs string_value = ~"[^\t\n]*" - timecode_value = ~"[^\d\t\n]*" ~"\d\d:\d\d:\d\d:\d\d(\.\d+)?" ~"[^\d\t\n]*" integer_value = ~"\d+" float_value = ~"\d+(\.\d+)" isp = ~"[^\d\t\n]*" diff --git a/ptulsconv/ptuls_parser_visitor.py b/ptulsconv/ptuls_parser_visitor.py index c537d4c..2928e80 100644 --- a/ptulsconv/ptuls_parser_visitor.py +++ b/ptulsconv/ptuls_parser_visitor.py @@ -17,14 +17,20 @@ class DictionaryParserVisitor(NodeVisitor): markers=markers) def visit_header(self, node, visited_children): + + tc_drop = False + for _ in visited_children[20]: + tc_drop = True + return dict(session_name=visited_children[2], sample_rate=visited_children[6], bit_depth=visited_children[10], start_timecode=visited_children[15], timecode_format=visited_children[19], - count_audio_tracks=visited_children[24], - count_clips=visited_children[28], - count_files=visited_children[32]) + timecode_drop_frame=tc_drop, + count_audio_tracks=visited_children[25], + count_clips=visited_children[29], + count_files=visited_children[33]) def visit_files_section(self, node, visited_children): return list(map(lambda child: dict(filename=child[0], path=child[2]), visited_children[2])) @@ -50,8 +56,9 @@ class DictionaryParserVisitor(NodeVisitor): clips.append(clip[0]) plugins = [] - for plugin in track_header[17]: - plugins.append(plugin[1]) + for plugin_opt in track_header[16]: + for plugin in plugin_opt[1]: + plugins.append(plugin[1]) return dict( name=track_header[2], @@ -114,8 +121,8 @@ class DictionaryParserVisitor(NodeVisitor): def visit_integer_value(self, node, visited_children): return int(node.text) - def visit_timecode_value(self, node, visited_children): - return visited_children[1].text + # def visit_timecode_value(self, node, visited_children): + # return node.text.strip(" ") def visit_float_value(self, node, visited_children): return float(node.text) diff --git a/tests/test_robinhood1.py b/tests/test_robinhood1.py index ebb9ff8..bc48ae7 100644 --- a/tests/test_robinhood1.py +++ b/tests/test_robinhood1.py @@ -1,6 +1,6 @@ import unittest import ptulsconv -import pprint +#import pprint import os.path @@ -18,6 +18,7 @@ class TestRobinHood1(unittest.TestCase): self.assertEqual(parsed['header']['sample_rate'], 48000.0) self.assertEqual(parsed['header']['bit_depth'], 24) self.assertEqual(parsed['header']['timecode_format'], 29.97) + self.assertEqual(parsed['header']['timecode_drop_frame'], False) def test_all_sections(self): with open(self.path, 'r') as f: @@ -102,8 +103,6 @@ class TestRobinHood1(unittest.TestCase): xformed = xformer.transform(parsed) - pprint.pprint(xformed) - diff --git a/tests/test_robinhooddf.py b/tests/test_robinhooddf.py new file mode 100644 index 0000000..8fcfedc --- /dev/null +++ b/tests/test_robinhooddf.py @@ -0,0 +1,36 @@ +import unittest +import ptulsconv +import os.path + + +class TestRobinHoodDF(unittest.TestCase): + path = os.path.dirname(__file__) + '/export_cases/Robin Hood SpottingDF.txt' + + def test_header_export_df(self): + with open(self.path, 'r') as f: + visitor = ptulsconv.DictionaryParserVisitor() + result = ptulsconv.protools_text_export_grammar.parse(f.read()) + parsed: dict = visitor.visit(result) + + self.assertTrue('header' in parsed.keys()) + self.assertEqual(parsed['header']['timecode_drop_frame'], True) + + def test_a_track(self): + with open(self.path, 'r') as f: + visitor = ptulsconv.DictionaryParserVisitor() + result = ptulsconv.protools_text_export_grammar.parse(f.read()) + parsed: dict = visitor.visit(result) + guy_track = parsed['tracks'][4] + self.assertEqual(guy_track['name'], 'Robin') + self.assertEqual(guy_track['comments'], '[ADR] {Actor=Errol Flynn} $CN=1') + self.assertEqual(guy_track['user_delay_samples'], 0) + self.assertListEqual(guy_track['state'], []) + self.assertEqual(len(guy_track['clips']), 10) + self.assertEqual(guy_track['clips'][5]['channel'], 1) + self.assertEqual(guy_track['clips'][5]['event'], 6) + self.assertEqual(guy_track['clips'][5]['clip_name'], "\"Hold there! What's his fault?\" $QN=R106") + self.assertEqual(guy_track['clips'][5]['start_time'], "01:05:30;15") + self.assertEqual(guy_track['clips'][5]['end_time'], "01:05:32;01") + self.assertEqual(guy_track['clips'][5]['duration'], "00:00:01;16") + self.assertEqual(guy_track['clips'][5]['timestamp'], None) + self.assertEqual(guy_track['clips'][5]['state'], 'Unmuted')