mirror of
https://github.com/AnxiousAnt/PatchGen.git
synced 2026-04-01 11:49:38 +02:00
171 lines
5.1 KiB
Python
171 lines
5.1 KiB
Python
def read_pd_file(file_path):
|
|
"""
|
|
Reads a .pd file and splits it into individual records.
|
|
|
|
Parameters:
|
|
- file_path (str): Path to the .pd file.
|
|
|
|
Returns:
|
|
- records (list): List of records, where each record is a dictionary with
|
|
'chunk_type', 'element_type', and 'parameters'.
|
|
"""
|
|
records = []
|
|
|
|
with open(file_path, 'r') as file:
|
|
for line in file:
|
|
# Strip the line endings
|
|
line = line.strip()
|
|
|
|
# Skip empty lines
|
|
if not line:
|
|
continue
|
|
|
|
# Check if the line ends with a semicolon and starts with '#'
|
|
if not line.endswith(';') or not line.startswith('#'):
|
|
print(f"Syntax error: Line does not start with '#' or end with ';': {line}")
|
|
continue
|
|
|
|
# Remove the leading '#' and trailing ';'
|
|
line = line[1:-1].strip()
|
|
|
|
# Split the line into parts
|
|
parts = line.split()
|
|
|
|
if len(parts) < 2:
|
|
print(f"Syntax error: Insufficient parts in the line: {line}")
|
|
continue
|
|
|
|
# Extract chunk type and element type
|
|
chunk_type = parts[0]
|
|
element_type = parts[1]
|
|
parameters = parts[2:]
|
|
|
|
# Append to the records list
|
|
records.append({
|
|
'chunk_type': chunk_type,
|
|
'element_type': element_type,
|
|
'parameters': parameters,
|
|
'original_line': line # Store the original line for later display
|
|
})
|
|
|
|
return records
|
|
|
|
def validate_canvas(parameters):
|
|
"""
|
|
Validates the parameters of a 'canvas' element.
|
|
|
|
Parameters:
|
|
- parameters (list): List of parameters for the 'canvas' element.
|
|
|
|
Returns:
|
|
- errors (list): List of error messages.
|
|
"""
|
|
errors = []
|
|
|
|
if len(parameters) != 6:
|
|
errors.append(f"Canvas element must have exactly 6 parameters, found {len(parameters)}.")
|
|
return errors
|
|
|
|
try:
|
|
x_pos = int(parameters[0])
|
|
y_pos = int(parameters[1])
|
|
x_size = int(parameters[2])
|
|
y_size = int(parameters[3])
|
|
except ValueError:
|
|
errors.append("Canvas positions and sizes must be integers.")
|
|
|
|
name = parameters[4]
|
|
|
|
try:
|
|
open_on_load = int(parameters[5])
|
|
if open_on_load not in {0, 1}:
|
|
errors.append("Canvas 'open_on_load' flag must be 0 or 1.")
|
|
except ValueError:
|
|
errors.append("Canvas 'open_on_load' flag must be an integer (0 or 1).")
|
|
|
|
return errors
|
|
|
|
def validate_pd_records(records):
|
|
"""
|
|
Validates the structure and parameters of the parsed .pd records.
|
|
|
|
Parameters:
|
|
- records (list): List of records parsed from a .pd file.
|
|
|
|
Returns:
|
|
- errors (list): List of error messages.
|
|
"""
|
|
errors = []
|
|
valid_chunk_types = {"X", "N", "A"}
|
|
valid_element_types = {
|
|
"array", "connect", "coords", "floatatom", "msg", "obj", "bng", "tgl",
|
|
"nbx", "vsl", "hsl", "vradio", "hradio", "vu", "cnv", "pd", "restore",
|
|
"symbolatom", "text", "canvas"
|
|
}
|
|
|
|
for i, record in enumerate(records):
|
|
chunk_type = record['chunk_type']
|
|
element_type = record['element_type']
|
|
parameters = record['parameters']
|
|
|
|
if chunk_type not in valid_chunk_types:
|
|
errors.append(f"Record {i}: Invalid chunk type '{chunk_type}'.")
|
|
|
|
if element_type not in valid_element_types:
|
|
errors.append(f"Record {i}: Invalid element type '{element_type}'.")
|
|
|
|
# Detailed validation for specific element types
|
|
if element_type == "canvas":
|
|
canvas_errors = validate_canvas(parameters)
|
|
if canvas_errors:
|
|
errors.extend([f"Record {i}: {error}" for error in canvas_errors])
|
|
|
|
return errors
|
|
|
|
def display_with_errors(file_path, errors):
|
|
"""
|
|
Displays the content of a .pd file with errors highlighted and explained.
|
|
|
|
Parameters:
|
|
- file_path (str): Path to the .pd file.
|
|
- records (list): List of records parsed from a .pd file.
|
|
- errors (list): List of error messages.
|
|
"""
|
|
with open(file_path, 'r') as file:
|
|
lines = file.readlines()
|
|
|
|
error_indices = [int(error.split()[1].strip(":")) for error in errors]
|
|
for i, line in enumerate(lines):
|
|
print(line.strip())
|
|
if i in error_indices:
|
|
for error in errors:
|
|
if int(error.split()[1].strip(":")) == i:
|
|
print(f" >> Error: {error}")
|
|
|
|
# Writing the sample file content to 'sample.pd'
|
|
sample_pd_patch = """
|
|
#N canvas 0 0 450 sample_patch 1;
|
|
#X obj 50 50 osc~ 440;
|
|
hey!
|
|
#X obj 50 100 dac~;
|
|
#N canvas dfa;
|
|
#X connect 0 0 1 0;
|
|
#MDMF loll fadlkf:
|
|
"""
|
|
|
|
with open('sample.pd', 'w') as file:
|
|
file.write(sample_pd_patch.strip())
|
|
|
|
# Reading and validating the sample file
|
|
file_path = 'sample.pd'
|
|
records = read_pd_file(file_path)
|
|
errors = validate_pd_records(records)
|
|
|
|
if errors:
|
|
display_with_errors(file_path, errors)
|
|
else:
|
|
print("No syntax errors found.")
|
|
|
|
|
|
print(errors)
|