Skip to content

Commit

Permalink
For frozen devices, show how often dependecies are used
Browse files Browse the repository at this point in the history
  • Loading branch information
mkp committed Nov 15, 2024
1 parent 4a20861 commit 3b101ef
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 20 deletions.
18 changes: 15 additions & 3 deletions maxdiff/frozen_device_printer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from freezing_utils import *
from get_frozen_stats import get_frozen_stats
from get_frozen_stats import get_frozen_stats, get_used_files


def print_frozen_device(data: bytes) -> str:
Expand All @@ -19,9 +19,21 @@ def print_frozen_device(data: bytes) -> str:

footer_entries = parse_footer(footer_data[8:])
device_entries = get_device_entries(data, footer_entries)
used_files = get_used_files(device_entries)

i = 0
for entry in device_entries:
if isinstance(entry["description"], str):
frozen_string += entry["description"] + "\n"
description = entry["description"]
if isinstance(description, str):
file_name = str(entry["file_name"])
if i == 0:
frozen_string += f"{description} <= Device \n"
else:
if file_name in used_files:
frozen_string += f"{description}, {used_files[file_name]} instance{'s' if used_files[file_name] > 1 else ''}\n"
else:
frozen_string += f"{description}, NOT FOUND IN PATCH\n"
i += 1

[object_count_total, line_count_total, object_count_unique, line_count_unique] = (
get_frozen_stats(device_entries)
Expand Down
143 changes: 143 additions & 0 deletions maxdiff/get_frozen_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,146 @@ def process_elements(self, patcher, voice_count: int, abstraction_name=""):
def get_results(self):
"""Returns the current counts."""
return self.object_count, self.line_count


def get_used_files(entries: list[device_entry_with_data]) -> dict[str, int]:
device = entries[0] # the first entry is always the device file

abstraction_entries = [
item for item in entries if str(item["file_name"]).endswith(".maxpat")
]

device_patch = get_patcher_dict(device)
if device_patch == {}:
return {}

abstractions_processor = FileNamesProcessor()
process_patch(device_patch, abstraction_entries, abstractions_processor)
return abstractions_processor.get_results()


class FileNamesProcessor(Processor):
def __init__(self):
self.found_filenames = {}

def process_elements(self, patcher, voice_count: int, abstraction_name=""):
"""If this patcher is an abstraction, i.e. when an abstraction_name is passed in, increment the entry in the dict.
For other patchers, scan them for objects that use files.
"""

filenames = get_dependency_filenames(patcher)
if abstraction_name != "":
filenames.append(abstraction_name)

for filename in filenames:
if filename in self.found_filenames:
self.found_filenames[filename] += voice_count
else:
self.found_filenames[filename] = voice_count

def get_results(self):
"""Returns a dict of used abstractions mapped to how oftern they are used."""
return self.found_filenames


def get_dependency_filenames(patcher):
"""Check all boxes in this patcher and report any dependencies they might be referring to"""
filenames = []
for box_entry in patcher["boxes"]:
box = box_entry["box"]

if box.get("pic"): # fic
filenames.append(box.get("pic"))
continue

if box.get("pictures"): # live.text, live.tab and live.menu
for name in box.get("pictures"):
filenames.append(name)
continue

if box.get("maxclass") == "pictctrl":
if box.get("name"):
filenames.append(box.get("name"))
continue

if box.get("bkgndpict"): # pictslider and matrixctrl
filenames.append(box.get("bkgndpict"))
continue

if box.get("knobpict"): # pictslider
filenames.append(box.get("knobpict"))
continue

if box.get("cellpict"): # pictslider
filenames.append(box.get("cellpict"))
continue

if box.get("filename"): # jsui
filenames.append(box.get("filename"))
continue

if box.get("filename"): # jsui
filenames.append(box.get("filename"))
continue

if box.get("text") and box.get("text").startswith("sfplay~"): # sfplay~
audiofile = get_max_attribute(box, "audiofile")
if audiofile:
filenames.append(audiofile)
continue

if box.get("text") and box.get("text").startswith("gen~"): # gen~
filename = get_max_attribute(box, "gen")
if filename:
filenames.append(add_if_needed(filename, ".gendsp"))
continue

if box.get("text") and (
box.get("text").startswith("jit.gen") or box.get("text").startswith("jit.pix")
): # jit.gen and jit.pix
filename = get_max_attribute(box, "gen")
if filename:
filenames.append(add_if_needed(filename, ".genjit"))
continue

if box.get("text") and box.get("text").startswith("node.script"): # node
filename = box.get("text").split("node.script ")[1].split()[0]
filenames.append(add_if_needed(filename, ".js"))

if box.get("text") and box.get("text").startswith("pattrstorage"): # pattrstorage
filename = box.get("text").split("pattrstorage ")[1].split()[0]
filenames.append(add_if_needed(filename, ".json"))
continue

if box.get("text") and box.get("text").startswith("table"): # pattrstorage
filename = box.get("text").split("table ")[1].split()[0]
filenames.append(filename)
continue

if box.get("maxclass") == "playlist~" and box.get("data"): # playlist~
for clip in box["data"].get("clips"):
if clip.get("filename"):
filenames.append(clip.get("filename"))
continue

if box.get("saved_object_attributes") and box["saved_object_attributes"].get(
"filename"
): # js
filename = box["saved_object_attributes"].get("filename")
filenames.append(add_if_needed(filename, ".js"))
continue

return filenames


def get_max_attribute(box, attribute_name: str):
"""parse the box text for a specific attribute value"""
attrstring = "@" + attribute_name + " "
if box.get("text") and attrstring in box.get("text"):
return box.get("text").split(attrstring)[1].split()[0]
return None


def add_if_needed(s: str, ext: str):
"""add an extension to a string if it doesn't exist yet"""
return s + ext if not s.endswith(ext) else s
18 changes: 9 additions & 9 deletions maxdiff/process_patcher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from freezing_utils import get_patcher_dict


class Processor:
def process_elements(self, patcher, voice_count: int, abstraction_name=""):
"""Processes patchers."""

def get_results(self):
"""Returns the current results."""
return None


def process_patch(patcher, abstraction_entries: list[dict], processor: Processor):
process_patch_recursive(patcher, abstraction_entries, processor, 1, "")

Expand Down Expand Up @@ -99,12 +108,3 @@ def get_abstraction_name(box, abstraction_entries: list[dict]):
)

return None


class Processor:
def process_elements(self, patcher, voice_count: int, abstraction_name=""):
"""Processes patchers."""

def get_results(self):
"""Returns the current results."""
return None
16 changes: 8 additions & 8 deletions maxdiff/tests/test_baselines/FrozenTest.amxd.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ MIDI Effect Device
-------------------
Device is frozen
----- Contents -----
Test.amxd: 24675 bytes, modified at 2024/10/21 12:19:47 UTC
ParamAbstraction.maxpat: 1570 bytes, modified at 2024/05/24 13:59:36 UTC
MyAbstraction.maxpat: 2015 bytes, modified at 2024/10/21 12:18:20 UTC
AbstractionWithParameter.maxpat: 1569 bytes, modified at 2024/05/24 13:59:36 UTC
hz-icon.svg: 484 bytes, modified at 2024/05/24 13:59:36 UTC
beat-icon.svg: 533 bytes, modified at 2024/05/24 13:59:36 UTC
fpic.png: 7094 bytes, modified at 2024/05/24 13:59:36 UTC
collContent.txt: 8 bytes, modified at 2024/05/24 13:59:36 UTC
Test.amxd: 24675 bytes, modified at 2024/10/21 12:19:47 UTC <= Device
ParamAbstraction.maxpat: 1570 bytes, modified at 2024/05/24 13:59:36 UTC, 2 instances
MyAbstraction.maxpat: 2015 bytes, modified at 2024/10/21 12:18:20 UTC, 6 instances
AbstractionWithParameter.maxpat: 1569 bytes, modified at 2024/05/24 13:59:36 UTC, 2 instances
hz-icon.svg: 484 bytes, modified at 2024/05/24 13:59:36 UTC, 1 instance
beat-icon.svg: 533 bytes, modified at 2024/05/24 13:59:36 UTC, 1 instance
fpic.png: 7094 bytes, modified at 2024/05/24 13:59:36 UTC, 1 instance
collContent.txt: 8 bytes, modified at 2024/05/24 13:59:36 UTC, NOT FOUND IN PATCH

Total - Counting every abstraction instance - Indicates loading time
Object instances: 64
Expand Down

0 comments on commit 3b101ef

Please sign in to comment.