Skip to main content

A package for timing-focused psychophysics using GLFW and OpenGL.

Project description

TachyPy

Docs Status

TachyPy is a psychophysics engine for Python focused on precise visual timing with OpenGL rendering, a GLFW-first display/input backend, and experiment-friendly stimulus helpers.

Photodiode timing validation: after-flip trigger aligned to ERG1 response

The name TachyPy comes from the tachistoscope: a classic laboratory instrument for presenting visual stimuli for precisely controlled, brief durations. TachyPy aims to bring that timing discipline into Python experiments while keeping the stimulus code readable and inspectable.

Historical tachistoscope device

Timing Validation

TachyPy's GLFW path has been tested with a photodiode setup using a centrally presented white square on a uniform gray background. The photodiode was placed at the screen center, over the white square, and the EEG recording captured both serial trigger events and the photodiode signal on ERG1.

In the after-flip trigger condition shown above, the white square was presented for one 60 Hz frame. Across 120 flashes, the photodiode pulse width was close to one refresh interval and the trigger-to-photodiode alignment was stable:

  • median ERG1 rise after flash trigger: 6.35 ms
  • SD of ERG1 rise after flash trigger: 0.20 ms
  • median photodiode pulse width: 16.60 ms
  • SD of photodiode pulse width: 0.18 ms

These measurements are hardware/display dependent, but they provide a concrete validation pattern for TachyPy timing tests: combine serial trigger logging, photodiode measurements, and TachyPy flip timestamps rather than relying on software timestamps alone.

Highlights

  • OpenGL stimulus rendering (Texture, Shapes, fixation, etc.).
  • GLFW-first window/input handling via Screen for tighter display control.
  • Backend-aware input handling through ResponseHandler.
  • Multiple text paths:
    • Text (Pillow-first convenience text; legacy pygame fallback if installed),
    • GLText (OpenGL bitmap glyphs),
    • GLTextSDF (distance-field text),
    • GLSystemText (system fonts via FreeType + HarfBuzz).
  • Psychophysics helpers (make_gabor, gratings, normalization, dithering).
  • Audio playback utility (Audio) with backend abstraction (sounddevice or dummy).
  • Test suite for core logic and regressions.

Installation

Install base package:

pip install tachypy

The base install includes GLFW for display/input, PyOpenGL, Pillow text support, and pyserial for serial/trigger workflows. Pygame is no longer a base dependency.

Editable install for development:

git clone https://github.com/Charestlab/tachypy.git
cd tachypy
pip install -e .

Optional extras:

pip install -e ".[test]"        # pytest
pip install -e ".[pygame]"      # legacy pygame compatibility backend
pip install -e ".[text]"        # Pillow text fallback
pip install -e ".[system_text]" # FreeType + HarfBuzz system-font text
pip install -e ".[audio_sd]"    # sounddevice backend

sounddevice / PortAudio prerequisites

sounddevice requires PortAudio on some systems.

Linux (Debian/Ubuntu):

sudo apt update
sudo apt install libportaudio2 libportaudiocpp0 portaudio19-dev

macOS:

Install Homebrew (if needed):

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Then install PortAudio:

brew install portaudio

Windows:

sounddevice wheels often already include what is needed. If installation still fails, one workaround is:

choco install portaudio

Quick Start

import os
from tachypy import Screen, ResponseHandler

backend = os.getenv("TACHYPY_BACKEND", "glfw")
screen = Screen(
    screen_number=0,
    fullscreen=False,
    width=1280,
    height=720,
    backend=backend,
)
responses = ResponseHandler(screen=screen)

running = True
while running:
    screen.fill((128, 128, 128))
    screen.flip()

    responses.get_events()
    if responses.should_quit() or responses.was_key_pressed("esc"):
        running = False
    if responses.was_key_pressed("space"):
        print("Space pressed")

screen.close()

To run the full demo:

python example_tachypy.py

The demo defaults to GLFW. Legacy pygame compatibility remains available if installed:

TACHYPY_BACKEND=pygame python example_tachypy.py

Choose a font for demo text rendering with GLFW GLSystemText:

TACHYPY_BACKEND=glfw TACHYPY_FONT="Avenir Next, Helvetica, Arial" python example_tachypy.py

Backend Notes

  • Screen(backend="glfw"): GLFW-managed window/events, with top-left logical coordinate handling aligned to TachyPy conventions.
  • Screen(backend="pygame"): legacy SDL/Pygame-managed compatibility backend. Install with tachypy[pygame].
  • For robust key/mouse behavior across backends, initialize ResponseHandler(screen=screen) so it can route event polling correctly.
  • DraggableManager now works on both backends when events are read through ResponseHandler(screen=screen).

Text Rendering Notes

  • Text is convenience-first and works for most instruction screens.
  • GLText/GLTextSDF/GLSystemText render text directly in OpenGL and are backend-independent.
  • GLSystemText supports system font selection by family name, fallback list (e.g. "Avenir Next, Helvetica, Arial"), or direct font file path.
  • For production instruction text, prefer GLSystemText with .[system_text].
  • The legacy pygame text path requires tachypy[pygame].

API Naming

The psychophysics module exposes modern English APIs (for example make_gabor, make_sine_grating, normalize_to_unit_interval). Legacy French names remain as compatibility wrappers and emit DeprecationWarning.

Testing

Run tests:

pip install -e ".[test]"
pytest

Current suite covers audio timing helpers, response/key state handling, backend behavior, psychophysics invariants, text layout/renderer basics, and other regression-prone utility paths.

For CI/headless testing, use:

TACHYPY_AUDIO_BACKEND=dummy pytest

Documentation

Expanded docs live in /docs and include:

  • getting started
  • backend behavior and input routing
  • text rendering options
  • audio backend guidance
  • examples and contribution workflow

Hosted docs (Read the Docs): https://tachypy.readthedocs.io/

If Read the Docs is not auto-updating after pushes, reconnect GitHub in RTD and re-sync project webhooks from the RTD project settings.

Main Modules

  • screen.py: display/context lifecycle and backend abstraction.
  • responses.py: keyboard/mouse event handling and key-state queries.
  • text.py, gltext.py, gltext_sdf.py, glsystemtext.py: text rendering.
  • textures.py, shapes.py, draggable.py, scrollbar.py: visual primitives.
  • psychophysics.py: stimulus generation and normalization utilities.
  • audio.py: sound playback and timing helpers.

Contributing

  1. Fork and clone the repository.
  2. Create a branch for your change.
  3. Add tests for behavioral changes.
  4. Run pytest.
  5. Open a pull request.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tachypy-0.1.11.tar.gz (61.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tachypy-0.1.11-py3-none-any.whl (50.2 kB view details)

Uploaded Python 3

File details

Details for the file tachypy-0.1.11.tar.gz.

File metadata

  • Download URL: tachypy-0.1.11.tar.gz
  • Upload date:
  • Size: 61.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tachypy-0.1.11.tar.gz
Algorithm Hash digest
SHA256 07d77a90a90ac7ea74b3243dea1c522e9f7d8d97200742a83d403d219fa332cb
MD5 f661b37cc1762df8079e922bf1465e34
BLAKE2b-256 bbefa1c417d69e77154f71886997ecfd193306463e094e2b1e29197382da3188

See more details on using hashes here.

File details

Details for the file tachypy-0.1.11-py3-none-any.whl.

File metadata

  • Download URL: tachypy-0.1.11-py3-none-any.whl
  • Upload date:
  • Size: 50.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tachypy-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 c5dc3cb6464f3d878b323384eb459376e947a34388c97e3c7966cdb4291361a8
MD5 ca65de3ab42205c98d709b804dedda8a
BLAKE2b-256 6f71b5401d48c924e8e50c38940d9319d6b5883b7ef8cc2cf72768784f3212da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page