summaryrefslogtreecommitdiffstats
path: root/src/clients/python/scripts/flatten.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/clients/python/scripts/flatten.py')
-rwxr-xr-xsrc/clients/python/scripts/flatten.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/clients/python/scripts/flatten.py b/src/clients/python/scripts/flatten.py
new file mode 100755
index 00000000..eaf8084d
--- /dev/null
+++ b/src/clients/python/scripts/flatten.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python
+
+###############################################################################
+#
+# flatten.py - a python script that merges all subpatches in an Om patch
+# into the parent patch
+#
+# Copyright (C) 2005 Lars Luthman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+###############################################################################
+
+import omsynth
+import os,time,sys
+
+
+def getPatchBounds(patch):
+ """Returns the smallest rectangle that contains all modules in the patch."""
+ min_x = None
+ min_y = None
+ max_x = None
+ max_y = None
+ for node in patch.getNodes():
+ x = node.metadata['module-x']
+ y = node.metadata['module-y']
+ if (x != None):
+ if (min_x == None or float(x) < min_x):
+ min_x = float(x)
+ if (max_x == None or float(x) > max_x):
+ max_x = float(x)
+ if (y != None):
+ if (min_y == None or float(y) < min_y):
+ min_y = float(y)
+ if (max_y == None or float(y) > max_y):
+ max_y = float(y)
+ if min_x == None:
+ min_x = 0
+ max_x = 0
+ if min_y == None:
+ min_y = 0
+ max_y = 0
+
+ return (min_x, min_y, max_x, max_y)
+
+
+def cloneNode(om, node, patch):
+ """Copy a node into a patch, return the new node's name."""
+
+ # create a node with a free name in the parent
+ names = []
+ for node2 in patch.getNodes():
+ names.append(node2.getName())
+ for patch2 in patch.getPatches():
+ names.append(patch2.getName())
+ names.sort()
+ name = node.getName()
+ for name2 in names:
+ if name2 == name:
+ name = name + '_'
+ om.synth.create_node.async(patch.getPath() + '/' + name,
+ node.plugintype, node.libname,
+ node.pluginlabel, node.polyphonic)
+
+ # copy port values
+ for port in node.getPorts():
+ path = '%s/%s/%s' % (patch.getPath(), name, port.getName())
+ om.synth.set_port_value_slow.async(path, port.value)
+ om.metadata.set.async(path, 'user-min', '%f' % port.minvalue)
+ om.metadata.set.async(path, 'user-max', '%f' % port.maxvalue)
+ return name
+
+
+def flatten(om, patch):
+ """Merge all subpatches into the parent patch."""
+
+ # something is wrong, we don't have a patch
+ if patch == None:
+ return
+
+ # iterate over all subpatches
+ for subpatch in patch.getPatches():
+ flatten(om, subpatch)
+ lookup = {}
+
+ # copy all nodes from the subpatch to the parent patch
+ for node in subpatch.getNodes():
+ lookup[node.getName()] = cloneNode(om, node, patch)
+
+ # copy all connections
+ for node in subpatch.getNodes():
+ for port in node.getPorts():
+ if port.direction == 'OUTPUT':
+ for target in port.getConnections().keys():
+ targetname = '%s/%s' % (lookup[target.getParent().getName()], target.getName())
+ om.synth.connect.async(patch.getPath() + '/' +
+ lookup[node.getName()] + '/' +
+ port.getName(),
+ patch.getPath() + '/' +
+ targetname)
+
+ # make external connections
+ for node in subpatch.getNodes():
+ if node.libname == '':
+ lbl = node.pluginlabel
+
+ if lbl == 'audio_input' or lbl == 'control_input':
+ port1 = node.getPort('in')
+ for port2 in port1.getConnections().keys():
+ dst = '%s/%s/%s' % (patch.getPath(), lookup[port2.getParent().getName()], port2.getName())
+ port4 = subpatch.getPort(node.getName())
+ conns = port4.getConnections().keys()
+ if len(conns) == 0:
+ portValue = port4.value
+ om.synth.set_port_value_slow.async(dst, portValue)
+ else:
+ for port3 in port4.getConnections().keys():
+ src = port3.getPath()
+ om.synth.connect.async(src, dst)
+
+ if lbl == 'audio_output' or lbl == 'control_output':
+ port2 = node.getPort('out', True)
+ for port1 in port2.getConnections().keys():
+ src = '%s/%s/%s' % (patch.getPath(), lookup[port1.getParent().getName()], port1.getName())
+ port3 = subpatch.getPort(node.getName())
+ for port4 in port3.getConnections().keys():
+ dst = port4.getPath()
+ om.synth.connect.async(src, dst)
+
+ # destroy all input and output nodes from the subpatch
+ for node in subpatch.getNodes():
+ if node.libname == '':
+ lbl = node.pluginlabel
+ if (lbl == 'audio_input' or lbl == 'control_input' or
+ lbl == 'audio_output' or lbl == 'control_output'):
+ om.synth.destroy_node.async('%s/%s' % (patch.getPath(),
+ lookup[node.getName()]))
+
+ # calculate where to move all the new nodes
+ (min_x, min_y, max_x, max_y) = getPatchBounds(subpatch)
+ sub_x = subpatch.metadata['module-x']
+ if sub_x == None:
+ sub_x = 0
+ sub_y = subpatch.metadata['module-y']
+ if sub_y == None:
+ sub_y = 0
+ x_offset = float(sub_x)
+ if min_x != None:
+ x_offset = float(sub_x) - min_x
+ y_offset = float(sub_y)
+ if min_y != None:
+ y_offset = float(sub_y) - min_y
+
+ # move the new nodes
+ for node in subpatch.getNodes():
+ x = float(node.metadata['module-x'])
+ if x == None:
+ x = 0
+ om.metadata.set.async('%s/%s' % (patch.getPath(),
+ lookup[node.getName()]),
+ 'module-x', '%f' % (x + x_offset))
+ y = float(node.metadata['module-y'])
+ if y == None:
+ y = 0
+ om.metadata.set.async('%s/%s' % (patch.getPath(),
+ lookup[node.getName()]),
+ 'module-y', '%f' % (y + y_offset))
+
+ # move the old nodes in the patch
+ x_offset = 0
+ if min_x != None and max_x != None:
+ x_offset = max_x - min_x
+ y_offset = 0
+ if min_y != None and max_y != None:
+ y_offset = max_y - min_y
+ for node in patch.getNodes():
+ if node.getName() not in lookup.values():
+ x = node.metadata['module-x']
+ if x != None and float(x) > float(sub_x):
+ om.metadata.set.async(node.getPath(), 'module-x',
+ '%f' % (float(x) + x_offset))
+ y = node.metadata['module-y']
+ if y != None and float(y) > float(sub_y):
+ om.metadata.set.async(node.getPath(), 'module-y',
+ '%f' % (float(y) + y_offset))
+ # destroy the subpatch
+ om.synth.destroy_patch(subpatch.getPath())
+
+
+def main(om):
+ om.setEnvironment(omsynth.Environment())
+ om.engine.activate.async()
+ om.engine.load_plugins.async()
+ om.request.all_objects(om.getAddressAsString())
+
+ # wait for all the data to arrive (there should be a cleaner way)
+ time.sleep(3)
+
+ patch = om.getEnvironment().getPatch(sys.argv[1], True);
+ flatten(om, patch)
+
+ os._exit(0)
+
+
+if len(sys.argv) > 1:
+ if sys.argv[1] == "--name":
+ print "Flatten patch"
+ os._exit(0)
+ elif sys.argv[1] == "--shortdesc":
+ print "Merge the contents of all subpatches into the parent patch";
+ os._exit(0)
+ elif sys.argv[1] == "--signature":
+ print "%p";
+ os._exit(0)
+ else:
+ omsynth.startClient(main)
+
+else:
+ print "Which patch do you want to flatten?"
+ os._exit(0)