Fabian Peter Hammerle 9 lat temu
rodzic
commit
83250aaa32
3 zmienionych plików z 177 dodań i 0 usunięć
  1. 157 0
      scripts/jack-plumber
  2. 2 0
      setup.cfg
  3. 18 0
      setup.py

+ 157 - 0
scripts/jack-plumber

@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# PYTHON_ARGCOMPLETE_OK
+
+import re
+import jack
+from gi.repository import GLib
+
+loop = GLib.MainLoop()
+
+class Instruction(object):
+    
+    def execute(self, client, port):
+        pass
+
+    def __repr__(self):
+        return type(self).__name__ + '(' + ', '.join([a + ': ' + repr(getattr(self, a)) for a in vars(self)]) + ')'
+
+class PortRenameInstruction(Instruction):
+
+    def __init__(self, new_port_name):
+        self.new_port_name = new_port_name
+
+    def execute(self, client, port):
+        port.set_short_name(self.new_port_name)
+
+class PortConnectInstruction(Instruction):
+
+    def __init__(self, other_client_pattern, other_port_pattern):
+        self.other_client_pattern = other_client_pattern
+        self.other_port_pattern = other_port_pattern
+
+    def execute(self, client, port):
+        for other_port in [
+                p for p in client.get_ports() 
+                    if re.match(self.other_client_pattern, p.get_client_name())
+                    and re.match(self.other_port_pattern, p.get_short_name())
+                ]:
+            try:
+                if port.is_output():
+                    client.connect(port, other_port)
+                else:
+                    client.connect(other_port, port)
+            except jack.ConnectionExists: 
+                pass
+
+def check_port(client, port, instructions, rename = True):
+    for client_pattern in instructions: 
+        if re.match(client_pattern, port.get_client_name()):
+            for port_pattern in instructions[client_pattern]:
+                if re.match(port_pattern, port.get_short_name()):
+                    for instruction in instructions[client_pattern][port_pattern]:
+                        if rename or not isinstance(instruction, PortRenameInstruction):
+                            GLib.idle_add(lambda: instruction.execute(client, port))
+
+def port_registered(client, port, instructions):
+    check_port(client, port, instructions)
+
+def port_renamed(client, port, old_name, new_name, instructions):
+    """ Avoid recursion by skipping rename instructions. """
+    check_port(client, port, instructions, rename = False)
+
+def server_shutdown(client, reason, arg = None):
+    loop = arg
+    print(reason)
+    loop.quit()
+
+def run(instructions):
+    
+    jack_client = jack.Client('plumber')
+    jack_client.set_port_registered_callback(port_registered, instructions)
+    jack_client.set_port_renamed_callback(port_renamed, instructions)
+    jack_client.set_shutdown_callback(server_shutdown, loop)
+    jack_client.activate()
+
+    for port in jack_client.get_ports():
+        check_port(jack_client, port, instructions)
+
+    try:
+        loop.run()
+    except KeyboardInterrupt:
+        pass
+
+def _init_argparser():
+
+    import argparse
+    argparser = argparse.ArgumentParser(description = None)
+    argparser.add_argument(
+            '--rename-port', 
+            dest = 'port_renaming_instructions',
+            action = 'append',
+            nargs = 3,
+            metavar = ('client_name_pattern', 'port_name_pattern', 'new_port_name'),
+            )
+    argparser.add_argument(
+            '--connect-ports', 
+            dest = 'port_connecting_instructions',
+            action = 'append',
+            nargs = 4,
+            metavar = (
+                'client_name_pattern_1', 
+                'port_name_pattern_1', 
+                'client_name_pattern_2', 
+                'port_name_pattern_2', 
+                ),
+            )
+    return argparser
+
+def register_instruction(client_pattern, port_pattern, instruction, instructions):
+    if not client_pattern in instructions:
+        instructions[client_pattern] = {}
+    if not port_pattern in instructions[client_pattern]:
+        instructions[client_pattern][port_pattern] = []
+    instructions[client_pattern][port_pattern].append(instruction)
+
+def main(argv):
+
+    argparser = _init_argparser()
+    try:
+        import argcomplete
+        argcomplete.autocomplete(argparser)
+    except ImportError:
+        pass
+    args = argparser.parse_args(argv)
+
+    instructions = {}
+    if args.port_renaming_instructions:
+        for renaming_instruction in args.port_renaming_instructions:
+            (client_pattern, port_pattern, new_port_name) = renaming_instruction
+            register_instruction(
+                client_pattern,
+                port_pattern,
+                PortRenameInstruction(new_port_name),
+                instructions,
+                )
+    if args.port_connecting_instructions:
+        for connecting_instruction in args.port_connecting_instructions:
+            (client_pattern_1, port_pattern_1, client_pattern_2, port_pattern_2) = connecting_instruction
+            register_instruction(
+                client_pattern_1,
+                port_pattern_1,
+                PortConnectInstruction(client_pattern_2, port_pattern_2),
+                instructions,
+                )
+            register_instruction(
+                client_pattern_2,
+                port_pattern_2,
+                PortConnectInstruction(client_pattern_1, port_pattern_1),
+                instructions,
+                )
+            
+    run(instructions)
+
+    return 0
+
+if __name__ == "__main__":
+    import sys
+    sys.exit(main(sys.argv[1:]))

+ 2 - 0
setup.cfg

@@ -0,0 +1,2 @@
+[metadata]
+description-file = README.md

+ 18 - 0
setup.py

@@ -0,0 +1,18 @@
+from setuptools import setup
+
+import glob
+
+setup(
+    name = 'jack-plumber',
+    version = '0.1',
+    description = 'Automatically rename and connect ports registered in JACK Audio Server',
+    author = 'Fabian Peter Hammerle',
+    author_email = 'fabian.hammerle@gmail.com',
+    url = 'https://github.com/fphammerle/jack-plumber',
+    download_url = 'https://github.com/fphammerle/jack-plumber/tarball/0.1',
+    keywords = ['audio', 'jack'],
+    classifiers = [],
+    scripts = glob.glob('scripts/*'),
+    install_requires = ['jacker>=0.3.1'],
+    tests_require = ['pytest']
+    )