#!/usr/bin/env python # Ingen Interactive Shell # Copyright 2011-2012 David Robillard # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import os.path import shlex import socket import sys import time import re try: import readline except: pass class Client: def __init__(self, uri='unix:///tmp/ingen.sock'): print 'Connecting to server %s' % uri self.msg_id = 1 if uri.startswith('unix://'): self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.connect(uri[len('unix://'):]) elif uri.startswith('tcp://'): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) parsed = re.split('[:/]', uri[len('tcp://'):]) addr = (parsed[0], int(parsed[1])) self.sock.connect(addr) def __del__(self): self.sock.close() def msgencode(self, msg): if sys.version_info[0] == 3: return bytes(msg, 'utf-8') else: return msg def msg_subject(self): #self.msg_id += 1 #return '_:msg%d' % self.msg_id return '[]' def send(self, msg): self.sock.send(self.msgencode(msg)) return True #response = self.sock.recv(1024) # if response != self.msgencode('OK'): # print('Error: %s' % response) # return False # else: # return True def put(self, path, body): return self.send(''' %s a patch:Put ; patch:subject <%s> ; patch:body [ %s ] . ''' % (self.msg_subject(), path, body)) def set(self, path, body): return self.send(''' %s a patch:Set ; patch:subject <%s> ; patch:body [ %s ] . ''' % (self.msg_subject(), path, body)) def connect(self, tail, head): return self.send(''' %s a patch:Put ; patch:subject <%s> ; patch:body [ a ingen:Edge ; ingen:tail <%s> ; ingen:head <%s> ; ] . ''' % (self.msg_subject(), os.path.commonprefix([tail, head]), tail, head)) def disconnect(self, tail, head): return self.send(''' %s a patch:Delete ; patch:body [ a ingen:Edge ; ingen:tail <%s> ; ingen:head <%s> ; ] . ''' % (self.msg_subject(), tail, head)) def delete(self, path): return self.send(''' %s a patch:Delete ; patch:subject <%s> . ''' % (self.msg_subject(), path)) def print_usage(): print('''Usage: ingenish [OPTION]... [COMMAND [ARGUMENT]...] A command line interface to an Ingen server. A command can be given directly on the command line, or when run with no arguments an interactive shell is launched. Options: -s ADDRESS The address of the Ingen server. Default is the local server at unix:///tmp/ingen.sock but remote servers can be used with an address like tcp:///my-ingen-server-host:16180 Commands: put PATH TURTLE_FRAGMENT set PATH TURTLE_FRAGMENT connect TAIL_PATH HEAD_PATH disconnect TAIL_PATH HEAD_PATH delete PATH help exit Paths are UNIX-style paths with strict LV2 symbol components, e.g. /foo/bar_2. Turtle fragments are used verbatim as the body of blank nodes, the syntax is identical to the descriptions in Ingen patch files. Example: ingenish put /left_in 'a lv2:InputPort ; a lv2:AudioPort' ingenish put /left_out 'a lv2:OutputPort ; a lv2:AudioPort' ingenish put /tone 'a ingen:Node ; ingen:prototype ' ingenish put /combo 'a ingen:Node ; ingen:prototype ' ingenish connect /left_in /tone/left_in ingenish connect /tone/left_out /combo/left_in ingenish connect /combo/left_out /left_out ingenish set /tone/output 'ingen:value 0.7' ''') def run(cmd): if cmd[0] == 'help': print_usage() elif cmd[0] == 'exit': sys.exit(0) elif cmd[0] == 'put' and len(cmd) == 3: return ingen.put(cmd[1], cmd[2]) elif cmd[0] == 'set' and len(cmd) == 3: return ingen.set(cmd[1], cmd[2]) elif cmd[0] == 'connect' and len(cmd) == 3: return ingen.connect(cmd[1], cmd[2]) elif cmd[0] == 'disconnect' and len(cmd) == 3: return ingen.disconnect(cmd[1], cmd[2]) elif cmd[0] == 'delete' and len(cmd) == 2: return ingen.delete(cmd[1]) else: return False a = 1 server = 'unix:///tmp/ingen.sock' if len(sys.argv) > 1: if sys.argv[a] == '-s': server = sys.argv[a + 1] a = a + 2 elif sys.argv[a][0] == '-': print_usage() sys.exit(1) ingen = Client(server) if len(sys.argv) - a == 0: while True: try: run(shlex.split(raw_input('> '))) except (EOFError, KeyboardInterrupt, SystemExit): print('') break except: print('error: %s' % sys.exc_info()[0]) else: if not run(sys.argv[1:]): print_usage() sys.exit(1)