-
Notifications
You must be signed in to change notification settings - Fork 8
Release notes
Thomas Euler edited this page Jul 24, 2025
·
71 revisions
- Command line options to convert stimuli into some defined format (e.g.,
.hd5
ornumpy
data file) with a given frame rate - Being able to save the background color explicitly in the
.pickle
file.
- Stimulus containing a wait can raise an uncaught error if no respective hardware is connected (e.g., stimulus
noise_Colored_Wait.py
) - Gamma LUT functionality does not work reliably. It can work with a single screen under Windows, but not for all multiple screen configurations. The respective code has not changed, therefore I am unsure of the cause (changed packages, e.g.
pyglet
,pyqt6
seem not to be responsible).
- Stimuli containing movies (from montages) run too slowly, causing frame drops. Stimuli containing videos are fine. In addition, large image montages (for movies) can cause a renderer error (probably related to 3D texture use).
- When running QDSpy via SSH,
q
does not abort stimulus presentation.
- Error message
QWindowsContext: OleInitialize() failed: "COM error 0x80010106: Der Threadmodus kann nicht nach dem Einstellen geändert werden."
appears when starting QDSpy withpyglet>1.5.5
andPyQt6
. I first thought it has no consequences but then saw that now the file dialog is not working anymore. For now, make sure thatpyglet
v1.5.5 is used under Windows.
- Fixed distort shader in Raspberry Pi/Linux version.
- New preliminary device file for LightCrafter DLP4710EVM-LC (
lightcrafter_4710.py
). It appears as if it is using the same API via I2C like the DLP 230NP, but could not test on real device so far. - Major refactoring of the code; now only the main Python scripts (i.e.
QDSpy_GUI_main.py
,QDSpy_MQTT_main.py
), the API file (QDS
), and the specific setup-related files and folders (e.g.,QDSpy.ini
,Stimuli
) are in the root folder.
- New class of devices (
LightSource
), with the implementation of Lumencor Aura III (qds\devices\saura3.py
) -
Lightcrafter
(if of typelcr4500
) now accepts an external lightsource, which can be controlled via the QDSpy GUI. Currently only using the Aura III LEDs' intensity property (no use of internal calibration yet).
- Raspberry Pi/Linux:
- Some small improvements to the GUI (sort stimulus names alphabetically and show selected stimulus name w/o path)
- Account for differences in
hid
(untested) - Issue with not centred movies when
bool_use3dtextures == 1
fixed
- Better error handling in
renderer_opengl.py
- Some bug fixes:
- Fixed error in
GetVideoParameters
- Adapted to current
moviepy
(>= version 2) - Fixed a few bugs that prevented restarting the same video
- Added missing error message strings
- Fixed error in
- Batch mode: This allows presenting a list of stimuli in one batch.
- Switched to
uv
for installation procedure - Linux compatibility (with a focus on the Raspberry Pi 5) was improved
- Helper functions for
QDSpy_stim_movie.py
added to remove direct calls topyglet
in that module
-
MQTT version:
QDSpy_MQTT_main.py
is a headless version of QDSpy that can be controlled via MQTT messages. Provided is also a simple test client (test_mqtt.py
). - Distortion shader (experimental): This feature applies a "distortion" shader to the final stimulus (w/p changing the stimulus scripts), which can be used to adapt the stimulus presentation geometrically to the shape of the projection surface (e.g., to the inside of a sphere). Currently, this feature can only be activated in
QDSpy_global.py
:The shader program# Distortion shader QDSpy_useDistort = False QDSpy_distort_vertex = "distort_vertex_shader.glsl" QDSpy_distort_fragment = "distort_barrel.frag"
distort_barrel.frag
contains the distortion code (here, a barrel distortion) that needs to be adapted to the projection geometry.
- Some bug fixes:
- Allow using file paths that contain spaces
- Log file path joining fixed in
QDSpy_GUI_main.py
-
QDSpy_checks.py
disabled - caused errors (?) -
QDSpy_core_shader.py
: fix joining paths -
Freeze
moviepy` package to version <2 because of breaking changes - In
QDSpy_core.py
, usesys.executable
instead of"python"
, because this ensures that Python is call within the current virtual environment - More path joining bugs fixed
- Now writes log file continuously, such that it is not lost when QDSpy crashes. If necessary, the previous behaviour can be restored by setting
QDSpy_saveLogInTheEnd
inQDSpy_global.py
toTrue
. -
hid
package for Python 3.13 added
- Experimental and master branches merged
- Path issues under Linux (hopefully) solved by collecting all file path related routines in one place (
QDSpy_file_support.py
) and by switching topathlib
for path handling. - Dependencies between modules further untangled, such as
Log
has been moved into its own module; GUI-related methods have been moved fromQDSpy_GUI_support
toQDSpy_GUI_main.py
; newQDSpy_app.py
module, on which the GUI app and the MQTT app are based - More
pyglet
calls encapsulated inrenderer_opengl.py
- Version that can be controlled via MQTT (work in progress)
- New digital I/O device added: "RaspberryPi". It uses by default pins GPIO26 for trigger-in and GPIO27 for marker-out. These pins cannot be changed as these are the only two free pins when using the DLP Lightcrafter 230NP EVM (dldcr203).
- Use
colorama
for console colors - Messages from the worker thread (the one that presents the stimuli) and the host thread (the GUI or the MQTT client) can now be distinguished; worker thread messages start with a
|
character. -
QDSpy_stim_movie.py
andQDSpy_stim_video.py
are not anymore directly dependent onpyglet
by adding helper functions torenderer_opengl.py
. - Log instance (
Log
) moved into own moduleLibraries\log.helper.py
- Multiprocessing support now in
Libraries\multiprocess_helper.py
- Linux: When using 64-bit Raspbian (bullseye),
q
to exit the program works - Now works with a newer release of
pyglet
version 1 (v1.5.5 instead of v1.4.x). Note that higher versions are still not supported; see also "Open issues" below. - GUI migrated to
PyQt6
, now supporting dark mode. - Progress shown in status bar during stimulus presentation.
- Added the option to play sounds, e.g., at the start and end of a stimulus presentation (see
QDSpy_global.py
, for settings). - More modules reformatted using
ruff
.
- Fixed finding shader files when run from the command line
- Running stimuli from the command line (w/o GUI) fixed
- Additional dependency:
pygame
-
Graphics/sounds.py
w/ folderSounds
now supports audio signals. -
QDSpy_GUI_main.py
,QDSpy_GUI_main.ui
,QDSpy_GUI_support.py
- Migrated to
PyQt6
- Fix for font color in log window for dark mode
- Migrated to
-
QDSpy_global.py
,-
QDSpy_useGUIScalingForHD
introduced to control if QDSpy attempts to rescale the GUI for high screen resolutions. If off forPyQt6
.
-
-
QDSpy_multiprocessing.py
- Small bug fix
-
Graphics/renderer_opengl.py
- Fixed a bug when using
pyglet
v1.5.x (still fixed to v1.5.5, see below)
- Fixed a bug when using
- Spot probe tool works again
-
movie_water.py
stimulus fixed and move error handling improved - Issues with Python v3.12 and
configparser
fixed -
hid.cp312-win_amd64.pyd
added toDevices\
-
QDSpy_GUI_main.py
- Reformatted (using Ruff)
- Small fixes for PEP violations
-
int()
where Qt5 does not accept float
-
QDSpy_global.py
- Fix for breaking change in
configparser
(seeQDSpy_config.py
):QDSpy_rec_setup_id
cannot beNone
-> changed to -1 for no setup defined
- Fix for breaking change in
-
QDSpy_stim.py
- Reformatted (using Ruff)
- Small fixes for PEP violations
- Bug fix related to correct error handling for movie compilation errors
-
QDSpy_config.py
- Reformatted (using Ruff)
- Fix for breaking change in
configparser
; now usingConfigParser
instead ofRawConfigParser
- Small fixes for PEP violations
- Set
rec_setup_id
toNone
if < 0
-
QDSpy_core.py
- Reformatted (using Ruff)
- Catch if
conda
is not installed
-
QDSpy_core_presenter.py
- Reformatted (using Ruff)
- Improved error message for movie errors
-
Graphics/renderer_opengl.py
- Reformatted (using Ruff)
- Fixed a bug that prevented using the probe spot tool
- 2024-04 | Thomas Zenkel, Jonathan Oesterle: With the following config changes the stimulus is written as a
numpy.array
to a file namedRecordingStimuli/stim_name.pickle
:Further changes:[Tweaking] bool_recordstim = 1 int_rec_f_downsample_x = 4 int_rec_f_downsample_t = 1
- Changed
np.int
toint
when initializing numpy.array (see numpy deprecation notes) - Delete folder
Stimuli/New Stimuli
- Update
.gitignore
- Changed
- Small bug related to the newest
numpy
version removed - New installation procedure using
conda
- New command
QDS.AwaitTTL()
added. When the script reaches this command, the execution will wait for a trigger. This currently only supports the Arduino as a digital I/O device. This is experimental, hence there are a few things to consider:- Only tested with a standard Arduino boards (UNO, Mini, Nano)
- I changed the baud rate to 230400 to reduce latencies; this is reflected in the new Arduino code. Note that the previous script used a lower baud rate (115200)
- Trigger-out (marker) is as before via pin 13
- Trigger-in is via pin 2, responding to a rising signal edge (which can be changed in the script, if needed)
- One can connect an LED to pin 12; then the LED lights up when a trigger is detected.
- Started to enable QDSpy running under Linux (work in progress)
- Added a shader example that shows how to deal with display aspect ratio
- Started Wiki
- Module
Devices.lightcrafter
now contains the essential API commands required to setup the pattern mode. For details and example scripts, seedocumentation
. - "LEDs" tab renamed to "LightCrafter(s)", buttons to inquire the status of up to two lightcrafters added (both must be connected via USB). The info is currently printed into the shell that runs QDSpy.
- Two example "stimulus" scripts added:
__toGB_8bit_patternMode.py
switches lightcrafter #0 to pattern mode, whereas__toVideoMode.py
switches lightcrafter #0 back to video mode. For details on scripts, seedocumentation
. Note when running these scripts from the QDSpy GUI, it will complain that it cannot compile the scripts. This is because these scripts do not contain any stimulus instructions; the python code that configures the lightcrafter is just directly executed. Executing these scripts from QDSpy GUI is the same as running them from a shell.
-
pyglet
1.4 is out and there were some changes to the API. Now, QDSpy should be compatible to allpyglet
versions (>= 1.3.x). - Bug fix: Maximal number of screens that can be selected for movie presentation was hard-coded; now it is defined
in
QDSpy_global.py
(thanks Maxime Zimmermann). - Possibility added to mirror the two screens separately in screen overlay mode, using additional
QDSpy.ini
parametersbool_v_flip_screen1
,bool_h_flip_screen1
,bool_v_flip_screen2
, andbool_h_flip_screen2
. When updating QDSpy, please follow the instructions about newQDSpy.ini
parameters below. - Changes by Tom Boissonnet added:
- Now computes hash only when starting the stimulus; GUI becomes more responsive with large pickle files.
- Stage offset, scale and rotation are now logged
- .pickle files in the stimulus folder are now ignored by GitHub (added
Stimuli/*.pickle
to.gitignore
) - Additional shader
- Bug fix: In Python 3.7, terminating QDSpy ->
RuntimeError: dictionary changed size during iteration
; fixed. - Bug fix: Default values for Arduino user-defined buttons fixed.
- Bug fix: Issue with loading gamma LUTs via
windll.gdi32.SetDeviceGammaRamp
fixed. - New digital I/O feature added: In addition to the marker pin, two user output pins can be now be defined in
the
QDSpy.ini
file. These allow to control simple external TTL-compatible hardware from the GUI, which now contains two user buttons to switch the signals at the user pins. A simple example application is controlling a drug puffing system. Note that this feature is not yet implemented for the Arduino as I/O device. Seeinifile
for details on the new parameters. - Changes by Tom Boissonnet:
- Bug fix in probing center feature.
- Parameters added to
QDSpy.ini
file:float_gui_time_out
(in seconds), which deals with potential problems when loading very large stimuli;str_antimarkerrgba
, defining the colour of the "anti" marker, which "blanks" the marker area on the screen when the marker is not displayed. This prevents large stimuli from interacting with the marker display.
-
IMPORTANT: The
QDSpy.ini
file contains new parameters, which need to be added to the existingQDSpy.ini
file, otherwise QDSpy will crash. The easiest way to do so, is to rename the file to, for example,QDSpy.ini_COPY
. Then start QDSpy and let it generate a fresh configuration file. Open both the new file and your copy in parallel and change the parameters in the new file according to your previous settings. See see :doc:inifile
for further details on the new parameters. - Small bug fix in the GUI.
- 2017-08-13: Accelerated program start (i.e. on PCs with many cores) by simplifying communication between stimulation process and GUI, avoiding time-consuming sync manager and by communicating with integers instead of strings.
- 2017-08-11: Bug fix: Probing center feature (Tom Boissonnet)
- Experimental support for an Arduino as low-cost digital I/O device (timing not yet thoroughly tested!).
- New feature contributed by Tom Boissonnet (Asari lab, EMBL Monterotondo):
It is found on the GUI tab "Tools". When pressing "Start probing center", a spot appears on the stimulus screen. The spot can be moved (dragged) with the left mouse button pressed. Changing the spot parameters in the GUI changes the spot immediately. The tool can, for example, be used to roughly explore the receptive field of a retinal ganglion cell. The probing mode can be left by either pressing the right mouse button (saving the position to the log), or by pressing "Abort" in the GUI. -
IMPORTANT: The
QDSpy.ini
file contains (a) new parameter(s), which need to be added to the existingQDSpy.ini
file, otherwise QDSpy will crash. The easiest way to do so, is to rename the file to, for example,QDSpy.ini_COPY
. Then start QDSpy and let it generate a fresh configuration file. Open both the new file and your copy in parallel and change the parameters in the new file according to your previous settings. See see :doc:inifile
for further details on the new parameters.
- Bug fix: Problems with "ghost images" when playing more than one movie or video were fixed. Now movie/video objects that are restarted before the previous run was finished are first automatically stopped and ended. Also, movies/videos were also forwarded for no-duration scenes (e.g. a change in object colour), which led to changes in the movie/video frame rate. This should now be fixed as well.
- Bug fix: The first command in a loop was ignored; this is fixed now.
- Bug fix:
__autofile.py
handling was restructured: When no__autorun.py
file exists in the.\Stimuli
folder, QDSpy warns and runs a default instead. An__autorun.py
does no longer have to be present in.\Stimuli
. -
New feature: Using the "screen overlay mode", stimuli with up to 6 different
wavelengths (hexachromatic) can be shown by extending the presentation area to
two neighbouring display devices (i.e. two lightcrafters with different sets of
LEDs). See
inifile
for details on the new configuration parameters in section[Overlay]
and Screen overlay mode for instructions. This feature was inspired by the paper "A tetrachromatic display for the spatiotemporal control of rod and cone stimulation" by Florian S. Bayer and colleagues (Bayer et al., 2015, J Vis doi:10.1167/15.11.15). -
IMPORTANT: The
QDSpy.ini
file contains a couple of new parameters, including a new section called[Overlay]
. Thus, the new parameters need to be added to the existingQDSpy.ini
file, otherwise QDSpy will crash. The easiest way to do so, is to rename the file to, for example,QDSpy.ini_COPY
. Then start QDSpy and let it generate a fresh configuration file. Open both the new file and your copy in parallel and change the parameters in the new file according to your previous settings. See see :doc:inifile
for further details on the new parameters. -
Known issues:
- The GUI controls for the "screen overlay mode" are already present but not
yet working. A work-around is changing the settings directly in
QDSpy.ini
. - Objects that use shaders are not yet correctly displayed in "screen overlay mode".
-
SetColorLUTEntry()
does not yet handle a LUT with more than 3 colours. - When starting QDSpy the stimulus screen may sometimes go white; as soon as the first stimulus is presented, the screen behaves normal.
- The GUI controls for the "screen overlay mode" are already present but not
yet working. A work-around is changing the settings directly in
- Added
hid.cp36-win_amd64.pyd
to.\Devices
to enablehid
under Python 3.6 (comes with Anaconda version 4.3.x). This means that now QDSpy should be compatible with the newest Anaconda distribution. - Attempted to simplify path management:
__autorun.pickle
is not anymore required in the stimulus folder - LED pre-settings for lightcrafter was extended: now for each LED also
the default current, the maximal current, the index of the lightcrafter
device (0 or 1), and the LED index (which LED position within the
lightcrafter) are defined in
QDSpy.ini
. - Up to two lightcrafters can be handled; the GUI has been changed accordingly.
-
IMPORTANT: Note that the
.pickle
format has changed and therefore all stimuli need to be recompiled. To avoid confusion, delete all.pickle
files in the\QDSpy\Stimulus
folder. -
IMPORTANT: The
QDSpy.ini
file contains a couple of new parameters, including a new section called[Overlay]
(the latter is work in progress and concerns a feature that is not yet fully implemented yet. Please ignore for now). Thus, the new parameters need to be added to the existingQDSpy.ini
file, otherwise QDSpy will crash. The easiest way to do so, is to rename the file to, for example,QDSpy.ini_COPY
. Then start QDSpy and let it generate a fresh configuration file. Open both the new file and your copy in parallel and change the parameters in the new file according to your previous settings. See see :doc:inifile
for further details on the new parameters. - Documentation was updated and extended (including, for example, a detailed
explanation of the parameters in
QDSpy.ini
).
- Installation instructions extended (2016-12-20 and 2017-01-18).
- Dependencies changed from Qt4 to Qt5. The background is that many packages, including Anaconda (from version 4.2.0), are now moving to Qt5 for several reasons. QDSpy is now using Qt5 and is now compatible to the latest version of the Anaconda distribution
- Bux fix: The GUI is now scaled if an HD display is detected - before it was
not usable on small HD screens. The mechanism is fairly simple: if one of the
connected screens has a pixel density larger than 110 dpi (currently defined
in
QDSpy_dpiThresholdForHD
inQDSpy_global.py
) then all GUI elements are scaled by this pixel density devided by 100. The font size of the text in the history is treated differently; dependent on whether an "HD" display was detected one of two pre-defined font sizes are used (seeQDSpy_fontPntSizeHistoryHD
andQDSpy_fontPntSizeHistoryHD
inQDSpy_global.py
). - Bug fix: Stimulus duration now calculated correctly.
- Bug fix:
GetStimulusPath()
now returns also to correct path for stimulus files in a subfolder of the default stimulus folder.
- Bug fix: GUI for adjusting LED currents now remains active after sending a
change to the lighcrafter. "Refresh display info" button now works and LED
status is updated after the automatic execution of
__autorun.pickle
.
-
Videos (AVI containers) now work except for the rotation parameter, which uses
a corner instead of the centre. The commands are
DefObj_Video()
,Start_Video()
andGetVideoParamters()
. Note that the latter now returns a dictionary instead of a list. - Like
GetVideoParamters()
,GetMovieParamters()
now also returns a dictionary. - The GUI has been reorganized:
- A font is used that works on all Window versions (7 and higher).
-
Lightcrafter only: The
LEDs: enable
button allows switching off the LEDs and changes to manual LED control (for details, see section :doc:lightcrafter
). - A new tab called "tools" was added; currently in contains a very simple interface to a USB camera (e.g. for observing the stimulus).
- A "Wait for trigger: ..." button has been added; this is not yet functional.
- Duration of stimulus is shown.
- Minor fixes.
- Now reports GLSL version
- Fixed error when QDSpy GUI does not find a compiled
__autorun
. - Stimulus folder can now be selected using the
Change folder
button. Note that at program start, QDSpy always pre-selects the default stimulus folder defined in theQDSpy.ini
file - Cleaning up some pyglet-related code
- Fixed that
psutil
was required even withbool_incr_process_prior=False
- Added two entries to the
[Display]
section of the configuration file:bool_markershowonscreen
determines if the marker ("trigger") that is send via an I/O card is indicated as a small box in the right-bottom corner of the screen. Entryint_markerrgba
(e.g. = 255,127,127,255) defines the marker color as RGB+alpha values. - Starting the GUI version does not require a command line parameter anymore
- Added a new optional command line parameter
--gui
, which when present directs all messages (except for messages generated when scripts are compiled) to the history window of the GUI. - If the
QDSpy.ini
file is missing, it will be recreated from default values. From now on, theQDSpy.ini
file will not be any longer in this repository to prevent that new versions overwrite setup-specific settings (e.g. hardware use, digital I/O configuration, etc.) - Removed currently unused tab "Setting" in GUI
- Changed code for increasing process priority via
psutil
- Added pre-compiled
hidapi
packages for Python 3.5.x (hid.cp35-win_amd64.pyd
); the version for Python 3.4.x was renamed tohid.cp34-win_amd64.pyd
. - Now QDSpy fully supports Python 3.5.x. The installation instructions were updated accordingly.
- Fixed bug in drawing routines for sectors and arcs
- 'Q' now aborts stimulus presentation for both the command line and GUI version of QDSpy
- Refractoring of the code that interfaces with the graphics API (currently OpenGL via pyglet)
- Fixed a bug in the way the scene is centered and scaled.
- Added a stimulus control window to be displayed on the GUI screen when
stimulus presentation is running fullscreen on a different display. This is beta;
the performance of drawing stimuli on different screens in parallel needs to
be carefully tested on different machines.
Added two entries to the
[Display]
section of the configuration file:bool_use_control_window
activates or deactivates the control window, andfloat_control_window_scale
is a scaling factor that defines the size of the control window. - When upgrading a QDSpy installation, new configuration file parameters are now
automatically added.
Important: for consistency, the names of some entries in the configuration
file needed to be changed:
str_digitalio_port_out
,str_digitalio_port_in
,str_led_filter_peak_wavelengths
,str_led_names
,str_led_qtcolor
, andstr_markerrgba
. This needs to be corrected manually in any pre-existing configuration file in an existing installation. Alternatively, the configuration file can be deleted, triggering QDSpy to generated a new one with default values. - Fixed a bug that caused QDSpy to freeze when changing stage parameters and then playing a stimulus.
- End program cleanly and with a clear error message when digital I/O is enabled
in the configuration file but the Universal Library drivers are not installed.
The default for the configuration file is now
bool_use_digitalio = False
.
- Bug fixes
- Added
DefObj_Video()
,Start_Video()
andGetVideoParamters()
commands. Not yet fully implemented and tested; do not use yet. - Added
GetMovieParameters()
command - Fixed
GetDefaultRefreshRate()
command; now reports requested frame rate. - Added
[Tweaking]
section to configuration file. Here, parameters that tune the behaviour of QDSpy are collected. The first parameter isbool_use3DTextures
; it determines, which of pyglets texture implementations is used to load and manage montage images for movie objects (0=texture grid, 1=3D texture). - Added instructions to the documentation of
DefObj_Movie()
how to convert a movie image montage used for the previous QDS with QDSpy. Key is that - in contrast to QDS - QDSpy considers the bottom-left frame of a montage the first frame of the sequence.
- Bug fixes
- Documentation updated
- Gamma correction of display now possible (see section
:doc:
how_QDSpy_works
) - Now catches errors generated when compiling shader scripts.
- Changed stage parameters (magification, center, rotation, etc.) are now written to the configuration file.
- Writes the log automatically to a file. The log contains machine-readable tags for the data analysis.
- Migrated to Python 3.4.3
- Added GUI
- Bug fixes
- Added rudimentary support for controlling a lightcrafter device
- Added movie commands, currently only copying what the old QDS commands did.
- Added a shader that acknowledges colour and alpha value of its object ("SINE_WAVE_GRATING_MIX").
- Minor bug fixes
- Fixed transparency of objects (works now)
- Basic functionality, proof of concept
- Release notes
- Installation
2.1. ... under Windows
2.2. ... under Linux (experimental) - Features
4.1. Running QDSpy as MQTT client
4.2. Batch mode - Notes
4.1. Aspect ratio of shader patterns
4.2. Using a LightCrafter DLP 230NP