How is it organized
A TMLG-plugin is in essence only a library with some special startupcode, allowing TMLG to
recognize it. The interface makes it possible to construct visual plugins or alter the
sound before playback. The interface offers a common messageport for use in a plugins
windows, if any. Two signals is also provided for use in the plugin when quitting
subtasks. These signals are garantied to be there, but are not to be used in asyncronous
communication, that is the plugin won't respond to these signals if not explicitly
"wait"ed for inside one of the functions.
The following is an explanation of how to construct a plugin, and it assumes
that you already know how to code a library. In short these are the steps to go through to
make a plugin (in StormC):
It doesn't seem that hard does it? I, draco, don't think so... Anyway, I have included the
sourcecode for "sampleview.plugin" as an example. It's a bit special, as it creates a new
task for updating the display. It is not very nice structured or anything, as it is
something I've developed along the way just to test the interface, but it should give an
idea as of how to make a plugin.
The startup-code
When TMLG opens the plugin-library, it expects the plugin to "announce" itself. If this
part is missing or fails, an error message displaying "not a plugin" will appear.
When the plugin is loaded by the system, it must search for the public semaphore named
"TMLG_PLUGIN_SEM" and lock it! The semaphore is the head of a datastructure as defined in
"AudioPluginStructs.h".
struct PluginSemaphore {
SignalSemaphore Sem;
/* WRITE during OpenLibrary */
BOOL IsPlugin; /* used to distinguish between library and plugin */
ULONG PluginVer;
ULONG PluginRev;
char *PluginName;
char *PluginCopyRight;
ULONG PluginFlags;
/* READ ONLY! */
ULONG PluginSignal; /* free signal for use from library-side of a plugin (when quitting sub-tasks)*/
ULONG PluginSignal2; /* free signal for use from library-side of a plugin (when quitting sub-tasks)*/
ULONG TMLGVer;
ULONG TMLGRev;
};
Part of this structure must be filled by the plugin upon startup! It is almost self
explanatory, but here's a short description:
Set this one to true. TMLG checks if this one is true after loading the plugin
(library).
Specify the version of the plugin.
The revision number.
Pointer to the name of the plugin.
Plugin copyright message.
These flags tells TMLG what the plugin is for!
#define PLUGIN_HAS_PREFS 1 /* This plugin has a preference window */
#define PLUGIN_HAS_ABOUT 2 /* I've got my own about window */
#define PLUGIN_HAS_WINDOW 4 /* This plugin has a "visual" window */
#define PLUGIN_DISPLAYS 4
#define PLUGIN_TRANSFORMS 8 /* I'm altering the sound */
Or the flags together to get the right attributes. If the plugin doesn't have an about
window, a default window will be used together with the version/name/copyright
information specified in the structure.
The library funtions
First a short scenarion, descriping the use and context of the different functions. At
first, immediately after loading the plugin, TMLG will try to initialize it. This is done
using the function "InitPlugin()". This function returns a pointer to a private
datastructure or NULL. Now TMLG will try to open the plugin visual-window if such one
exists (PLUGIN_HAS_WINDOW or PLUGIN_DISPLAYS), calling "ShowPlugin". Now we're ready to
go! When starting on a new song, TMLG calls the function "InitTransformation" and at the
end the function "EndTransformation" is called. In between TMLG will call the functions
"Transform" and/or "PluginDisplay" with the newly decoded sounddata or "about to be
played" data! When quitting TMLG will call "QuitPlugin"...
APTR InitPlugin(PluginData *data, MsgPort *windowport, CxObj *broker);
Initialize the plugin befor usage. If this one returns NULL, a requester will appear
saying the plugin couldn't be initialized.
Input
Pointer to previously saved data or NULL. See GetPluginData.
Pointer to a shared msgport for the plugins windows. HandleWindowMsg will be called
each time a message arrives at this port.
Pointer to TMLG's commodity broker. You may add hotkeys and the likes to this, just be
shure they have a unique id, and remember to remove it during QuitPlugin.
Output
Returns pointer to plugin private data. This pointer is passed as argument to every
other function. NULL indicates failure to initialize the plugin.
void QuitPlugin(APTR data);
Cleanup before unloading the plugin.
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Nothing.
BOOL ShowPlugin(APTR data, MsgPort *port);
Please reveal the plugins "visual" window.
Input
Pointer to plugin private data, as returned by InitPlugin.
Pointer to shared MsgPort for usage as the windows UserPort. (win->UserPort = port;)
Output
Return TRUE if windows has opened. Otherwise FALSE.
BOOL AboutPlugin(APTR data, MsgPort *port);
Show a plugin specific "about" window if any (PLUGIN_HAS_ABOUT). If this cannot be done,
TMLG uses a default window, displaying the information given at startup.
Input
Pointer to plugin private data, as returned by
InitPlugin.
Pointer to shared MsgPort for usage as the windows UserPort. (win->UserPort = port;)
Output
Return TRUE if windows has opened. Otherwise FALSE.
BOOL PluginPrefs(APTR data, MsgPort *port);
Open the plugins preference window, if any (PLUGIN_HAS_PREFS)
Input
Pointer to plugin private data, as returned by InitPlugin.
Pointer to shared MsgPort for usage as the windows UserPort. (win->UserPort = port;)
Output
Return TRUE if windows has opened. Otherwise FALSE.
void HidePlugin(APTR data);
Please hide the plugins windows.
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Nothing.
BOOL HiddenPlugin(APTR data);
Is the plugin window hidden?
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Return TRUE if the plugin has no open window, otherwise FALSE.
BOOL HandleWindowMsg(APTR data, IntuiMessage **msgptr);
Each time a message arrives at the shared messageport, this function will be called until
either there are no more plugins, or one of the functions has returned TRUE. It is allowed
to reply the message (must be done before closing a window!), just remember to set
the IntuiMessage pointer to NULL in this case (*msgptr = NULL;). Remember this
message might not be for your plugin!
Input
Pointer to plugin private data, as returned by InitPlugin.
Pointer to the IntuiMessage pointer!
Output
Return TRUE if you answered to this window. Otherwise FALSE.
BOOL PluginHandleKey(APTR data, ULONG key);
If TMLG recieves a commodity message it doesn't know, it's id (key) is passed to this
function in every plugin until no more plugins exists, or one has returned TRUE.
Input
Pointer to plugin private data, as returned by InitPlugin.
The commodity message id.
Output
Return TRUE if you answered to this key. Otherwise FALSE.
void InitTransformation(APTR data, char *label, ULONG duration, ULONG samplefreq, ULONG channels, ULONG bitrate, ULONG elapsed);
Prepare plugin to recieve audiodata (Start Of Song).
Input
Pointer to plugin private data, as returned by InitPlugin.
Song label.
Duration of the song in seconds.
Sounddata sample frequency.
Number of channels used for playback.
The used bitrate.
The time in seconds already elapsed before playback.
Output
Nothing.
void Transform(APTR data, WORD *left_buffer, WORD *right_buffer, ULONG samples);
Function called for altering audiodata. This is before the data enters TMLG's internal
ringbuffer.
Input
Pointer to plugin private data, as returned by InitPlugin.
Pointer to audiobuffer for left channel.
Pointer to audiobuffer for right channel. This may be NULL in case of mono playback.
The number of samples in the audiobuffer.
Output
Nothing.
void PluginDisplay(APTR data, WORD *left_buffer, WORD *right_buffer, ULONG samples);
Function called immediately before playback. Used for the "visual" plugins.
Input
Pointer to plugin private data, as returned by InitPlugin.
Pointer to audiobuffer for left channel.
Pointer to audiobuffer for right channel. This may be NULL in case of mono playback.
The number of samples in the audiobuffer.
Output
Nothing.
void EndTransformation(APTR data);
Cleanup after last recieved sounddata (End Of Song).
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Nothing.
struct PluginData *GetPluginData(APTR data);
Return pointer to a well defined structure for saving on disk.
struct PluginData {
ULONG Size; /* size of the structure (the number of bytes to be saved!)
BOOL ShowMain; /* Is the "visual" window open?
UWORD MainX, MainY, MainW, MainH; /* coordinates of the "visual" window */
};
Note: this is the minimum structure, if your plugin doesn't have a window, set ShowMain to
FALSE.
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Return pointer to the data that should be saved.
void LockPluginGUI(APTR data);
Please lock the plugins windows for further input.
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Nothing.
void UnLockPluginGUI(APTR data);
Unlock the plugins windows.
Input
Pointer to plugin private data, as returned by InitPlugin.
Output
Nothing.
void PluginPriority(APTR data, LONG pri);
Please change the priority of any subtasks the plugin may have.
Pointer to plugin private data, as returned by InitPlugin.
The intended new priority.
Output
Nothing.
Any comments or questions can be e-mailed to me, draco at , or you can reach me on irc #AmigaDK...