Skip to main content

Acquisition Plugins in MNE Scan

Acquisition plugins (also called sensor plugins) are the entry point for all data in MNE Scan. They interface with hardware devices or data sources — EEG amplifiers, MEG systems, file readers, or simulated signals — and stream data into the real-time processing pipeline.

Three-Tier Architecture

All acquisition plugins follow a consistent three-tier architecture that separates concerns between the MNE Scan framework, the data acquisition logic, and the hardware driver:

TierClass RoleResponsibilities
Plugin (top)Main plugin class, inherits from AbstractSensorCommunicates with MNE Scan; manages the GUI (setup widget, toolbar buttons); creates and owns the Producer
Producer (middle)Data acquisition controllerManages the acquisition thread; pulls data from the Driver and pushes it into ring buffers; bridges Plugin ↔ Driver
Driver (bottom)Hardware/device interfaceDirectly communicates with the device SDK or API; handles device initialization, parameter configuration, and raw sample retrieval

This separation means that the Plugin and Producer classes are structurally similar across all acquisition plugins — only the Driver class changes significantly depending on the hardware.

┌─────────────────────────────────┐
│ MNE Scan │
│ (plugin pipeline framework) │
└──────────┬──────────────────────┘
│ ← AbstractSensor interface
┌──────────▼──────────────────────┐
│ Plugin Class │
│ (e.g. GUSBamp, BabyMEG, │
│ FiffSimulator, LSLAdapter) │
│ • GUI setup widget │
│ • Start/stop acquisition │
│ • Output connectors │
└──────────┬──────────────────────┘

┌──────────▼──────────────────────┐
│ Producer Class │
│ (e.g. GUSBampProducer) │
│ • Runs acquisition thread │
│ • Ring buffer management │
│ • Calls driver for samples │
└──────────┬──────────────────────┘

┌──────────▼──────────────────────┐
│ Driver Class │
│ (e.g. GUSBampDriver) │
│ • Device SDK calls │
│ • Parameter configuration │
│ • Raw sample retrieval │
└──────────┬──────────────────────┘

┌─────▼─────┐
│ Hardware │
│ Device │
└───────────┘

Example: gUSBamp EEG Driver

The gUSBamp plugin illustrates this pattern:

The left side shows the MNE Scan boundary; the right side shows the hardware device. The three classes mediate between them:

  • gUSBamp — main plugin class; communicates with MNE Scan and manages the GUI.
  • gUSBampproducer — controls the acquisition thread and bridges the plugin with the driver.
  • gUSBampdriver — communicates directly with the gUSBamp amplifier hardware.

Data Flow

All three classes are constructed sequentially during plugin initialization, setting up default parameters. Once initialized, the plugin waits for a start command or parameter changes from the GUI.

Starting Acquisition

Starting acquisition triggers a chain: the Plugin starts the Producer, and the Producer starts the Driver. The Driver initializes the hardware and begins sampling. Both the Plugin and Producer run internal threads that pull data from the class below and push it upward via ring buffers (CircularBuffer), creating a continuous data stream into MNE Scan.

Stopping Acquisition

When stopping the acquisition, both threads are interrupted by setting the m_bIsRunning flag to false, and the Driver class puts the device into standby mode. The ring buffers are flushed and reset.

Key Base Classes

ClassLocationPurpose
AbstractSensorsrc/applications/mne_scan/libs/scShared/Base class for all acquisition plugins
CircularBuffersrc/libraries/utils/Lock-free ring buffer for inter-thread data transfer
PluginOutputDatasrc/applications/mne_scan/libs/scShared/Typed output connector that passes data to downstream plugins

Implementing a New Acquisition Plugin

To create a new acquisition plugin:

  1. Copy an existing plugin folder (e.g., dummytoolbox or fiffsimulator) as a template.
  2. Create three classes: MyPlugin (inherits AbstractSensor), MyPluginProducer, and MyPluginDriver.
  3. Implement the Driver to interface with your device's SDK — initialize the device, configure parameters, and read raw samples.
  4. Implement the Producer to run the acquisition loop in a separate thread, pulling samples from the Driver and pushing them into a CircularBuffer.
  5. Implement the Plugin to set up the GUI, create output connectors, and manage the start/stop lifecycle.
  6. Register the plugin in the parent CMakeLists.txt and, for static builds, in main.cpp via Q_IMPORT_PLUGIN.

See Creating a Plugin for the general plugin scaffolding guide.