14 Commits

Author SHA1 Message Date
Jamie Hardt
1412efe509 autopep 2025-05-18 13:39:06 -07:00
Jamie Hardt
12a6c05467 autopep 2025-05-18 13:37:46 -07:00
Jamie Hardt
cf87986014 autopep'd test 2025-05-18 13:35:12 -07:00
Jamie Hardt
67533879f8 Rewrote parsing to handle old & new-style markers 2025-05-18 13:33:51 -07:00
Jamie Hardt
f847b88aa3 Nudged version and copyright date 2025-05-17 12:06:56 -07:00
Jamie Hardt
c3a600c5d7 Integrated track marker test case and fixed parser 2025-05-17 12:05:27 -07:00
Jamie Hardt
914783a809 Updated documentation 2025-05-17 11:26:07 -07:00
Jamie Hardt
c638c673e8 Adding track marker export case 2025-05-17 11:23:54 -07:00
Jamie Hardt
15fe6667af Fixed up unit test 2025-05-17 11:23:02 -07:00
Jamie Hardt
d4e23b59eb Adding support for track markers
(Always ignore for now)
2025-05-17 11:19:22 -07:00
Jamie Hardt
a602b09551 flake8 2025-05-17 10:47:21 -07:00
Jamie Hardt
448d93d717 Fix for flake 2025-05-17 10:45:40 -07:00
Jamie Hardt
59e7d40d97 Merge branch 'master' of https://github.com/iluvcapra/ptulsconv 2025-05-11 22:19:26 -07:00
Jamie Hardt
eaa5fe824f Fixed parser logic to handle new-style marker tracks 2025-05-11 22:17:42 -07:00
7 changed files with 114 additions and 28 deletions

View File

@@ -76,7 +76,10 @@ Fields set in markers, and in marker comments, will be applied to all clips
whose finish is *after* that marker. Fields in markers are applied cumulatively
from breakfast to dinner in the session. The latest marker applying to a clip has
precedence, so if one marker comes after the other, but both define a field, the
value in the later marker
value in the later marker.
All markers on all rulers will be scanned for tags. All markers on tracks will
be ignored.
An important note here is that, always, fields set on the clip name have the
highest precedence. If a field is set in a clip name, the same field set on the

View File

@@ -2,8 +2,8 @@
Parse and convert Pro Tools text exports
"""
__version__ = '2.1.1'
__version__ = '2.2.0'
__author__ = 'Jamie Hardt'
__license__ = 'MIT'
__copyright__ = "%s %s (c) 2023 %s. All rights reserved." \
__copyright__ = "%s %s (c) 2025 %s. All rights reserved." \
% (__name__, __version__, __author__)

View File

@@ -19,11 +19,17 @@ class SessionDescriptor:
self.tracks = kwargs['tracks']
self.markers = kwargs['markers']
def markers_timed(self) -> Iterator[Tuple['MarkerDescriptor', Fraction]]:
def markers_timed(self,
only_ruler_markers: bool = True) -> \
Iterator[Tuple['MarkerDescriptor', Fraction]]:
"""
Iterate each marker in the session with its respective time reference.
"""
for marker in self.markers:
if marker.track_marker and only_ruler_markers:
continue
marker_time = Fraction(marker.time_reference,
int(self.header.sample_rate))
# marker_time = self.header.convert_timecode(marker.location)
@@ -182,6 +188,7 @@ class MarkerDescriptor:
units: str
name: str
comments: str
track_marker: bool
def __init__(self, **kwargs):
self.number = kwargs['number']
@@ -190,3 +197,4 @@ class MarkerDescriptor:
self.units = kwargs['units']
self.name = kwargs['name']
self.comments = kwargs['comments']
self.track_marker = kwargs['track_marker']

View File

@@ -9,7 +9,8 @@ from .doc_entity import SessionDescriptor, HeaderDescriptor, TrackDescriptor, \
protools_text_export_grammar = Grammar(
r"""
document = header files_section? clips_section? plugin_listing?
track_listing? markers_listing?
track_listing? markers_block?
header = "SESSION NAME:" fs string_value rs
"SAMPLE RATE:" fs float_value rs
"BIT DEPTH:" fs integer_value "-bit" rs
@@ -74,17 +75,33 @@ protools_text_export_grammar = Grammar(
track_clip_state = ("Muted" / "Unmuted")
markers_listing = markers_listing_header markers_column_header
marker_record*
markers_listing_header = "M A R K E R S L I S T I N G" rs
markers_column_header = "# " fs "LOCATION " fs
"TIME REFERENCE " fs
"UNITS " fs
"NAME " fs
"COMMENTS" rs
markers_block = markers_block_header
(markers_list / markers_list_simple)
markers_list_simple = markers_column_header_simple marker_record_simple*
markers_list = markers_column_header marker_record*
markers_block_header = "M A R K E R S L I S T I N G" rs
markers_column_header_simple =
"# LOCATION TIME REFERENCE "
"UNITS NAME "
"COMMENTS" rs
markers_column_header =
"# LOCATION TIME REFERENCE "
"UNITS NAME "
"TRACK NAME "
"TRACK TYPE COMMENTS" rs
marker_record_simple = integer_value isp fs string_value fs
integer_value isp fs string_value fs string_value
fs string_value rs
marker_record = integer_value isp fs string_value fs integer_value isp fs
string_value fs string_value fs string_value rs
string_value fs string_value fs string_value fs
string_value fs string_value rs
fs = "\t"
rs = "\n"
@@ -231,22 +248,37 @@ class DocParserVisitor(NodeVisitor):
return node.text
@staticmethod
def visit_markers_listing(_, visited_children):
def visit_markers_block(_, visited_children):
markers = []
for marker in visited_children[2]:
for marker in visited_children[1][0][1]:
markers.append(marker)
return markers
@staticmethod
def visit_marker_record(_, visited_children):
def visit_marker_record_simple(_, visited_children):
return MarkerDescriptor(number=visited_children[0],
location=visited_children[3],
time_reference=visited_children[5],
units=visited_children[8],
name=visited_children[10],
comments=visited_children[12])
comments=visited_children[12],
track_marker=False)
@staticmethod
def visit_marker_record(_, visited_children):
track_type = visited_children[15]
is_track_marker = (track_type == "Track")
return MarkerDescriptor(number=visited_children[0],
location=visited_children[3],
time_reference=visited_children[5],
units=visited_children[8],
name=visited_children[10],
comments=visited_children[16],
track_marker=is_track_marker)
@staticmethod
def visit_formatted_clip_name(_, visited_children):

View File

@@ -0,0 +1,24 @@
SESSION NAME: Test for ptulsconv
SAMPLE RATE: 48000.000000
BIT DEPTH: 24-bit
SESSION START TIMECODE: 00:00:00:00
TIMECODE FORMAT: 23.976 Frame
# OF AUDIO TRACKS: 1
# OF AUDIO CLIPS: 0
# OF AUDIO FILES: 0
T R A C K L I S T I N G
TRACK NAME: Hamlet
COMMENTS: {Actor=Laurence Olivier}
USER DELAY: 0 Samples
STATE:
CHANNEL EVENT CLIP NAME START TIME END TIME DURATION STATE
1 1 Test Line 1 $QN=T1001 00:00:00:00 00:00:02:00 00:00:02:00 Unmuted
1 2 Test Line 2 $QN=T1002 00:00:04:00 00:00:06:00 00:00:02:00 Unmuted
M A R K E R S L I S T I N G
# LOCATION TIME REFERENCE UNITS NAME TRACK NAME TRACK TYPE COMMENTS
1 00:00:00:00 0 Samples {Title=Multiple Marker Rulers Project} Markers Ruler
2 00:00:04:00 192192 Samples Track Marker Hamlet Track

View File

@@ -2,33 +2,52 @@ import unittest
import tempfile
import sys
import os.path
import os
import glob
from ptulsconv import commands
class TestPDFExport(unittest.TestCase):
def test_report_generation(self):
"""
Setp through every text file in export_cases and make sure it can
be converted into PDF docs without throwing an error
"""
files = [os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting.txt"]
#files.append(os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting2.txt")
files = []
files = [os.path.dirname(__file__) +
"/../export_cases/Robin Hood Spotting.txt"]
for path in files:
tempdir = tempfile.TemporaryDirectory()
os.chdir(tempdir.name)
try:
commands.convert(input_file=path, major_mode='doc')
except:
assert False, "Error processing file %s" % path
except Exception as e:
print("Error in test_report_generation")
print(f"File: {path}")
print(repr(e))
raise e
finally:
tempdir.cleanup()
def test_report_generation_track_markers(self):
files = []
files.append(os.path.dirname(__file__) +
"/../export_cases/Test for ptulsconv.txt")
for path in files:
tempdir = tempfile.TemporaryDirectory()
os.chdir(tempdir.name)
try:
commands.convert(input_file=path, major_mode='doc')
except Exception as e:
print("Error in test_report_generation_track_markers")
print(f"File: {path}")
print(repr(e))
raise e
finally:
tempdir.cleanup()
if __name__ == '__main__':
unittest.main()

View File

@@ -102,14 +102,14 @@ class TestTagCompiler(unittest.TestCase):
time_reference=48000 * 3600,
units="Samples",
name="Marker 1 {Part=1}",
comments=""
comments="", track_marker=False,
),
doc_entity.MarkerDescriptor(number=2,
location="01:00:01:00",
time_reference=48000 * 3601,
units="Samples",
name="Marker 2 {Part=2}",
comments="[M1]"
comments="[M1]", track_marker=False,
),
]