From e342c309d1788336c66b92b3cbc34f8a5b9033d8 Mon Sep 17 00:00:00 2001 From: mkp Date: Thu, 26 Feb 2026 10:30:43 +0100 Subject: [PATCH 1/3] maxdiff: cleanups - rename some variables in patch printer - remove unused indent - simplify get_param_properties_from_ids_recursive loop --- maxdiff/patch_printer.py | 68 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/maxdiff/patch_printer.py b/maxdiff/patch_printer.py index 1076987..32c2ad6 100644 --- a/maxdiff/patch_printer.py +++ b/maxdiff/patch_printer.py @@ -220,9 +220,7 @@ def get_box_text(box: dict) -> str: return boxtext -def get_object_names_from_ids_recursive( - id_hierarchy: list, boxes_parent: list, indent: int = 0 -): +def get_object_names_from_ids_recursive(id_hierarchy: list, boxes_parent: list): """Translates an object id hierarchy string in the form of "obj-n::obj-m:: etc" to a string in the form of "/ 1: - id_hierarchy.pop(0) + if len(id_hierarchy) > 1: if "patcher" in box: subpatcher_boxes = box["patcher"]["boxes"] - name += f"/{get_object_names_from_ids_recursive(id_hierarchy, subpatcher_boxes, indent + 1)}" + name += f"/{get_object_names_from_ids_recursive(id_hierarchy[1:], subpatcher_boxes)}" else: - for id_level in id_hierarchy: + for id_level in id_hierarchy[1:]: name += f"/[{id_level}]" if name == "": - name = f"[{id_to_check}]" + name = f"[{id_hierarchy[0]}]" return name @@ -279,7 +275,7 @@ def get_properties_to_print( continue if key == "saved_attribute_attributes": - # We take the attributes out or saved_attribute_attributes and present them as properties + # We take the attributes out of saved_attribute_attributes and present them as properties attributes = get_saved_attribute_attributes(value) attributes_to_print = get_properties_to_print( attributes, default, skip_properties @@ -291,7 +287,7 @@ def get_properties_to_print( continue if key == "saved_object_attributes": - # We take the attributes out or saved_object_attributes and present them as properties + # We take the attributes out of saved_object_attributes and present them as properties attributes = get_saved_object_attributes(value) attributes_to_print = get_properties_to_print( attributes, default, skip_properties @@ -373,30 +369,36 @@ def get_parameters_string_block(patcher: dict) -> str: Non-overridden parameter attributes are already shown with the parameter objects. """ parameters = patcher["parameters"] + + param_overrides = ( + parameters["parameter_overrides"] if "parameter_overrides" in parameters else {} + ) + + param_banks = parameters["parameterbanks"] if "parameterbanks" in parameters else {} + parameters_string = "" - for bankindex, bank in parameters.items(): - if bankindex in ["parameter_overrides", "parameterbanks"]: + for index, item in parameters.items(): + if index in ["parameter_overrides", "parameterbanks"]: continue - parsed_key = bankindex - if bankindex.startswith("obj"): - id_tokens = bankindex.split("::") - parsed_key = get_object_names_from_ids_recursive(id_tokens, patcher["boxes"]) + object_names = index + if index.startswith("obj"): + id_tokens = index.split("::") + object_names = get_object_names_from_ids_recursive( + id_tokens, patcher["boxes"] + ) - parameters_string += f"\t{parsed_key}: {bank}" + parameters_string += f"\t{object_names}: {item}" - if ( - "parameter_overrides" in parameters - and bankindex in parameters["parameter_overrides"] - ): - override = parameters["parameter_overrides"][bankindex] + if index in param_overrides: + param_override = param_overrides[index] override_print = [ - override.get("parameter_longname", "-"), - override.get("parameter_shortname", "-"), - str(override.get("parameter_linknames", "-")), + param_override.get("parameter_longname", "-"), + param_override.get("parameter_shortname", "-"), + str(param_override.get("parameter_linknames", "-")), ] - for key, value in override.items(): + for key, value in param_override.items(): if key in [ "parameter_longname", "parameter_shortname", @@ -408,19 +410,19 @@ def get_parameters_string_block(patcher: dict) -> str: parameters_string += f" > override > {str(override_print)}" parameters_string += "\n" - if "parameterbanks" in parameters: + if param_banks != {}: parameters_string += "banks:\n" - for bankindex, bank in parameters["parameterbanks"].items(): - for key, value in bank.items(): + for index, item in param_banks.items(): + for key, value in item.items(): parameters_string += "\t" if key == "index": parameters_string += f"{value}:" elif key == "name": parameters_string += f"({value})" if value != "" else "" elif key == "parameters": - parameters_string += f"encoders: {bank['parameters']}" + parameters_string += f"encoders: {item['parameters']}" elif key == "buttons": - parameters_string += f"buttons: {bank['buttons']}" + parameters_string += f"buttons: {item['buttons']}" else: parameters_string += f"{value}" parameters_string += "\n" From 16b3c3f2459d349148094df5e49012a2a860352b Mon Sep 17 00:00:00 2001 From: mkp Date: Fri, 27 Feb 2026 12:26:56 +0100 Subject: [PATCH 2/3] Save test files with 9.1.3 --- .../tests/test_baselines/FrozenTest.amxd.txt | 8 +- maxdiff/tests/test_baselines/Test.amxd.txt | 31 +--- .../AbstractionWithParameter.maxpat | 116 +++++--------- maxdiff/tests/test_files/FrozenTest.amxd | Bin 409862 -> 431418 bytes maxdiff/tests/test_files/MyAbstraction.maxpat | 148 +++++++++--------- .../tests/test_files/ParamAbstraction.maxpat | 91 +++++------ maxdiff/tests/test_files/Test.amxd | Bin 36675 -> 57317 bytes 7 files changed, 165 insertions(+), 229 deletions(-) diff --git a/maxdiff/tests/test_baselines/FrozenTest.amxd.txt b/maxdiff/tests/test_baselines/FrozenTest.amxd.txt index 715473a..208538f 100644 --- a/maxdiff/tests/test_baselines/FrozenTest.amxd.txt +++ b/maxdiff/tests/test_baselines/FrozenTest.amxd.txt @@ -2,10 +2,10 @@ MIDI Effect Device ------------------- Device is frozen ----- Contents ----- -Test.amxd: 36531 bytes, modified at 2026/01/28 10:27:01 UTC <= Device -ParamAbstraction.maxpat: 956 bytes, modified at 2026/01/28 10:25:56 UTC, 2 instances -MyAbstraction.maxpat: 1369 bytes, modified at 2026/01/28 10:26:01 UTC, 6 instances -AbstractionWithParameter.maxpat: 1569 bytes, modified at 2024/05/24 13:59:36 UTC, 2 instances +Test.amxd: 57285 bytes, modified at 2026/02/26 15:37:26 UTC <= Device +MyAbstraction.maxpat: 2027 bytes, modified at 2026/02/26 15:36:38 UTC, 6 instances +ParamAbstraction.maxpat: 1335 bytes, modified at 2026/02/26 15:36:29 UTC, 2 instances +AbstractionWithParameter.maxpat: 1334 bytes, modified at 2026/02/26 15:36:26 UTC, 2 instances hz-icon.svg: 484 bytes, modified at 2024/05/24 13:59:36 UTC, 3 instances beat-icon.svg: 533 bytes, modified at 2024/05/24 13:59:36 UTC, 3 instances fpic.png: 7094 bytes, modified at 2024/05/24 13:59:36 UTC, 5 instances diff --git a/maxdiff/tests/test_baselines/Test.amxd.txt b/maxdiff/tests/test_baselines/Test.amxd.txt index 99bd229..5a0c2db 100644 --- a/maxdiff/tests/test_baselines/Test.amxd.txt +++ b/maxdiff/tests/test_baselines/Test.amxd.txt @@ -15,23 +15,6 @@ parameters: inherited_shortname: 1 banks: 0: (MyBank) encoders: ['live.dial', 'InsideBpatcher', '-', '-', '-', '-', '-', '-'] buttons: ['live.text', '-', '-', '-', '-', '-', '-', 'live.menu'] -dependency_cache: - {'name': 'AbstractionWithParameter.maxpat', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'JSON', 'implicit': 1} - {'name': 'MyAbstraction.maxpat', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'JSON', 'implicit': 1} - {'name': 'ParamAbstraction.maxpat', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'JSON', 'implicit': 1} - {'name': 'TestScript.js', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'TEXT', 'implicit': 1} - {'name': 'VisibleBang.js', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'TEXT', 'implicit': 1} - {'name': 'beat-icon.svg', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'svg', 'implicit': 1} - {'name': 'collContent.txt', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'TEXT', 'implicit': 1} - {'name': 'fpic.png', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'PNG', 'implicit': 1} - {'name': 'hz-icon.svg', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'svg', 'implicit': 1} - {'name': 'my-maxnode-basic.js', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'TEXT', 'implicit': 1} - {'name': 'myTestTable', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'TEXT', 'implicit': 1} - {'name': 'mystorage.json', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'JSON', 'implicit': 1} - {'name': 'myxfade.genjit', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'gJIT', 'implicit': 1} - {'name': 'shakerkicksnare.aif', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'AIFF', 'implicit': 1} - {'name': 'times3.gendsp', 'bootpath': '~/maxdevtools/maxdiff/tests/test_files', 'type': 'gDSP', 'implicit': 1} - project: version: 1 | creationdate: 3590052786 | modificationdate: 3590052786 | viewrect: [25, 106, 300, 500] | autoorganize: 1 | hideprojectwindow: 1 | showdependencies: 1 | autolocalize: 0 | layout: {} | searchpath: {} | detailsvisible: 0 | amxdtype: 1835887981 | readonly: 0 | devpathtype: 0 | devpath: . | sortmode: 0 | viewmode: 0 | includepackages: 0 contents: @@ -39,7 +22,7 @@ project: collContent.txt ----------- patcher ----------- -appversion: 9.0.10-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] | default_fontsize: 10.0 | default_fontname: Arial Bold | gridsize: [8, 8] | boxanimatetime: 500 | latency: 0 | is_mpe: 0 | external_mpe_tuning_enabled: 0 | platform_compatibility: 0 | autosave: 0 +appversion: 9.1.3-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] | openrectmode: 0 | default_fontsize: 10.0 | default_fontname: Arial Bold | gridsize: [8, 8] | boxanimatetime: 500 | latency: 0 | is_mpe: 0 | external_mpe_tuning_enabled: 0 | platform_compatibility: 0 | autosave: 0 ----------- objects ----------- [comment NOTE: after any changes to this device, also update FrozenTest.amxd] [poly~ MyAbstraction] @@ -50,7 +33,7 @@ appversion: 9.0.10-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] [coll] [p ImplicitDependencies] varname: ImplicitDependencies ----------- patcher ----------- - appversion: 9.0.10-x64-1 | rect: [60, 130, 639, 710] + appversion: 9.1.3-x64-1 | rect: [60, 130, 639, 710] ----------- objects ----------- [js TestScript] filename: TestScript | parameter_enable: 0 [comment We would expect implicit dependencies for these but they don't seem to be added.] bubble: 1 | bubbleside: 2 | linecount: 2 @@ -73,17 +56,17 @@ appversion: 9.0.10-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] [jsui] filename: VisibleBang.js [live.menu] pictures: [hz-icon.svg, beat-icon.svg] | remapsvgcolors: 1 | parameter: | usepicture: 1 | usesvgviewbox: 1 [live.text] pictures: [hz-icon.svg, beat-icon.svg] | remapsvgcolors: 1 | parameter: | usepicture: 1 | usesvgviewbox: 1 - [playlist~] basictuning: 440 | clipheight: 28.0 | data: {'clips': [{'absolutepath': 'shakerkicksnare.aif', 'filename': 'shakerkicksnare.aif', 'filekind': 'audiofile', 'id': 'u400003311', 'loop': 1, 'content_state': {'loop': 1}}]} | mode: basic | originallength: [0, ticks] | originaltempo: 120.0 | quality: basic + [playlist~] clipheight: 28.0 | data: {'clips': [{'absolutepath': 'shakerkicksnare.aif', 'filename': 'shakerkicksnare.aif', 'filekind': 'audiofile', 'id': 'u400003311', 'loop': 1, 'content_state': {'loop': 1}}]} | mode: basic | quality: basic [pictslider] bkgndpict: fpic.png | clickedimage: 0 | knobpict: fpic.png [pictctrl] name: fpic.png [fpic] pic: fpic.png - [live.tab] annotation: Toggles between Beat Sync and Free running (Hz). | annotation_name: Time Mode | fontsize: 9.0 | livemode: 1 | num_lines_patching: 2 | num_lines_presentation: 2 | pictures: [hz-icon.svg, beat-icon.svg] | remapsvgcolors: 1 | parameter: | usepicture: 1 | usesvgviewbox: 1 | varname: Time Mode + [live.tab] annotation: Toggles between Beat Sync and Free running (Hz). | annotation_name: Time Mode | fontsize: 9.0 | livemode: 1 | num_lines_patching: 2 | num_lines_presentation: 2 | pictures: [hz-icon.svg, beat-icon.svg] | remapsvgcolors: 1 | parameter: | usepicture: 1 | usesvgviewbox: 1 | varname: Time Mode ----------- patch cords ----------- [pattr test] (1) => (0) [number] [message read myTestTable] (0) => (0) [table myTestTable] [bpatcher ThisWasAnAbstractionBeforeEmbeddingIt.maxpat] embed: 1 ----------- patcher ----------- - appversion: 9.0.10-x64-1 | rect: [927, 431, 640, 480] + appversion: 9.1.3-x64-1 | rect: [927, 431, 640, 480] ----------- objects ----------- [live.comment Embedded] [live.numbox] parameter: @@ -97,7 +80,7 @@ appversion: 9.0.10-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] [button] [gen @t exponent] ----------- patcher ----------- - appversion: 9.0.10-x64-1 | classnamespace: dsp.gen | rect: [84, 144, 653, 641] + appversion: 9.1.3-x64-1 | classnamespace: dsp.gen | rect: [84, 144, 653, 641] ----------- objects ----------- [codebox] //============================================================ @@ -140,7 +123,7 @@ appversion: 9.0.10-x64-1 | rect: [91, 153, 1288, 310] | openrect: [0, 0, 0, 169] [coll @embed 1] coll_data: {'count': 2, 'data': [{'key': 0, 'value': ['test']}, {'key': 1, 'value': ['another', 'test']}]} | embed: 1 | precision: 6 [p MySubpatcher] ----------- patcher ----------- - appversion: 9.0.10-x64-1 | rect: [805, 282, 271, 250] + appversion: 9.1.3-x64-1 | rect: [805, 282, 271, 250] ----------- objects ----------- [live.dial] parameter: [t b b] diff --git a/maxdiff/tests/test_files/AbstractionWithParameter.maxpat b/maxdiff/tests/test_files/AbstractionWithParameter.maxpat index b2254af..f029271 100644 --- a/maxdiff/tests/test_files/AbstractionWithParameter.maxpat +++ b/maxdiff/tests/test_files/AbstractionWithParameter.maxpat @@ -1,75 +1,43 @@ { - "patcher" : { - "fileversion" : 1, - "appversion" : { - "major" : 8, - "minor" : 5, - "revision" : 5, - "architecture" : "x64", - "modernui" : 1 - } -, - "classnamespace" : "box", - "rect" : [ 312.0, 228.0, 221.0, 176.0 ], - "bglocked" : 0, - "openinpresentation" : 0, - "default_fontsize" : 12.0, - "default_fontface" : 0, - "default_fontname" : "Arial", - "gridonopen" : 1, - "gridsize" : [ 15.0, 15.0 ], - "gridsnaponopen" : 1, - "objectsnaponopen" : 1, - "statusbarvisible" : 2, - "toolbarvisible" : 1, - "lefttoolbarpinned" : 0, - "toptoolbarpinned" : 0, - "righttoolbarpinned" : 0, - "bottomtoolbarpinned" : 0, - "toolbars_unpinned_last_save" : 0, - "tallnewobj" : 0, - "boxanimatetime" : 200, - "enablehscroll" : 1, - "enablevscroll" : 1, - "devicewidth" : 0.0, - "description" : "", - "digest" : "", - "tags" : "", - "style" : "", - "subpatcher_template" : "", - "assistshowspatchername" : 0, - "boxes" : [ { - "box" : { - "id" : "obj-1", - "maxclass" : "live.dial", - "numinlets" : 1, - "numoutlets" : 2, - "outlettype" : [ "", "float" ], - "parameter_enable" : 1, - "patching_rect" : [ 33.0, 20.0, 81.0, 48.0 ], - "saved_attribute_attributes" : { - "valueof" : { - "parameter_longname" : "MyParameter", - "parameter_shortname" : "MyParameter", - "parameter_type" : 0, - "parameter_unitstyle" : 0 - } - - } -, - "varname" : "live.dial" - } - - } - ], - "lines" : [ ], - "saved_attribute_attributes" : { - "default_plcolor" : { - "expression" : "" - } - - } - - } - -} + "patcher": { + "fileversion": 1, + "appversion": { + "major": 9, + "minor": 1, + "revision": 3, + "architecture": "x64", + "modernui": 1 + }, + "classnamespace": "box", + "rect": [ 312.0, 228.0, 221.0, 176.0 ], + "boxes": [ + { + "box": { + "id": "obj-1", + "maxclass": "live.dial", + "numinlets": 1, + "numoutlets": 2, + "outlettype": [ "", "float" ], + "parameter_enable": 1, + "patching_rect": [ 33.0, 20.0, 81.0, 48.0 ], + "saved_attribute_attributes": { + "valueof": { + "parameter_longname": "MyParameter", + "parameter_modmode": 0, + "parameter_shortname": "MyParameter", + "parameter_type": 0, + "parameter_unitstyle": 0 + } + }, + "varname": "live.dial" + } + } + ], + "lines": [], + "saved_attribute_attributes": { + "default_plcolor": { + "expression": "" + } + } + } +} \ No newline at end of file diff --git a/maxdiff/tests/test_files/FrozenTest.amxd b/maxdiff/tests/test_files/FrozenTest.amxd index 8b0db1c60f7dc6ca4df4720f740dcf987b7415f7..7d08fae85792b972b0d1a61dd9e5d9fc1a62e7bf 100644 GIT binary patch delta 57653 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 W_W9e`o9f}u_edSC`u^6rKmR{*e?Y|m delta 23338 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 diff --git a/maxdiff/tests/test_files/MyAbstraction.maxpat b/maxdiff/tests/test_files/MyAbstraction.maxpat index bf73c54..55be0c1 100644 --- a/maxdiff/tests/test_files/MyAbstraction.maxpat +++ b/maxdiff/tests/test_files/MyAbstraction.maxpat @@ -1,79 +1,71 @@ { - "patcher" : { - "fileversion" : 1, - "appversion" : { - "major" : 9, - "minor" : 0, - "revision" : 10, - "architecture" : "x64", - "modernui" : 1 - } -, - "classnamespace" : "box", - "rect" : [ 312.0, 228.0, 221.0, 176.0 ], - "gridsize" : [ 15.0, 15.0 ], - "boxes" : [ { - "box" : { - "id" : "obj-3", - "maxclass" : "button", - "numinlets" : 1, - "numoutlets" : 1, - "outlettype" : [ "bang" ], - "parameter_enable" : 0, - "patching_rect" : [ 113.0, 60.0, 24.0, 24.0 ] - } - - } -, { - "box" : { - "comment" : "", - "id" : "obj-2", - "index" : 1, - "maxclass" : "outlet", - "numinlets" : 1, - "numoutlets" : 0, - "patching_rect" : [ 40.0, 60.0, 30.0, 30.0 ] - } - - } -, { - "box" : { - "comment" : "", - "id" : "obj-1", - "index" : 1, - "maxclass" : "inlet", - "numinlets" : 0, - "numoutlets" : 1, - "outlettype" : [ "" ], - "patching_rect" : [ 40.0, 22.0, 30.0, 30.0 ] - } - - } - ], - "lines" : [ { - "patchline" : { - "destination" : [ "obj-2", 0 ], - "order" : 1, - "source" : [ "obj-1", 0 ] - } - - } -, { - "patchline" : { - "destination" : [ "obj-3", 0 ], - "order" : 0, - "source" : [ "obj-1", 0 ] - } - - } - ], - "saved_attribute_attributes" : { - "default_plcolor" : { - "expression" : "" - } - - } - - } - -} + "patcher": { + "fileversion": 1, + "appversion": { + "major": 9, + "minor": 1, + "revision": 3, + "architecture": "x64", + "modernui": 1 + }, + "classnamespace": "box", + "rect": [ 312.0, 228.0, 221.0, 176.0 ], + "boxes": [ + { + "box": { + "id": "obj-3", + "maxclass": "button", + "numinlets": 1, + "numoutlets": 1, + "outlettype": [ "bang" ], + "parameter_enable": 0, + "patching_rect": [ 113.0, 60.0, 24.0, 24.0 ] + } + }, + { + "box": { + "comment": "", + "id": "obj-2", + "index": 1, + "maxclass": "outlet", + "numinlets": 1, + "numoutlets": 0, + "patching_rect": [ 40.0, 60.0, 30.0, 30.0 ] + } + }, + { + "box": { + "comment": "", + "id": "obj-1", + "index": 1, + "maxclass": "inlet", + "numinlets": 0, + "numoutlets": 1, + "outlettype": [ "" ], + "patching_rect": [ 40.0, 22.0, 30.0, 30.0 ] + } + } + ], + "lines": [ + { + "patchline": { + "destination": [ "obj-2", 0 ], + "order": 1, + "source": [ "obj-1", 0 ] + } + }, + { + "patchline": { + "destination": [ "obj-3", 0 ], + "order": 0, + "source": [ "obj-1", 0 ] + } + } + ], + "saved_attribute_attributes": { + "default_plcolor": { + "expression": "" + } + } + } +} \ No newline at end of file diff --git a/maxdiff/tests/test_files/ParamAbstraction.maxpat b/maxdiff/tests/test_files/ParamAbstraction.maxpat index 45171d7..817316c 100644 --- a/maxdiff/tests/test_files/ParamAbstraction.maxpat +++ b/maxdiff/tests/test_files/ParamAbstraction.maxpat @@ -1,50 +1,43 @@ { - "patcher" : { - "fileversion" : 1, - "appversion" : { - "major" : 9, - "minor" : 0, - "revision" : 10, - "architecture" : "x64", - "modernui" : 1 - } -, - "classnamespace" : "box", - "rect" : [ 192.0, 591.0, 640.0, 480.0 ], - "gridsize" : [ 15.0, 15.0 ], - "boxes" : [ { - "box" : { - "id" : "obj-1", - "maxclass" : "live.dial", - "numinlets" : 1, - "numoutlets" : 2, - "outlettype" : [ "", "float" ], - "parameter_enable" : 1, - "patching_rect" : [ 80.0, 64.0, 41.0, 48.0 ], - "saved_attribute_attributes" : { - "valueof" : { - "parameter_longname" : "InsideBpatcher", - "parameter_modmode" : 0, - "parameter_shortname" : "live.dial", - "parameter_type" : 0, - "parameter_unitstyle" : 0 - } - - } -, - "varname" : "live.dial" - } - - } - ], - "lines" : [ ], - "saved_attribute_attributes" : { - "default_plcolor" : { - "expression" : "" - } - - } - - } - -} + "patcher": { + "fileversion": 1, + "appversion": { + "major": 9, + "minor": 1, + "revision": 3, + "architecture": "x64", + "modernui": 1 + }, + "classnamespace": "box", + "rect": [ 192.0, 591.0, 640.0, 480.0 ], + "boxes": [ + { + "box": { + "id": "obj-1", + "maxclass": "live.dial", + "numinlets": 1, + "numoutlets": 2, + "outlettype": [ "", "float" ], + "parameter_enable": 1, + "patching_rect": [ 80.0, 64.0, 41.0, 48.0 ], + "saved_attribute_attributes": { + "valueof": { + "parameter_longname": "InsideBpatcher", + "parameter_modmode": 0, + "parameter_shortname": "live.dial", + "parameter_type": 0, + "parameter_unitstyle": 0 + } + }, + "varname": "live.dial" + } + } + ], + "lines": [], + "saved_attribute_attributes": { + "default_plcolor": { + "expression": "" + } + } + } +} \ No newline at end of file diff --git a/maxdiff/tests/test_files/Test.amxd b/maxdiff/tests/test_files/Test.amxd index a77c841b21b67b95bb79222f05e27de93fcbfbbf..2acb4fa1bcf4922214ba53517f636931399107ee 100644 GIT binary patch literal 57317 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 From a0ba14b048d17a92854b1238750c285a0fcba8e3 Mon Sep 17 00:00:00 2001 From: mkp Date: Tue, 24 Feb 2026 15:37:31 +0100 Subject: [PATCH 3/3] maxdiff: print parameter properties in parameter summary This makes it much easier to spot regressions in the parameter space when refactoring devices --- maxdiff/patch_printer.py | 110 +++++++++++++++--- .../tests/test_baselines/FrozenTest.amxd.txt | 8 +- maxdiff/tests/test_baselines/Test.amxd.txt | 78 ++++++++++++- maxdiff/tests/test_files/FrozenTest.amxd | Bin 431418 -> 431681 bytes .../tests/test_files/ParamAbstraction.maxpat | 2 + maxdiff/tests/test_files/Test.amxd | Bin 57317 -> 57545 bytes 6 files changed, 178 insertions(+), 20 deletions(-) diff --git a/maxdiff/patch_printer.py b/maxdiff/patch_printer.py index 32c2ad6..eff34f1 100644 --- a/maxdiff/patch_printer.py +++ b/maxdiff/patch_printer.py @@ -255,6 +255,66 @@ def get_object_names_from_ids_recursive(id_hierarchy: list, boxes_parent: list): return name +def get_param_properties_from_ids_recursive(id_hierarchy: list, boxes_parent: list): + """Travels an object id hierarchy string in the form of "obj-n::obj-m:: etc" and finds properties + contained in valueof in saved_attribute_attributes. + + If an object id cannot be found in the patch, for instance because it refers to an object + inside an abstraction, returns an empty object. + """ + + # every entry of "boxes_parent" has a single item "box" + boxes = list(map(lambda val: val["box"], boxes_parent)) + + for box in boxes: + if "id" in box and id_hierarchy[0] == box["id"]: + if len(id_hierarchy) > 1: + if "patcher" in box: + subpatcher_boxes = box["patcher"]["boxes"] + return get_param_properties_from_ids_recursive( + id_hierarchy[1:], subpatcher_boxes + ) + else: + return {} # can't traverse into abstraction + else: + saved_attrs = box.get("saved_attribute_attributes", {}) + return saved_attrs.get("valueof", {}) + + return {} # object not found + + +def get_param_annotations_from_ids_recursive(id_hierarchy: list, boxes_parent: list): + """Travels an object id hierarchy string in the form of "obj-n::obj-m:: etc" and finds the + parameter's annotations saved as box properties + + If an object id cannot be found in the patch, for instance because it refers to an object + inside an abstraction, returns an empty object. + """ + + # every entry of "boxes_parent" has a single item "box" + boxes = list(map(lambda val: val["box"], boxes_parent)) + + for box in boxes: + if "id" in box and id_hierarchy[0] == box["id"]: + if len(id_hierarchy) > 1: + if "patcher" in box: + subpatcher_boxes = box["patcher"]["boxes"] + return get_param_annotations_from_ids_recursive( + id_hierarchy[1:], subpatcher_boxes + ) + else: + return {} # can't traverse into abstraction + else: + annotation = box.get("annotation", {}) + annotation_name = box.get("annotation_name", {}) + return { + "annotation": annotation, + "annotation_name": annotation_name, + } + + return {} # object not found + + def get_properties_to_print( box_or_patcher: dict, default: dict, skip_properties: list[str] ) -> dict: @@ -390,24 +450,46 @@ def get_parameters_string_block(patcher: dict) -> str: parameters_string += f"\t{object_names}: {item}" + if index.startswith("obj"): + id_tokens = index.split("::") + param_properties = get_param_properties_from_ids_recursive( + id_tokens, patcher["boxes"] + ) + + for key, value in param_properties.items(): + key_text = ( + key[len("parameter_") :] if key.startswith("parameter_") else key + ) + parameters_string += f"\n\t\t{key_text}: {value}" + + param_annotations = get_param_annotations_from_ids_recursive( + id_tokens, patcher["boxes"] + ) + + if param_annotations != {}: + parameters_string += "\n\t\t____Info____" + parameters_string += f"\n\t\t{param_annotations['annotation_name'] if 'annotation_name' in param_annotations and param_annotations['annotation_name'] != {} else ''}" + if ( + "annotation" in param_annotations + and param_annotations["annotation"] != {} + ): + value_text = "\n\t\t".join( + str(param_annotations["annotation"]).splitlines() + ) + parameters_string += f"\n\t\t{value_text}" + else: + parameters_string += "\n\t\t" + if index in param_overrides: param_override = param_overrides[index] - override_print = [ - param_override.get("parameter_longname", "-"), - param_override.get("parameter_shortname", "-"), - str(param_override.get("parameter_linknames", "-")), - ] + parameters_string += f"\n\toverrides:" for key, value in param_override.items(): - if key in [ - "parameter_longname", - "parameter_shortname", - "parameter_linknames", - ]: - continue - override_print.append(f"{key}: {value}") - - parameters_string += f" > override > {str(override_print)}" + key_text = ( + key[len("parameter_") :] if key.startswith("parameter_") else key + ) + parameters_string += f"\n\t\t{key_text}: {value}" + parameters_string += "\n" if param_banks != {}: diff --git a/maxdiff/tests/test_baselines/FrozenTest.amxd.txt b/maxdiff/tests/test_baselines/FrozenTest.amxd.txt index 208538f..ec8ed8d 100644 --- a/maxdiff/tests/test_baselines/FrozenTest.amxd.txt +++ b/maxdiff/tests/test_baselines/FrozenTest.amxd.txt @@ -2,10 +2,10 @@ MIDI Effect Device ------------------- Device is frozen ----- Contents ----- -Test.amxd: 57285 bytes, modified at 2026/02/26 15:37:26 UTC <= Device -MyAbstraction.maxpat: 2027 bytes, modified at 2026/02/26 15:36:38 UTC, 6 instances -ParamAbstraction.maxpat: 1335 bytes, modified at 2026/02/26 15:36:29 UTC, 2 instances -AbstractionWithParameter.maxpat: 1334 bytes, modified at 2026/02/26 15:36:26 UTC, 2 instances +Test.amxd: 57392 bytes, modified at 2026/02/26 15:45:49 UTC <= Device +MyAbstraction.maxpat: 2027 bytes, modified at 2026/02/26 15:38:57 UTC, 6 instances +ParamAbstraction.maxpat: 1491 bytes, modified at 2026/02/26 15:40:50 UTC, 2 instances +AbstractionWithParameter.maxpat: 1334 bytes, modified at 2026/02/26 15:38:57 UTC, 2 instances hz-icon.svg: 484 bytes, modified at 2024/05/24 13:59:36 UTC, 3 instances beat-icon.svg: 533 bytes, modified at 2024/05/24 13:59:36 UTC, 3 instances fpic.png: 7094 bytes, modified at 2024/05/24 13:59:36 UTC, 5 instances diff --git a/maxdiff/tests/test_baselines/Test.amxd.txt b/maxdiff/tests/test_baselines/Test.amxd.txt index 5a0c2db..27e14e8 100644 --- a/maxdiff/tests/test_baselines/Test.amxd.txt +++ b/maxdiff/tests/test_baselines/Test.amxd.txt @@ -2,16 +2,90 @@ MIDI Effect Device ------------------- parameters: [p MySubpatcher]/[live.dial]: ['In a subpatcher', 'live.dial', 0] + longname: In a subpatcher + modmode: 0 + shortname: live.dial + type: 0 + unitstyle: 0 + ____Info____ + + [bpatcher ParamAbstraction.maxpat]/[obj-1]: ['InsideBpatcher', 'live.dial', 0] [AbstractionWithParameter]/[obj-1]: ['MyParameter', 'MyParameter', 0] - [AbstractionWithParameter]/[obj-1]: ['MyParameter[1]', 'MyParameter', 0] > override > ['MyParameter[1]', '-', '-'] + [AbstractionWithParameter]/[obj-1]: ['MyParameter[1]', 'MyParameter', 0] + overrides: + longname: MyParameter[1] [p ImplicitDependencies]/[live.tab]: ['Time Mode', 'Time Mode', 0] + enum: ['Free', 'Sync'] + invisible: 2 + linknames: 1 + longname: Time Mode + mmax: 1 + modmode: 0 + shortname: Time Mode + type: 2 + unitstyle: 9 + ____Info____ + Time Mode + Toggles between Beat Sync and Free running (Hz). [p ImplicitDependencies]/[live.text]: ['live.text', 'live.text', 0] + button_mode: Momentary + enum: ['val1', 'val2'] + longname: live.text + mmax: 1 + modmode: 0 + shortname: live.text + type: 2 + ____Info____ + + [p ImplicitDependencies]/[live.menu]: ['live.menu', 'live.menu', 0] - [bpatcher ParamAbstraction.maxpat]/[obj-1]: ['OverruledParamLongName', 'OverruledParamShortName', 0] > override > ['OverruledParamLongName', 'OverruledParamShortName', '-'] + button_mode: Cycle + enum: ['one', 'two', 'three'] + longname: live.menu + mmax: 2 + modmode: 0 + shortname: live.menu + type: 2 + ____Info____ + + + [bpatcher ParamAbstraction.maxpat]/[obj-1]: ['OverruledParamLongName', 'OverruledParamShortName', 0] + overrides: + invisible: 0 + longname: OverruledParamLongName + modmode: 0 + range: [0, 127] + shortname: OverruledParamShortName + type: 1 + unitstyle: 0 [bpatcher ThisWasAnAbstractionBeforeEmbeddingIt.maxpat ]/[live.numbox]: ['EmbeddedParam', 'Embedded', 0] + longname: EmbeddedParam + modmode: 3 + shortname: Embedded + type: 0 + unitstyle: 0 + ____Info____ + + [live.dial]: ['live.dial', 'live.dial', 0] + longname: live.dial + modmode: 0 + shortname: live.dial + type: 0 + unitstyle: 0 + ____Info____ + + [live.dial]: ['live.dial[1]', 'live.dial', 0] + longname: live.dial[1] + modmode: 0 + shortname: live.dial + type: 0 + unitstyle: 0 + ____Info____ + + inherited_shortname: 1 banks: 0: (MyBank) encoders: ['live.dial', 'InsideBpatcher', '-', '-', '-', '-', '-', '-'] buttons: ['live.text', '-', '-', '-', '-', '-', '-', 'live.menu'] diff --git a/maxdiff/tests/test_files/FrozenTest.amxd b/maxdiff/tests/test_files/FrozenTest.amxd index 7d08fae85792b972b0d1a61dd9e5d9fc1a62e7bf..33e2d80e2631efd5ff7071743e0548dfe6ccb355 100644 GIT binary patch delta 467 zcmdnBO6uSmsR=S7iqqH_aw{B?85kG@fS7@St-o=j!8iNO^Boq>V9U%a%Ph{E%-F3k zIUt*J@`W4RlYMSlOtycmI4Ou*peQjfJypp{AzHyeN5Rm@d@|#9>UZuq)3W<67B^jwj3OSi&sd_1yi8*=- zKB*<@#R?^$oQyR7p%O*!H|R@l|``D@Gt@0%B$$X4#(jinVwN(*uL)*ZSD>n51>5v-Pui zF+FgYK5qh>0?X55k`t$w^|RUYUd~T5HUb6%4+FysZJ4AK)AVQkY(Y$K|G`9n%Ht-m z*)e@K0g0qBeU$*w+S3guvY9h}pFVd2o6hv96WQ#UgdT$=#HYWV$mY*fYB}9*5?dBi zSs7eVcKW?ZY(`8KZqwIIVKbTTHW|oiaD{NzfjB)gL3*^O^G;ziXX@<$$v8}Jo5H5X Q)UO2Mq%rkZf=p8Z0M~f0vH$=8 delta 380 zcmX@OMrzk8sR=S7Qd8L&aw{B?85kG@fS7@St*>gM!8d!sy!@2Z_@vCd_=3ce3?(ZC zrO6Auv;~#&3UV<-H>)}6mwn>o`rH4rC@N$}3}jg#3-roWuZ z#xq@ZGMgGxiP7}NDL`cfliBQ4eFf=G^kG+E@H&gR|K+81pppBjSv6; diff --git a/maxdiff/tests/test_files/ParamAbstraction.maxpat b/maxdiff/tests/test_files/ParamAbstraction.maxpat index 817316c..7a32aff 100644 --- a/maxdiff/tests/test_files/ParamAbstraction.maxpat +++ b/maxdiff/tests/test_files/ParamAbstraction.maxpat @@ -13,6 +13,8 @@ "boxes": [ { "box": { + "annotation": "Just another live.dial. Let's test if we can override this.", + "annotation_name": "Just a live.dial", "id": "obj-1", "maxclass": "live.dial", "numinlets": 1, diff --git a/maxdiff/tests/test_files/Test.amxd b/maxdiff/tests/test_files/Test.amxd index 2acb4fa1bcf4922214ba53517f636931399107ee..c5294a2931552e84338544ec0f3aecc3aa2f38d3 100644 GIT binary patch delta 99 zcmV-p0G$8jzXQp^1CSg7so=3564?f6Zgy#NX_N7aAd^6A36sFs3zIzAIFlZ1A(QY? z3lMT)Zf9j8Iv`shFf1T3GB=a)wj-19xDAtm*%*^k*&&lKeFu}JOc#==DU(nJ9ka*T F9tJblDBS=6 delta 40 ycmV+@0N4M?!2{*L1CSg7#ow_W64{f#*bI|u**KH%xDAsI+8C4Je=f7D+8zd