Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Enum classes for the channel value formats and post processing flags #87

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pylsl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
DEDUCED_TIMESTAMP,
FOREVER,
IRREGULAR_RATE,
ChannelValueFormats,
PostProcessingFlags,
ContinuousResolver,
InternalError,
InvalidArgumentError,
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/GetTimeCorrection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import time

from pylsl import StreamInlet, resolve_stream
from pylsl import StreamInlet, resolve_byprop


def main():
# first resolve an EEG stream on the lab network
print("looking for an EEG stream...")
streams = resolve_stream("type", "EEG")
streams = resolve_byprop("type", "EEG")
info = streams[0]

# create a new inlet to read from the stream
Expand Down
6 changes: 3 additions & 3 deletions pylsl/examples/HandleMetadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

import time

from pylsl import StreamInfo, StreamInlet, StreamOutlet, resolve_stream
from pylsl import StreamInfo, StreamInlet, StreamOutlet, ChannelValueFormats, resolve_byprop


def main():
# create a new StreamInfo object which shall describe our stream
info = StreamInfo("MetaTester", "EEG", 8, 100, "float32", "myuid56872")
info = StreamInfo("MetaTester", "EEG", 8, 100, ChannelValueFormats.FLOAT32.value, "myuid56872")

# now attach some meta-data (in accordance with XDF format,
# see also https://github.com/sccn/xdf/wiki/Meta-Data)
Expand All @@ -33,7 +33,7 @@ def main():

# first we resolve a stream whose name is MetaTester (note that there are
# other ways to query a stream, too - for instance by content-type)
results = resolve_stream("name", "MetaTester")
results = resolve_byprop("name", "MetaTester")

# open an inlet so we can read the stream's data (and meta-data)
inlet = StreamInlet(results[0])
Expand Down
43 changes: 17 additions & 26 deletions pylsl/examples/PerformanceTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,8 @@

import numpy as np

from pylsl import (
StreamInfo,
StreamInlet,
StreamOutlet,
local_clock,
proc_clocksync,
proc_dejitter,
proc_monotonize,
resolve_bypred,
resolve_byprop,
)
from pylsl import StreamInfo, StreamOutlet, local_clock, resolve_byprop, PostProcessingFlags, StreamInlet, \
resolve_bypred

try:
from pyfftw.interfaces.numpy_fft import ( # Performs much better than numpy's fftpack
Expand Down Expand Up @@ -102,13 +93,13 @@ def generate(self):

class BetaGeneratorOutlet(object):
def __init__(
self,
Fs=2**14,
FreqBeta=20.0,
AmpBeta=100.0,
AmpNoise=20.0,
NCyclesPerChunk=4,
channels=["RAW1", "SPK1", "RAW2", "SPK2", "RAW3", "SPK3"],
self,
Fs=2 ** 14,
FreqBeta=20.0,
AmpBeta=100.0,
AmpNoise=20.0,
NCyclesPerChunk=4,
channels=["RAW1", "SPK1", "RAW2", "SPK2", "RAW3", "SPK3"],
):
"""
:param Fs: Sampling rate
Expand Down Expand Up @@ -189,7 +180,7 @@ def __init__(self):
streams = resolve_byprop("type", "EEG")

# create a new inlet to read from the stream
proc_flags = proc_clocksync | proc_dejitter | proc_monotonize
proc_flags = PostProcessingFlags.CLOCKSYNC.value | PostProcessingFlags.DEJITTER.value | PostProcessingFlags.MONOTONIZE.value
self.inlet = StreamInlet(streams[0], processing_flags=proc_flags)

# The following is an example of how to read stream info
Expand Down Expand Up @@ -227,11 +218,11 @@ class MarkersGeneratorOutlet(object):
}

def __init__(
self,
class_list=[1, 3],
classes_rand=True,
target_list=[1, 2],
targets_rand=True,
self,
class_list=[1, 3],
classes_rand=True,
target_list=[1, 2],
targets_rand=True,
):
"""

Expand Down Expand Up @@ -289,15 +280,15 @@ def update(self):
else self.target_list[
(self.target_list.index(self.target_id) + 1)
% len(self.target_list)
]
]
)
self.class_id = (
random.choice(self.class_list)
if self.classes_rand
else self.class_list[
(self.class_list.index(self.class_id) + 1)
% len(self.class_list)
]
]
)
# print("New class_id: {}, target_id: {}".format(self.class_id, self.target_id))
out_string = "NewTrial {}, Class {}, Target {}".format(
Expand Down
29 changes: 15 additions & 14 deletions pylsl/examples/ReceiveAndPlot.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui

import pylsl
from pylsl import StreamInfo, StreamInlet, PostProcessingFlags, resolve_streams, IRREGULAR_RATE, ChannelValueFormats, \
local_clock

# Basic parameters for the plotting window
plot_duration = 5 # how many seconds of data to show
Expand All @@ -27,7 +28,7 @@
class Inlet:
"""Base class to represent a plottable inlet"""

def __init__(self, info: pylsl.StreamInfo):
def __init__(self, info: StreamInfo):
# create an inlet and connect it to the outlet we found earlier.
# max_buflen is set so data older the plot_duration is discarded
# automatically and we only pull data new enough to show it
Expand All @@ -36,10 +37,10 @@ def __init__(self, info: pylsl.StreamInfo):
# same time domain as the local lsl_clock()
# (see https://labstreaminglayer.readthedocs.io/projects/liblsl/ref/enums.html#_CPPv414proc_clocksync)
# and dejitter timestamps
self.inlet = pylsl.StreamInlet(
self.inlet = StreamInlet(
info,
max_buflen=plot_duration,
processing_flags=pylsl.proc_clocksync | pylsl.proc_dejitter,
processing_flags=PostProcessingFlags.CLOCKSYNC.value | PostProcessingFlags.DEJITTER.value,
)
# store the name and channel count
self.name = info.name()
Expand All @@ -60,7 +61,7 @@ class DataInlet(Inlet):

dtypes = [[], np.float32, np.float64, None, np.int32, np.int16, np.int8, np.int64]

def __init__(self, info: pylsl.StreamInfo, plt: pg.PlotItem):
def __init__(self, info: StreamInfo, plt: pg.PlotItem):
super().__init__(info)
# calculate the size for our buffer, i.e. two times the displayed data
bufsize = (
Expand All @@ -85,7 +86,7 @@ def pull_and_plot(self, plot_time, plt):
# ts will be empty if no samples were pulled, a list of timestamps otherwise
if ts:
ts = np.asarray(ts)
y = self.buffer[0 : ts.size, :]
y = self.buffer[0: ts.size, :]
this_x = None
old_offset = 0
new_offset = 0
Expand Down Expand Up @@ -113,7 +114,7 @@ def pull_and_plot(self, plot_time, plt):
class MarkerInlet(Inlet):
"""A MarkerInlet shows events that happen sporadically as vertical lines"""

def __init__(self, info: pylsl.StreamInfo):
def __init__(self, info: StreamInfo):
super().__init__(info)

def pull_and_plot(self, plot_time, plt):
Expand All @@ -130,7 +131,7 @@ def main():
# firstly resolve all streams that could be shown
inlets: List[Inlet] = []
print("looking for streams")
streams = pylsl.resolve_streams()
streams = resolve_streams()

# Create the pyqtgraph window
pw = pg.plot(title="LSL Plot")
Expand All @@ -142,15 +143,15 @@ def main():
for info in streams:
if info.type() == "Markers":
if (
info.nominal_srate() != pylsl.IRREGULAR_RATE
or info.channel_format() != pylsl.cf_string
info.nominal_srate() != IRREGULAR_RATE
or info.channel_format() != ChannelValueFormats.STRING.value
):
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
info.nominal_srate() != IRREGULAR_RATE
and info.channel_format() != ChannelValueFormats.STRING.value
):
print("Adding data inlet: " + info.name())
inlets.append(DataInlet(info, plt))
Expand All @@ -162,12 +163,12 @@ def 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 * 0.002
plot_time = pylsl.local_clock()
plot_time = 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
mintime = 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.
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/ReceiveData.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Example program to show how to read a multi-channel time series from LSL."""

from pylsl import StreamInlet, resolve_stream
from pylsl import StreamInlet, resolve_byprop


def main():
# first resolve an EEG stream on the lab network
print("looking for an EEG stream...")
streams = resolve_stream("type", "EEG")
streams = resolve_byprop("type", "EEG")

# create a new inlet to read from the stream
inlet = StreamInlet(streams[0])
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/ReceiveDataInChunks.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Example program to demonstrate how to read a multi-channel time-series
from LSL in a chunk-by-chunk manner (which is more efficient)."""

from pylsl import StreamInlet, resolve_stream
from pylsl import StreamInlet, resolve_byprop


def main():
# first resolve an EEG stream on the lab network
print("looking for an EEG stream...")
streams = resolve_stream("type", "EEG")
streams = resolve_byprop("type", "EEG")

# create a new inlet to read from the stream
inlet = StreamInlet(streams[0])
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/ReceiveStringMarkers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Example program to demonstrate how to read string-valued markers from LSL."""

from pylsl import StreamInlet, resolve_stream
from pylsl import StreamInlet, resolve_byprop


def main():
# first resolve a marker stream on the lab network
print("looking for a marker stream...")
streams = resolve_stream("type", "Markers")
streams = resolve_byprop("type", "Markers")

# create a new inlet to read from the stream
inlet = StreamInlet(streams[0])
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/SendData.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import time
from random import random as rand

from pylsl import StreamInfo, StreamOutlet, local_clock
from pylsl import StreamInfo, StreamOutlet, local_clock, ChannelValueFormats


def main(argv):
Expand Down Expand Up @@ -39,7 +39,7 @@ def main(argv):
# last value would be the serial number of the device or some other more or
# less locally unique identifier for the stream as far as available (you
# could also omit it but interrupted connections wouldn't auto-recover)
info = StreamInfo(name, type, n_channels, srate, "float32", "myuid34234")
info = StreamInfo(name, type, n_channels, srate, ChannelValueFormats.FLOAT32.value, "myuid34234")

# next make an outlet
outlet = StreamOutlet(info)
Expand Down
16 changes: 8 additions & 8 deletions pylsl/examples/SendDataAdvanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time
from random import random as rand

import pylsl
from pylsl import ChannelValueFormats, StreamInfo, StreamOutlet, local_clock


def main(name="LSLExampleAmp", stream_type="EEG", srate=100):
Expand Down Expand Up @@ -35,8 +35,8 @@ def main(name="LSLExampleAmp", stream_type="EEG", srate=100):
# The last value would be the serial number of the device or some other more or
# less locally unique identifier for the stream as far as available (you
# could also omit it but interrupted connections wouldn't auto-recover).
info = pylsl.StreamInfo(
name, stream_type, n_channels, srate, "float32", "myuid2424"
info = StreamInfo(
name, stream_type, n_channels, srate, ChannelValueFormats.FLOAT32.value, "myuid2424"
)

# append some meta-data
Expand All @@ -59,7 +59,7 @@ def main(name="LSLExampleAmp", stream_type="EEG", srate=100):

# next make an outlet; we set the transmission chunk size to 32 samples
# and the outgoing buffer size to 360 seconds (max.)
outlet = pylsl.StreamOutlet(info, 32, 360)
outlet = StreamOutlet(info, 32, 360)

if False:
# It's unnecessary to check the info when the stream was created in the same scope; just use info.
Expand All @@ -68,14 +68,14 @@ def main(name="LSLExampleAmp", stream_type="EEG", srate=100):
assert check_info.name() == name
assert check_info.type() == stream_type
assert check_info.channel_count() == len(channel_names)
assert check_info.channel_format() == pylsl.cf_float32
assert check_info.channel_format() == ChannelValueFormats.FLOAT32.value
assert check_info.nominal_srate() == srate

print("now sending data...")
start_time = pylsl.local_clock()
start_time = local_clock()
sent_samples = 0
while True:
elapsed_time = pylsl.local_clock() - start_time
elapsed_time = local_clock() - start_time
required_samples = int(srate * elapsed_time) - sent_samples
if required_samples > 0:
# make a chunk==array of length required_samples, where each element in the array
Expand All @@ -86,7 +86,7 @@ def main(name="LSLExampleAmp", stream_type="EEG", srate=100):
]
# Get a time stamp in seconds. We pretend that our samples are actually
# 125ms old, e.g., as if coming from some external hardware with known latency.
stamp = pylsl.local_clock() - 0.125
stamp = local_clock() - 0.125
# now send it and wait for a bit
# Note that even though `rand()` returns a 64-bit value, the `push_chunk` method
# will convert it to c_float before passing the data to liblsl.
Expand Down
4 changes: 2 additions & 2 deletions pylsl/examples/SendStringMarkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import random
import time

from pylsl import StreamInfo, StreamOutlet
from pylsl import StreamInfo, StreamOutlet, ChannelValueFormats


def main():
Expand All @@ -15,7 +15,7 @@ def main():
# connections wouldn't auto-recover). The important part is that the
# content-type is set to 'Markers', because then other programs will know how
# to interpret the content
info = StreamInfo("MyMarkerStream", "Markers", 1, 0, "string", "myuidw43536")
info = StreamInfo("MyMarkerStream", "Markers", 1, 0, ChannelValueFormats.STRING.value, "myuidw43536")

# next make an outlet
outlet = StreamOutlet(info)
Expand Down
Loading