| | 42 | class NodeInputOutput(object): |
|---|
| | 43 | """NodeInputOutput acts as an Input or an Output for a Node. It buffers data that |
|---|
| | 44 | is written to it so that it may later be read (in order). It doesn't care |
|---|
| | 45 | whether it is used as an Input or as an Output and really could be used as |
|---|
| | 46 | either.""" |
|---|
| | 47 | def __init__(self): |
|---|
| | 48 | self.buffer = [] |
|---|
| | 49 | self.nc = NotificationCenter() |
|---|
| | 50 | self.source = None |
|---|
| | 51 | |
|---|
| | 52 | def connect(self, output): |
|---|
| | 53 | self.source = output |
|---|
| | 54 | self.nc.addListener(output, 'DATA_READY', self.processInput) |
|---|
| | 55 | |
|---|
| | 56 | def disconnect(self): |
|---|
| | 57 | self.nc.removeListener(output, 'DATA_READY', self.processInput) |
|---|
| | 58 | self.source = None |
|---|
| | 59 | |
|---|
| | 60 | def processInput(self, node_output, signal): |
|---|
| | 61 | if signal == 'DATA_READY': |
|---|
| | 62 | self.write(node_output.read()) |
|---|
| | 63 | |
|---|
| | 64 | |
|---|
| | 65 | |
|---|
| | 66 | |
|---|
| | 67 | #### Node Output |
|---|
| | 68 | def readyData(self): |
|---|
| | 69 | return len(self.buffer) |
|---|
| | 70 | |
|---|
| | 71 | def read(self, count=1): |
|---|
| | 72 | #print '>>>>>>> read(), self.buffer=%s' % (self.buffer,) |
|---|
| | 73 | |
|---|
| | 74 | if count == 0: |
|---|
| | 75 | count = len(self.buffer) |
|---|
| | 76 | |
|---|
| | 77 | ret = self.buffer[0:count] |
|---|
| | 78 | #print 'ret = %s' % (ret,) |
|---|
| | 79 | del self.buffer[0:count] |
|---|
| | 80 | #print 'ret = %s' % (ret,) |
|---|
| | 81 | return ret |
|---|
| | 82 | |
|---|
| | 83 | def readSample(self): |
|---|
| | 84 | return self.read()[0] |
|---|
| | 85 | |
|---|
| | 86 | |
|---|
| | 87 | #### Node Input |
|---|
| | 88 | def write(self, data): |
|---|
| | 89 | self.buffer += data |
|---|
| | 90 | #print 'posting DATA_READY' |
|---|
| | 91 | self.nc.post(self, 'DATA_READY') |
|---|
| | 92 | |
|---|
| | 93 | def writeSample(self, data): |
|---|
| | 94 | self.write((data,)) |
|---|
| | 95 | |
|---|
| 60 | | pass |
|---|
| 61 | | |
|---|
| 62 | | def addListener(self, listener, signal='all'): |
|---|
| 63 | | self.signalListeners[signal].append(listener) |
|---|
| 64 | | |
|---|
| 65 | | def tripSignal(self, signal): |
|---|
| 66 | | if self.signalListeners.hasKey(signal): |
|---|
| 67 | | listeners = self.signalListeners[signal] |
|---|
| 68 | | for listener in listeners: |
|---|
| 69 | | listener(self, signal) |
|---|
| 70 | | |
|---|
| 71 | | |
|---|
| 72 | | class NotificationCenter(Singleton): |
|---|
| 73 | | def __init__(self): |
|---|
| 74 | | self.listeners = {} |
|---|
| 75 | | |
|---|
| 76 | | def _ensureListenerList(self, source, signal): |
|---|
| 77 | | if not self.listeners.has_key((source, signal)): |
|---|
| 78 | | self.listeners[(source, signal)] = [] |
|---|
| 79 | | |
|---|
| 80 | | def addListener(self, source, signal, callable): |
|---|
| 81 | | self._ensureListenerList(source, signal) |
|---|
| 82 | | self.listeners[(source, signal)].append(callable) |
|---|
| 83 | | |
|---|
| 84 | | def removeListener(self, source, signal, func): |
|---|
| 85 | | key = (source, signal) |
|---|
| 86 | | if self.listeners.has_key(key): |
|---|
| 87 | | f = lambda x: x not func, |
|---|
| 88 | | self.listeners[key] = filter(f, self.listeners[key]) |
|---|
| 89 | | |
|---|
| 90 | | def post(self, source, signal): |
|---|
| 91 | | key = (source, signal) |
|---|
| 92 | | if self.listeners.has_key(key): |
|---|
| 93 | | for f in self.listeners[key]: |
|---|
| 94 | | f(source, signal) |
|---|
| 95 | | |
|---|
| 96 | | |
|---|
| 97 | | class PassthroughNode(Node): |
|---|
| 98 | | class PassthroughOutput(Output): |
|---|
| 99 | | def __init__(self, input=None): |
|---|
| 100 | | if input is not None: |
|---|
| 101 | | self.source = input |
|---|
| 102 | | |
|---|
| 103 | | def read(self): |
|---|
| 104 | | return self.source |
|---|
| 105 | | |
|---|
| 106 | | def __init__(self): |
|---|
| 107 | | Node.__init__(self) |
|---|
| 108 | | i = Input() |
|---|
| 109 | | self.inputs.append(i) |
|---|
| 110 | | self.outputs.append(PassthroughOutput(i)) |
|---|
| | 132 | raise NotImplemented() |
|---|
| | 133 | |
|---|
| | 134 | # def addListener(self, listener, signal): |
|---|
| | 135 | # self.signalListeners[signal].append(listener) |
|---|
| | 136 | # |
|---|
| | 137 | # def tripSignal(self, signal): |
|---|
| | 138 | # if self.signalListeners.hasKey(signal): |
|---|
| | 139 | # listeners = self.signalListeners[signal] |
|---|
| | 140 | # for listener in listeners: |
|---|
| | 141 | # listener(self, signal) |
|---|
| | 142 | |
|---|
| | 182 | |
|---|
| | 183 | class NotificationCenter(Singleton): |
|---|
| | 184 | def __init__(self): |
|---|
| | 185 | self.listeners = {} |
|---|
| | 186 | |
|---|
| | 187 | def _ensureListenerList(self, source, signal): |
|---|
| | 188 | if not self.listeners.has_key((source, signal)): |
|---|
| | 189 | self.listeners[(source, signal)] = [] |
|---|
| | 190 | |
|---|
| | 191 | def addListener(self, source, signal, callable): |
|---|
| | 192 | #print 'adding listener: source=%s, signal=%s, callable=%s' % (source, signal, callable) |
|---|
| | 193 | self._ensureListenerList(source, signal) |
|---|
| | 194 | self.listeners[(source, signal)].append(callable) |
|---|
| | 195 | |
|---|
| | 196 | def removeListener(self, source, signal, func): |
|---|
| | 197 | key = (source, signal) |
|---|
| | 198 | if self.listeners.has_key(key): |
|---|
| | 199 | f = lambda x: x is not func |
|---|
| | 200 | self.listeners[key] = filter(f, self.listeners[key]) |
|---|
| | 201 | |
|---|
| | 202 | def post(self, source, signal): |
|---|
| | 203 | #print 'signal posted: (%s, %s)' % (source, signal) |
|---|
| | 204 | key = (source, signal) |
|---|
| | 205 | if self.listeners.has_key(key): |
|---|
| | 206 | for f in self.listeners[key]: |
|---|
| | 207 | #print '\tnotifying %s' % (f,) |
|---|
| | 208 | f(source, signal) |
|---|
| | 209 | |
|---|
| | 210 | |
|---|
| | 211 | class PassthroughNode(Node): |
|---|
| | 212 | def __init__(self): |
|---|
| | 213 | Node.__init__(self) |
|---|
| | 214 | i = NodeInputOutput() |
|---|
| | 215 | self.inputs.append(i) |
|---|
| | 216 | self.outputs.append(i) |
|---|
| | 217 | |
|---|
| | 218 | class ConsolePrintNode(Node): |
|---|
| | 219 | def __init__(self): |
|---|
| | 220 | Node.__init__(self) |
|---|
| | 221 | self.nc = NotificationCenter() |
|---|
| | 222 | i = Input() |
|---|
| | 223 | self.nc.addListener(i, 'CONNECT', self.handleConnections) |
|---|
| | 224 | self.nc.addListener(i, 'DISCONNECT', self.handleConnections) |
|---|
| | 225 | self.inputs.append(i) |
|---|
| | 226 | |
|---|
| | 227 | def handleConnections(self, node_input, signal): |
|---|
| | 228 | output = node_input.source |
|---|
| | 229 | |
|---|
| | 230 | if signal == 'CONNECT': |
|---|
| | 231 | self.nc.addListener(output, 'DATA_READY', self.handleInput) |
|---|
| | 232 | elif signal == 'DISCONNECT': |
|---|
| | 233 | self.nc.removeListener(output, 'DATA_READY', self.handleInput) |
|---|
| | 234 | |
|---|
| | 235 | def handleInput(self, node_output, signal): |
|---|
| | 236 | #print '>>>> handleInput (node_output=%s, signal=%s)' % (node_output, signal) |
|---|
| | 237 | if signal == 'DATA_READY': |
|---|
| | 238 | data = node_output.read() |
|---|
| | 239 | #print '\t\tdata=%s' % (data,) |
|---|
| | 240 | for datum in data: |
|---|
| | 241 | print "read: %s" % (datum,) |
|---|
| | 242 | |
|---|
| | 243 | class FuncOutput(NodeInputOutput): |
|---|
| | 244 | def getFunc(self): |
|---|
| | 245 | def f(*args, **kwargs): |
|---|
| | 246 | self.writeSample((args, kwargs)) |
|---|
| | 247 | |
|---|
| | 248 | return f |
|---|