First thing's first. We've moved over to the 4.0 version of the .NET framework. That is all.
"Modules" = Plugins + add-ins. Those two terms have been brought together under the more generic term "module" to avoid continuing to throw around two terms where one is sufficient. And, to remove any ambiguity between 2.x and 3.0, "plugins" was abandoned.
Second thing's second. We'll start out with a short explanation of the different module types that can be implemented before getting into how they're implemented.
Output modules = output plugins. A controller uses one output module to interact with the controller it represents. Controllers are updated at a regular frequency and with an update, each output module receives a state as a collection of data. Data is slightly more elaborate than byte values this time around, so the controller can choose to ignore data based on its properties.
There are two basic types of sequences -- your standard container for channel data and script sequences. A sequence module is an implementation of one of these two types. It gives identity to a specific implementation for editors to use. While one of the two types of sequences gives basic functionality to store data for execution, a sequence module implementation can extend them to add additional functionality or data (surfaced through an editor).
An editor module is a UI implementation to edit a type of sequence. The file type identity provided by a sequence module is what an editor module keys off of. A single editor can state multiple types of sequences it will edit.
An effect is the high-level data that the user interacts with. Effects generate lower-level data that is then executed. Effects can make use of properties (property modules) to help define their runtime behavior and define parameters that the user configures at design time.
Since an effect can do pretty much anything, there's no way to anticipate what kind of editing needs every effect will have. An effect editor can specify effects it can edit (can be multiple) and/or it can specify parameter signatures. This allows, for example, a single effect editor that edits a floating-point value to service any effect with a single floating-point parameter.
A sequence no longer specifies a single audio file to play during its execution. Instead, it is allowed to specify a list of media files to play. A media module handles the playing of the different media types (by file type). A single module can specify multiple file types. One or none of a sequence's media modules can also serve as the timing source for the sequence.
Users can apply properties to groups and channels to help define and model their display. Effects can make use of these properties to direct their behavior. A property module defines the property, a self-contained attribute, along with the UI to configure it. An example is an RGB property that, when applied to a three-channel group, allows the user to assign a color to each channel. Then an effect can intelligently handle channels by their color to, for another example, transition down a color path over time.
For effects to make use of properties, they must reference the assembly that implements property types. One motivation for doing this is to allow properties to define helper methods for effects to use.
Not terribly unlike 2.x input plugins. The module defines a collection of inputs that are polled. An input raises an event when its value changes and has a parameterized effect associated with it (to be written to a channel, if the consumer so chooses). This module type has been a low priority, but will be further defined and refined with community use.
Script modules implement scripting languages, as was covered in a previous post. A script module provides three things:
1. Code provider - To compile the source code.
2. Skeleton file generator - Generates the partial class that the user starts writing their script within.
3. Framework file generator - Generates the partial class that implements the properties and methods available to the user's script.
I think you can figure this one out. It provides timing for a sequence (assuming the sequence is not using a media source as its timing). With timing being implemented as a module, anything can be a timing source. Time doesn't even have to be the basis of the timing. You could have a timing module that steps through execution in response to external events (such as a user clicking a button).
If a sequence does not specify a timing or media module as its timing source, a default one will be used. The default timing source is the timing module with a specific id, so that, too, is replaceable.
Trigger plugins are back! But, they've been a bit more defined, and a bit less supported. Let me explain.
First, the "less supported" bit. Instead of imposing a scheme of how to handle triggers, that has been left completely to the utilizers of the triggers. The trigger module itself may write data to the system for execution, or maybe an application module responds to trigger events. It doesn't have to result in a sequence being executed. This also means a sequence is not necessary to have a response to a trigger.
Second, the "more defined" bit. We've tried to define a set of trigger conditions to cover most expected use cases. A trigger can be digital, specifying a set-to-reset or reset-to-set trigger condition, or analog, using thresholds and ranges as the trigger condition.
Like input modules, a trigger module defines a collection of triggers that are polled. A trigger raises an event when it goes into the set condition. There is some gray area between inputs and triggers as we try to define them, so their very definition may change over time with community input. Unlike inputs, a trigger doesn't have data associated with it. This has been another low-priority module type, so it may be underdeveloped.
Application modules are what used to be "add-ins". They are modules that get access to the client application, as well as the system's entry points (which any module does). A scheduler is an excellent example of an application module -- it needs to add menu items to provide users a way to interact with it (app modules are like services in that they don't have a defined user interface) and it needs to initiate execution. Any module can initiate execution, but only app modules get access to the client application's visual environment.
That covers most of the module types in brief. There are a few more, but their fate and/or definition is in jeopardy.
Basic Anatomy of a Module
A module is made up of two or three parts -- a descriptor, a module instance, and a data object. The first two are required, the third is optional. A specific module type will contain the following at a minimum and may contain more that pertains to modules of that type.
A descriptor is just that. It provides information such as the module's id, author, version, text description, and types of the module instance and data model.
"Abandon hope, all ye who enter without a unique ID."
Every module has a GUID id. This is its unique identifier. If you've copied someone else's module code and haven't changed the id, neither module will be loaded. You've been warned.
Module data is serialized and deserialized for the module through this data object. The module defines a class as its data object and gets/sets its data through an instance of this class (which is provided for the module upon instantiation). A module is not required to have a data object.
An instance of the module. In most cases. Additionally, some module types will be managed as singletons, so the instance you receive may not be just your own.
Every module type has its own interfaces for the module descriptor and instance and every module type has a base class. This is so that you don't have to implement the same mundane members in every module you write and it allows us to provide some niceties for your use on occasion.
Modules can specify dependencies. This becomes helpful when your effect absolutely requires a property and won't work without it. If the property is not installed, your effect will not be loaded and you won't have to field a bunch of questions asking why your effect is so broken. But if that effect can work with and without said properties, then don't list them as dependencies.
I realize that this was a quick run-through, but I'm already a day behind on this post (and, thanks to work, a bit more behind in coding), so I gotta get this thing posted! Our hope is to follow this up with some specific examples; each week focusing on a specific type of module (starting with output modules).
I want to thank folks for following along and the continuing encouragement. If we miss our goal, it's not going to be for a lack of trying or due to lack of community response. You guys have been great and we really appreciate you all.