def create_stream(self): logging.info('Looking for LSL stream...') available_streams = resolve_streams(5) if len(available_streams) > 0: self.stream_reader = StreamInlet(available_streams[0], max_chunklen=self.chunk_len, recover=False) # Extract stream info id = self.stream_reader.info().session_id() self.fs = int(self.stream_reader.info().nominal_srate()) self.n_channels = int(self.stream_reader.info().channel_count()) logging.info(f'Stream {id} found at {self.fs} Hz ' f'with {self.n_channels} channels') # Fetching channel names ch = self.stream_reader.info().desc().child('channels').first_child() self.ch_names = [] for i in range(self.n_channels): self.ch_names.append(ch.child_value('label')) ch = ch.next_sibling() logging.info(f"Channel names: {self.ch_names}") else: logging.error('No stream found !') raise Exception
def setup_streams(self): # Outlets # Start/stop markers stream_name = self.outlet_names[0] info = StreamInfo(stream_name, 'Markers', 1, 0, 'string', 'UiOutput1') self.outlets[stream_name] = StreamOutlet(info) # StreamInlets # See also: resolve_byprop, resolve_pypred print('Searching for stream inlets...') while len(self.inlets) < len(self.inlet_names): # Iterate over LSL streams and connect them to an outlet streams = resolve_streams(wait_time=1.0) for stream in streams: if stream.name() in self.inlet_names and stream.name( ) not in self.inlets.keys(): self.inlets[stream.name()] = StreamInlet(stream) # Check which streams are missing and let user know missing_streams = [ n for n in self.inlet_names if n not in self.inlets.keys() ] if any(missing_streams): print('Waiting for stream(s): {}'.format(missing_streams)) print('''\nUI connected to streams:\n\tInlets: {}\n\tOutlets: {}'''. format(list(self.inlets.keys()), list(self.outlets.keys())))
def get_live_streams(): live_streams = pylsl.resolve_streams() return { 'command': 'live_streams', 'data': {'streams': [*map(RelayMode.gen_stream_info_dict, live_streams)]}, 'error': None }
def connect_streams(self): ''' Creates streamOutlets for sending commands to the UI. Then looks for streamInlets corresponding to the names given in the config file. Check infinitely until all streams are connected and prints out the names of the stream that are still not connected. LSL DOCS/CODE: https://github.com/chkothe/pylsl/blob/master/pylsl/pylsl.py # For selecting streamInlets, see also: resolve_byprop, resolve_pypred ''' stream_name = self.outlet_names[0] info = StreamInfo(stream_name, 'Commands', 1, 0, 'int8', 'com1') self.outlets[stream_name] = StreamOutlet(info) # StreamInlets print('Searching for stream inlets...') while len(self.inlets) < len(self.inlet_names): # Iterate over LSL streams and connect them to an outlet streams = resolve_streams(wait_time=1.0) for stream in streams: if stream.name() in self.inlet_names and stream.name( ) not in self.inlets.keys(): self.inlets[stream.name()] = StreamInlet(stream) # Check which streams are missing and let user know missing_streams = [ n for n in self.inlet_names if n not in self.inlets.keys() ] if any(missing_streams): print('Waiting for stream(s): {}'.format(missing_streams)) print( '''\nDecoder connected to streams:\n\tInlets: {}\n\tOutlets: {}'''. format(list(self.inlets.keys()), list(self.outlets.keys())))
def main(): # firstly resolve all streams that could be shown inlets: List[Inlet] = [] print("looking for streams") streams = pylsl.resolve_streams() # Create the pyqtgraph window pw = pg.plot(title='LSL Plot') plt = pw.getPlotItem() plt.enableAutoRange(x=False, y=True) # iterate over found streams, creating specialized inlet objects that will # handle plotting the data for info in streams: if info.type() == 'Markers': if info.nominal_srate() != pylsl.IRREGULAR_RATE \ or info.channel_format() != pylsl.cf_string: print('Invalid marker stream ' + info.name()) print('Adding marker inlet: ' + info.name()) inlets.append(MarkerInlet(info)) elif info.nominal_srate() != pylsl.IRREGULAR_RATE \ and info.channel_format() != pylsl.cf_string: print('Adding data inlet: ' + info.name()) inlets.append(DataInlet(info, plt)) else: print('Don\'t know what to do with stream ' + info.name()) def scroll(): """Move the view so the data appears to scroll""" # We show data only up to a timepoint shortly before the current time # so new data doesn't suddenly appear in the middle of the plot fudge_factor = pull_interval * .002 plot_time = pylsl.local_clock() pw.setXRange(plot_time - plot_duration + fudge_factor, plot_time - fudge_factor) def update(): # Read data from the inlet. Use a timeout of 0.0 so we don't block GUI interaction. mintime = pylsl.local_clock() - plot_duration # call pull_and_plot for each inlet. # Special handling of inlet types (markers, continuous data) is done in # the different inlet classes. for inlet in inlets: inlet.pull_and_plot(mintime, plt) # create a timer that will move the view every update_interval ms update_timer = QtCore.QTimer() update_timer.timeout.connect(scroll) update_timer.start(update_interval) # create a timer that will pull and add new data occasionally pull_timer = QtCore.QTimer() pull_timer.timeout.connect(update) pull_timer.start(pull_interval) import sys # Start Qt event loop unless running in interactive mode or using pyside. if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): QtGui.QApplication.instance().exec_()
def getAvailableStreams(self): self.isAvailable = False # Resets availability of streams -> Always false unless stream is found self.lslobj.clear( ) # Clears container of lsl inlets for new batch of inlets streams = pylsl.resolve_streams( wait_time=1.0 ) # Contains information about all available lsl inlets # If streams list is empty, no streams are available # Clear the channelLayout of all previously listed channels, since no streams are available if len(streams) == 0: print("No streams available.") self.clearChannels() else: self.isAvailable = True print("Got all available streams. Starting streams now.....") for s in streams: lsl_inlet = pylsl.StreamInlet(s, max_buflen=4) lsl_inlet.open_stream() lsl = LSLRINGBUFFER(lsl_type=lsl_inlet.info().type(), name=lsl_inlet.info().name(), inlet=lsl_inlet,\ fs=lsl_inlet.info().nominal_srate(), buffer_duration=4.0, \ num_channels=lsl_inlet.info().channel_count(), uid=lsl_inlet.info().uid(),\ hostname=lsl_inlet.info().hostname(), channel_format='float64') self.lslobj[lsl_inlet.info().name()] = lsl
def update_streams(self): if not self.streams: self.streams = pylsl.resolve_streams(wait_time=1.0) for k, stream in enumerate(self.streams): n = stream.name() stream_params = copy.deepcopy(self.def_stream_parms) stream_params['metadata'].update({ "name": n, "ch_count": stream.channel_count(), "ch_format": stream.channel_format(), "srate": stream.nominal_srate() }) # ch = stream.desc().child("channels").child("channel") # for ch_ix in range(stream.channel_count()): # print(" " + ch.child_value("label")) # ch = ch.next_sibling() stream_params['inlet'] = pylsl.StreamInlet(stream) stream_params['is_marker'] = stream.channel_format() in ["String", pylsl.cf_string]\ and stream.nominal_srate() == pylsl.IRREGULAR_RATE if not stream_params['is_marker']: if self.sig_strm_idx < 0: self.sig_strm_idx = k srate = stream.nominal_srate() stream_params['downSampling'] = srate > 1000 stream_params['chunkSize'] = round(srate / self.chunksPerScreen * self.seconds_per_screen) if stream_params['downSampling']: stream_params['downSamplingFactor'] = round(srate / 1000) n_buff = round(stream_params['chunkSize'] / stream_params['downSamplingFactor']) stream_params['downSamplingBuffer'] = [[0] * int(stream.channel_count())] * n_buff self.stream_params.append(stream_params) self.updateStreamNames.emit([_['metadata'] for _ in self.stream_params], self.sig_strm_idx) self.start()
def print_available_streams(): """prints all available streams in their xml form Example:: import liesl liesl.print_available_streams() """ available_streams = pylsl.resolve_streams() for a in available_streams: print(a.as_xml())
def net_streams(): net_streams = resolve_streams(wait_time=1.0) if len(net_streams) > 1: for i in range(len(net_streams)): print('Net Stream: ', i + 1, net_streams[i]) return 'Many Streams.' elif len(net_streams) == 1: print('Single Network Stream: ', net_streams) return 'Single Stream.' elif len(net_streams) is None: print('No streams on network..')
def search_lsl(ignore_markers=False): import time # look for LSL servers amp_list = [] amp_list_backup = [] while True: streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, si in enumerate(streamInfos): # LSL XML parser has a bug which crashes so do not use for now #desc = pylsl.StreamInlet(si).info().desc() #amp_serial = desc.child('acquisition').child_value('serial_number').strip() amp_serial = 'N/A' # serial number not supported yet amp_name = si.name() if 'Markers' in amp_name: amp_list_backup.append((index, amp_name, amp_serial)) else: amp_list.append((index, amp_name, amp_serial)) break print('No server available yet on the network...') time.sleep(1) if ignore_markers is False: amp_list += amp_list_backup qc.print_c('-- List of servers --', 'W') for i, (index, amp_name, amp_serial) in enumerate(amp_list): if amp_serial == '': amp_ser = 'N/A' else: amp_ser = amp_serial qc.print_c('%d: %s (Serial %s)' % (i, amp_name, amp_ser), 'W') if len(amp_list) == 1: index = 0 else: index = input( 'Amp index? Hit enter without index to select the first server.\n>> ' ) if index.strip() == '': index = 0 else: index = int(index.strip()) amp_index, amp_name, amp_serial = amp_list[index] si = streamInfos[amp_index] assert amp_name == si.name() # LSL XML parser has a bug which crashes so do not use for now #assert amp_serial == pylsl.StreamInlet(si).info().desc().child('acquisition').child_value('serial_number').strip() print('Selected %s (Serial: %s)' % (amp_name, amp_serial)) return amp_name, amp_serial
def search_lsl(ignore_markers=False): import pylsl, time # look for LSL servers amp_list = [] amp_list_backup = [] while True: streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, si in enumerate(streamInfos): amp_serial = pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() amp_name = si.name() if 'Markers' in amp_name: amp_list_backup.append((index, amp_name, amp_serial)) else: amp_list.append((index, amp_name, amp_serial)) break print('No server available yet on the network...') time.sleep(1) if ignore_markers is False: amp_list += amp_list_backup qc.print_c('-- List of servers --', 'W') for i, (index, amp_name, amp_serial) in enumerate(amp_list): if amp_serial == '': amp_ser = 'N/A' else: amp_ser = amp_serial qc.print_c('%d: %s (Serial %s)' % (i, amp_name, amp_ser), 'W') if len(amp_list) == 1: index = 0 dong = 0 else: dong = 1 index = raw_input( 'Amp index? Hit enter without index to select the first server.\n>> ' ).strip() index = int(index) # dong #amp_index, amp_name, amp_serial= [(0, u'g.USBamp-1',u'UB-2010.06.31')] #qc.shell() amp_index, amp_name, amp_serial = amp_list[index] #if dong == 1: #amp_index = 0 #print('!!!!!!!!!!!!!!!') si = streamInfos[amp_index] assert amp_name == si.name() assert amp_serial == pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() print('Selected %s (Serial: %s)' % (amp_name, amp_serial)) return amp_name, amp_serial
def prepare_data(time): a = resolve_streams() inlet = StreamInlet(a[0]) print(a[0].name()) data = [] while len(data) <= time: # get a new sample (you can also omit the timestamp part if you're not # interested in it) sample, timestamp = inlet.pull_sample() data.append(sample) print("prepare_data was run") return data
def connect(self): '''Connecte le stream listener au stream vérifaint streamType et streamName. Renvoie si un stream à été trouvé. Peut lever une NameError Conçu en reprenant le code du groupe de PSC précédent''' streams = resolve_streams() for stream in streams: #cherche parmi les flux arrivant celui qui vient de NIC if (stream.name() == self.streamName and stream.type() == self.streamType): self._inlet = StreamInlet( stream, 3) #garde le stream en mémoire dans "inlet" self.offset = time.time() - self._inlet.pull_sample()[1] return True return False
def fetch_lsl_streams(self): """ This method fetches available LSL streams, and updates variables """ # Set loading labels self.wl_selected_streams.setText(LOADING_MSG) # Fetch data self.available_streams = pylsl.resolve_streams() self.available_stream_labels = list( map(lambda x: (self.gen_stream_label(x), 3), self.available_streams)) # Update labels self.wl_selected_streams.setText(SELECT_STREAM_MSG)
def check_lsl(): streams = resolve_streams(wait_time=0.5) marker_status = False eeg_status = False for i in range(0, len(streams)): stream_name = streams[i].name() if stream_name == config.marker_stream_name: marker_status = True if stream_name == config.eeg_stream_name: eeg_status = True return eeg_status, marker_status
def print_available_streams_fields(fields: List[str]): """prints a specific field from all available streams Example:: import liesl liesl.streams.finder.print_available_streams_fields() """ available_streams = pylsl.resolve_streams() count = 0 for a in available_streams: print("Stream #{0:3.0f}".format(count)) count += 1 for field in fields: value = a.__getattribute__(field)() print("{0} = {1}".format(field, value))
def is_available(): """Check if an lsl stream is available on the network. Returns ------- ok : Boolean True if there is a lsl stream, False otherwise """ # Return True only if at least one lsl stream can be found on # the network if pylsl.resolve_streams(): return True return False
def __init__(self, pipeline, **kwargs): kwargs['title'] = 'LSL stream' super().__init__(pipeline, **kwargs) stream_names = [info.name() for info in pylsl.resolve_streams()] values = [self.STREAM_NAME_PLACEHOLDER] + stream_names try: value = self.source_node.stream_name except AttributeError: value = self.STREAM_NAME_PLACEHOLDER stream_names_combo = parameterTypes.ListParameter( name=self.STREAM_NAMES_COMBO_NAME, values=values, value=value) stream_names_combo.sigValueChanged.connect(self._on_stream_name_picked) self.stream_names_combo = self.addChild(stream_names_combo)
def scan(): """ Scan through all visible streams and check if they can be connected to """ colorama.init() streams = pylsl.resolve_streams() connection_ok = [] for stream in streams: # Check if stream can be connected to inlet = pylsl.StreamInlet(stream) if inlet: connection_ok.append(True) else: connection_ok.append(False) return streams, connection_ok
def list_lsl_streams(ignore_markers=False, logger=logger, state=mp.Value('i', 1)): """ List all the available outlets on LSL network. Parameters ---------- ignore_markers : bool If True, ignore streams with Marker type. logger : logging.Logger The logger to output info. state: mp.Value The multiprocess sharing variable, used to stop search from another process. """ # look for LSL servers stream_list = [] stream_list_markers = [] while state.value == 1: streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, streamInfo in enumerate(streamInfos): stream_name = streamInfo.name() if 'Markers' in streamInfo.type(): stream_list_markers.append((index, stream_name)) else: stream_list.append((index, stream_name)) break logger.info('No server available yet on the network...') time.sleep(1) if ignore_markers is False: stream_list += stream_list_markers logger.info('-- List of servers --') for i, (index, stream_name) in enumerate(stream_list): logger.info(f'{i}: {stream_name}') return stream_list, streamInfos
def list_lsl_streams(window, state=None, logger=logger, ignore_markers=False): """ """ import time # GUI sharing variable to stop the process, 1 = start, 0 = stop if not state: state = mp.Value('i', 1) # look for LSL servers amp_list = [] amp_list_backup = [] while True: # Stop if recording state (mp shared variable) is set to 0 from GUI if not state.value: sys.exit() streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, si in enumerate(streamInfos): # LSL XML parser has a bug which crashes so do not use for now #desc = pylsl.StreamInlet(si).info().desc() #amp_serial = desc.child('acquisition').child_value('serial_number').strip() amp_serial = 'N/A' # serial number not supported yet amp_name = si.name() if 'Markers' in amp_name: amp_list_backup.append((index, amp_name, amp_serial)) else: amp_list.append((index, amp_name, amp_serial)) break logger.info('No server available yet on the network...') time.sleep(1) if ignore_markers is False: amp_list += amp_list_backup logger.info('-- List of servers --') for i, (index, amp_name, amp_serial) in enumerate(amp_list): if amp_serial == '': amp_ser = 'N/A' else: amp_ser = amp_serial logger.info('%d: %s (Serial %s)' % (i, amp_name, amp_ser)) window.selector_window.textEdit_streaminfo.append('%d: %s (Serial %s)' % (i, amp_name, amp_ser)) window.stream_selector_window.show() return amp_list, streamInfos
def test_BaseStream_record_data_indefinitely(): """Test rteeg.base.BaseStream""" # Start a LabStreamingLayer stream of synthetic data. eeg_out = SyntheticData("EEG", 32, 100, send_data=True) inlet = StreamInlet(resolve_streams(wait_time=1.)[0]) base = BaseStream() # Check that length of base.data increases. len_0 = len(base.data) t = threading.Thread(target=base._record_data_indefinitely, args=(inlet,)) t.daemon = True t.start() time.sleep(2.) len_1 = len(base.data) assert len_1 > len_0, "Data not being recorded." # Clean up. base._kill_signal.set() eeg_out.stop()
def get_lsl_streams(): """Discover all LSL streams available on the local network. Returns: dict[str, dict[str, pylsl.StreamInfo]]: Streams mapped to source/type. Keys are source IDs; values are dictionaries for which the keys are stream types and the values are stream. Example: When EEG and accelerometer streams are found for a single Muse headset: >>> get_lsl_streams() {'Muse-00:00:00:00:00:00': {'EEG': <pylsl.pylsl.StreamInfo>, 'accelerometer': <pylsl.pylsl.StreamInfo>}} """ streams = [(stream.source_id(), stream.type(), stream) for stream in lsl.resolve_streams(wait_time=2)] streams_dict = streams_dict_from_streams(streams) return streams_dict
def get_streaminfos_matching(**kwargs) -> List[StreamInfo]: """ args ---- **kwargs: keyword arguments to identify the desired stream returns ------- sinfos: List[StreamInfo] a list of StreamInfo matching the kwargs Example:: import liesl sinfos = liesl.get_streaminfos_matching(name="Liesl-Mock-EEG") """ # find all available streams, check whether they are fitting with kwargs available_streams = pylsl.resolve_streams() if len(available_streams) == 0: return None fitting_streams = [] for st in available_streams: for k, v in kwargs.items(): if eval("st." + k + "()") != v: break else: fitting_streams.append(st) # either throws a timepout, returns a streaminfo or a list of streaminfos if len(fitting_streams) == 0: return None else: return fitting_streams
ft_output.connect(ftc_host, ftc_port) if debug > 0: print("Connected to output FieldTrip buffer") except: raise RuntimeError("cannot connect to output FieldTrip buffer") print("looking for an LSL stream...") start = time.time() selected = [] while len(selected) < 1: if (time.time() - start) > timeout: print("Error: timeout while waiting for LSL stream") raise SystemExit # find the desired stream on the lab network streams = lsl.resolve_streams() for stream in streams: inlet = lsl.StreamInlet(stream) name = inlet.info().name() type = inlet.info().type() source_id = inlet.info().source_id() # determine whether this stream should be further processed match = True if len(lsl_name): match = match and lsl_name == name if len(lsl_type): match = match and lsl_type == type if match: # select this stream for further processing selected.append(stream) print('-------- STREAM(*) ------')
def enumerate(): streams = resolve_streams() for stream in streams: print( f"name: {stream.name()}, type: {stream.type()}, source_id: {stream.source_id()}" )
if(dataPoint > state.highestAmplitude): state.highestAmplitude = dataPoint remappedValue = interp(dataPoint, [state.lowestAmplitude, state.highestAmplitude], [-0.5, 0.5]) lslSampleSet.append( remappedValue )# demo use only one channel sample,ts = inlet.pull_sample(0.0) sampleSet = lslSampleSet if any(sampleSet): data[state.lastSampleOffset:state.currentSampleOffset,1] = sampleSet program['a_position'].set_data(data) c.update() streams = resolve_streams() if not any(streams): print 'No Streams found' exit() inlet = StreamInlet(streams[0]) c.show() timer.start() app.run()
def _start(): '''Start the module This uses the global variables from setup and adds a set of global variables ''' global parser, args, config, r, response, patch, name global monitor, timeout, lsl_name, lsl_type, ft_host, ft_port, ft_output, start, selected, streams, stream, inlet, type, source_id, match, lsl_id, channel_count, channel_format, nominal_srate, samples, blocksize # this can be used to show parameters that have changed monitor = EEGsynth.monitor(name=name, debug=patch.getint('general', 'debug')) # get the options from the configuration file timeout = patch.getfloat('lsl', 'timeout', default=30) lsl_name = patch.getstring('lsl', 'name') lsl_type = patch.getstring('lsl', 'type') try: ft_host = patch.getstring('fieldtrip', 'hostname') ft_port = patch.getint('fieldtrip', 'port') monitor.info('Trying to connect to buffer on %s:%i ...' % (ft_host, ft_port)) ft_output = FieldTrip.Client() ft_output.connect(ft_host, ft_port) monitor.info("Connected to output FieldTrip buffer") except: raise RuntimeError("cannot connect to output FieldTrip buffer") monitor.success("looking for an LSL stream...") start = time.time() selected = [] while len(selected) < 1: if (time.time() - start) > timeout: monitor.error("Error: timeout while waiting for LSL stream") raise SystemExit # find the desired stream on the lab network streams = lsl.resolve_streams() for stream in streams: inlet = lsl.StreamInlet(stream) name = inlet.info().name() type = inlet.info().type() source_id = inlet.info().source_id() # determine whether this stream should be further processed match = True if len(lsl_name): match = match and lsl_name == name if len(lsl_type): match = match and lsl_type == type if match: # select this stream for further processing selected.append(stream) monitor.success('-------- STREAM(*) ------') else: monitor.success('-------- STREAM ---------') monitor.info("name", name) monitor.info("type", type) monitor.success('-------------------------') # create a new inlet from the first (and hopefully only) selected stream inlet = lsl.StreamInlet(selected[0]) # give some feedback lsl_name = inlet.info().name() lsl_type = inlet.info().type() lsl_id = inlet.info().source_id() monitor.success('connected to LSL stream %s (type = %s, id = %s)' % (lsl_name, lsl_type, lsl_id)) channel_count = inlet.info().channel_count() channel_format = inlet.info().channel_format() nominal_srate = inlet.info().nominal_srate() ft_output.putHeader(channel_count, nominal_srate, FieldTrip.DATATYPE_FLOAT32) # this is used for feedback samples = 0 blocksize = 1 # there should not be any local variables in this function, they should all be global if len(locals()): print('LOCALS: ' + ', '.join(locals().keys()))
def list_all_streams(wait_time=1.0): # todo: be a little more proactive here infos = resolve_streams(wait_time)
def connect(self, bufsize=1, winsize=1, stream_name=None, eeg_only=False): """ Search for the available streams on the LSL network and connect to the appropriate ones. If a LSL stream fullfills the requirements (name...), a connection is established. This function is called while instanciating a StreamReceiver and can be recall to reconnect to the LSL streams. Parameters ---------- bufsize : int The buffer's size [secs]. 1-day is the maximum size. Large buffer may lead to a delay if not pulled frequently. winsize : int To extract the latest winsize samples from the buffer [secs]. stream_name : list | str Servers' name or list of servers' name to connect to. None: no constraint. eeg_only : bool If true, ignore non-EEG servers. """ self._streams = dict() self._is_connected = False server_found = False while not server_found: if stream_name is None: logger.info("Looking for available lsl streaming servers...") else: logger.info(f"Looking for server(s): '{stream_name}'...") streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for streamInfo in streamInfos: # EEG streaming server only? if eeg_only and streamInfo.type().lower() != 'eeg': logger.info(f'Stream {streamInfo.name()} skipped.') continue # connect to a specific amp only? if isinstance(stream_name, str) and \ streamInfo.name() != stream_name: if stream_name in streamInfo.name(): logger.info(f'Stream {stream_name} skipped, ' f'however {streamInfo.name()} exists.') continue if isinstance(stream_name, (list, tuple)) and \ streamInfo.name() not in stream_name: logger.info(f'Stream {streamInfo.name()} skipped.') continue # do not connect to StreamRecorderInfo if streamInfo.name() == 'StreamRecorderInfo': continue # EEG stream if streamInfo.type().lower() == "eeg": self._streams[streamInfo.name()] = StreamEEG( streamInfo, bufsize, winsize) # Marker stream elif streamInfo.nominal_srate() == 0: self._streams[streamInfo.name()] = StreamMarker( streamInfo, bufsize, winsize) server_found = True time.sleep(1) for stream in self._streams: if stream not in self._acquisition_threads.keys(): self._acquisition_threads[stream] = None self.show_info() self._is_connected = True logger.info('Ready to receive data from the connected streams.')
def fetch(plot_duration=10, update_interval=30, pull_interval=250, fn=fn): """ Receive, preprocess and plot LSL recording Args: plot_duration: int how many seconds of data to show update_interval: int ms between screen updates pull_interval: int ms of each pull operation fn: function preprocessing function """ # Create the pyqtgraph window pw = pg.plot(title='LSL Plot') plt = pw.getPlotItem() plt.setAxisItems = {'bottom': TimeAxisItem(orientation='bottom')} plt.enableAutoRange(x=False, y=True) # firstly resolve all streams that could be shown streams = pylsl.resolve_streams() inlets = read_streams(streams, plot_duration, plt) # iterate over found streams, creating specialized inlet objects that will # handle plotting the data def scroll(): """Move the view so the data appears to scroll""" # We show data only up to a timepoint shortly before the current time # so new data doesn't suddenly appear in the middle of the plot fudge_factor = pull_interval * .002 plot_time = pylsl.local_clock() pw.setXRange(plot_time - plot_duration + fudge_factor, plot_time - fudge_factor) def update(): # Read data from the inlet. # Use a timeout of 0.0 so we don't block GUI interaction. mintime = pylsl.local_clock() - plot_duration # call pull_and_plot for each inlet. # Special handling of inlet types (markers, continuous data) is done in # the different inlet classes. if inlets: for inlet in inlets: if isinstance(inlet, DataInlet): try: ts, window = inlet.pull_and_plot(mintime, plt) detected = fn(ts, window) if detected: for t in detected: plt.addItem( pg.InfiniteLine( t, angle=90, movable=False, pen=pg.mkPen(color=(255, 119, 0), style=QtCore.Qt.DotLine))) except TypeError: continue elif isinstance(inlet, MarkerInlet): inlet.pull_and_plot(mintime, plt) # create a timer that will move the view every update_interval ms update_timer = QtCore.QTimer() update_timer.timeout.connect(scroll) update_timer.start(update_interval) # create a timer that will pull and add new data occasionally pull_timer = QtCore.QTimer() pull_timer.timeout.connect(update) pull_timer.start(pull_interval) # Start Qt event loop unless running in interactive mode or using pyside. if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): app = QtGui.QApplication.instance() sys.exit(app.exec_())