Programming Reference:Class Hierarchies
BCI2000 consists of a large number of classes, which interact in complicated ways, and are difficult to oversee. Most of these classes are of little importance to the overall picture of BCI2000. In fact, knowledge of a small number of BCI2000 classes, and their inheritance relationships, is sufficient to understand how BCI2000 works, and how to write your own BCI2000 filters and modules.
This page gives an overview over the class hierarchies which matter to you when doing programming work in BCI2000. It does not describe individual self-contained classes such as the SignalProperties or GenericSignal; rather, it explains classes that are part of hierarchies, each playing a certain role in its hierarchy.
Types of Classes
In BCI2000, class hierarchies consist of three types of classes: Interface class, mix-in classes, and client classes.
Interface classes, which provide an abstract interface for functionality that is then implemented by classes derived from those interface classes. Due to the common interface, the BCI2000 framework can deal with a great number of derived classes, serving their needs without even knowing which derived classes exist and what they do.
Interface classes typically declare a number of so-called virtual functions. In the interface class, these virtual functions do nothing specific; in most cases, they are not even defined, such that a derived class is forced to implement its own version of that function. An interface class' virtual functions provide an interface to their derived classes. In addition to virtual functions, an interface class also has plain member functions; these provide an interface to classes that use objects of the interface class, rather than inheriting from it.
In BCI2000, there are a large number of interface classes that represent programming interfaces for filters, data acquisition interfaces, file writers, application modules, and graphic objects. The most important interface class is the GenericFilter class, which defines the programming interface for all BCI2000 filter components that are part of the filter chain.
Most often, interfaces are built around the notion of an "event". When an event happens, it requires an action. Actions are defined by client classes that implement an interface. Each virtual function in the interface corresponds to an event, and derived classes implement those functions, thus providing event "handlers". As an example, the GraphObject interface class declares a virtual function called OnPaint(). Individual graphic objects inherit from the GraphObject class, and implement the associated interface by providing their own OnPaint() function. Whenever a window needs redrawing, graphic objects are asked to handle the Paint event, i.e. for all graphic objects tied to the respective window, the OnPaint() event handler is called. In its OnPaint() function, a GraphObject descendant class that represents a circle will provide code that draws a circle, while a GraphObject descendant representing a text field will implement an OnPaint() event handler that draws text.
Most often, classes directly inherit from a single interface class only, e.g. when you write a BCI2000 filter component, it inherits from the GenericFilter interface class. However, it is not uncommon that there is a hierarchy of interface classes which all build upon each other, where the line of inheritage represents increasing specialization. As an example, all BCI2000 filters inherit from the GenericFilter interface class. However, data acquisition filters do not inherit from GenericFilter directly; rather, they inherit from a class called GenericADC, which in turn inherits from GenericFilter, i.e. it specializes the GenericFilter interface for data acquisition components. In addition, there exists an interface class called BufferedADC which provides buffering, and an interface for data acquisition components that write their acquired data into a ring buffer. A class that inherits the BufferedADC interface thus implements an interface that has been specialized all the way down from GenericADC and GenericFilter to BufferedADC.
Unlike interface classes, which provide a more-or-less empty framework to be filled in by descendant classes, mix-in classes do actually implement functionality. This functionality is contained in non-virtual functions which may be declared "protected" to make them accessible only to classes that inherit from the mix-in class. An example of such a mix-in class in BCI2000, is the Environment class, which provides access to the Parameters and States that exist in the system. As GenericFilter inherits from Environment, most BCI2000 components inherit from Environment without explicitly asking for it. However, any class that wants to access parameters or states may inherit from the Environment class. Another example of a mix-in class is the ApplicationWindowClient class. To its inheritants, it provides access to application windows, taking care of window creation and deletion, and allowing filters in the application module to share windows for drawing.
Client classes are at the bottom of the inheritance hierarchy. They implement inherited interfaces, and use the functionality provided by mix-in classes, to actually get something done. E.g., the LinearClassifier class implements the GenericFilter interface, using the mix-in functionality of the Environment class, resulting in a BCI2000 component that applies a linear classifier to a stream of data. The StimulusPresentationTask class implements the StimulusTask interface, which in turn is a specialization of the GenericFilter interface, and inherits functionality from the ApplicationBase base class.
GenericFilter is an interface class that serves as a base class for all BCI2000 filter components, i.e. components that process signals in the filter chain. GenericFilter also inherits from the Environment class, and thus provides the ability to access parameters and states to its descendants. Specializations to GenericFilter comprise GenericADC, and BufferedADC.
EnvironmentExtension is an interface class for BCI2000 components that do not process signals, and are not part of the filter chain, but need to be notified of BCI2000 events such as Preflight, Initialize, or StartRun. Typical descendants of EnvironmentExtension are utility classes such as LogFile or RandomGenerator.
This class inherits from GenericFilter, and serves as a base class for application task filters in application modules. To these, it provides a logging facility in form of the AppLog member object, and a random number generator in its RandomNumberGenerator member object. Two specializations of ApplicationBase exist that provide specialized interfaces to certain types of task filters: FeedbackTask, and StimulusTask. These two interface classes define events that are specific to task filters proving feedback, and doing stimulus presentation, respectively. E.g., the FeedbackTask defines an event FeedbackBegin which should be handled by displaying, say, a feedback cursor on a feedback screen, while the StimulusTask defines an event StimulusBegin, which is triggered when a stimulus is being displayed.
GraphObject and GraphDisplay
The GraphObject class defines an interface for classes that represent objects displayed on a GraphDisplay. GraphObjects are attached to GraphDisplays, and have a rectangle that defines their position and extent. GraphObject descendants implement handlers of the Paint event. The VisualStimulus class inherits from both GraphObject and Stimulus base classes, providing a stimulus that draws itself on a GraphDisplay when presented.
In stimulus-based application modules, an interface is needed for classes that represent stimuli. The interface defines that stimuli may be presented, or hidden. A Stimulus descendant implements this interface by providing appropriate code to present itself (showing an image on a display, or playing a sound).
Target, SpellerTarget and Speller
For application modules that implement spellers, such as the P3Speller, there is a general Target interface class for objects that can be selected by brain signals, and a specialized interface classes called SpellerTarget. A SpellerTarget is linked to a on object that implements the Speller interface, and its action is to enter text into the Speller from its Select event handler.
Programming Reference:Contents, Programming Tutorial:Implementing a Data Acquisition Module, Programming Tutorial:Implementing a Signal Processing Filter, Programming Tutorial:Implementing an Input Logger