CL-Amp
Input Plugin Document v2
You find the latest version here: http://www4.tripnet.se/~slarti/CL-Amp_InPlug_Doc.htm
What's a plugin?
A CL-Amp plugin is simply a AddOn library in which 1 function is known
by CL-Amp. CL-Amp is loading the Plugin into memory and is then calling
the known function. This function is returning a pointer to a InputPlugin
class object which will be used as an interface between CL-Amp and the
plugin.
Changed in version 2 (CL-Amp 3.0 and later...)
I have added some more hook functions! They will only be needed in some
rare plugins and you don't have to worry about them!! If you have made
a plugin with the old headers, just recompile your project with the new
headers!
I have tried to support 2 different approaches!
-
Ordinary C code (the interface is always C++, but it can call ordinary
C functions)
-
Object oriented C++ code
To do this I have created a class (InputPlugin) that has a set of
virtual functions.
-
In a C++ approach this class is used as a base class, and you make your
own class which is overriding all of these functions. Since all the virtual
functions is NULL functions, ALL functions must be provided!! They dont
have to do anything but they must be provided!
-
In the ordinary C approach a special class is already done which
is using the InputPlugin class as a base class. What it does is simply
calling ordinary C functions with the same name as below EXCEPT all of
them has a capital C in the beginning! { JumpTo() -> CJumpTo() }
(I have no good example ready for the C approach but if you mail
me I can put it together quickly!!)
-
To make it dead simple to port ordinary C code I never use more than ONE
instance of the InputPlugin class. It means that you can use global variables
and such things! (If I need another copy of the InputPlugin class I load
a totally new copy of the whole AddOn again)
BeOS = Threads
There is ONE consideration I have to point out! Some of the functions
are called from a thread called A and the rest from thread B.
Since its important that they dont use memory between each others in a
clumpsy way, I try to mark this as clearly as possible in the list below!
Its not anything to worry about, just keep in mind that when a thread
has read one variable halfways another thread can read the value. Since
some bytes are from the new value and some are from the old value,
the resulting value can be whatever, which will cause dramatic effects
and perhaps also crash the program. Simply avoid sharing variables across
such functions!
I have tried to keep all thread handling inside CL-Amp to make it easier
to make the plugin!
--------------
I'm working on this section! You could ignore
for now!!
How should they work?
They can be divided in to two large groups!
-
Lazy plugins - They let CL-Amp do as much
as possible. This is probably the best way to do it! However, not all plugins
can be done like this...
-
Independent plugins - They do most of the
job by them selfs. They will contain an own player loop. A CD playing plugin
will need to be of this type!
End of section!
------------
The hook functions that should be provided
The functions that should be provided by using InputPlugin as a base
class and overriding the virtual versions are:
Init() - No
thread considerations
Cleanup() - No
thread considerations
void Init ();
void Cleanup ();
Init() is called once when CL-Amp
has loaded the plugin into memory.
Cleanup() is called once when
CL-Amp is going to unload the plugin from memory.
GetUserData() - No
thread considerations - (New in CL-Amp
3.0 and later...)
SetUserData() - No
thread considerations - (New in CL-Amp
3.0 and later...)
void *GetUserData();
void SetUserData(void *UserData);
Normally these functions could be ignored (the InputPlugin class has
dummy functions for them)!
Some very rare and special kind of plugins perhaps need to set up some
kind of global memory which should be reachable by all copies of the plugin!
Remember that CL-Amp don't create a new instance of the InputPlugin class...
Instead it creates a new copy of the whole AddOn library!
CL-Amp always load one copy that it will keep until CL-Amp is closed.
That plugin is called the Master plugin!
To determine (in Init() normally) if it's the Master plugin, you can
call this function (will return true if it's the Master):
bool IsMaster();
When CL-Amp is cross fading it will load a new copy and when it does
that, it will make the following call:
NewPlugin.SetUserData(MasterPlugin.GetUserData());
and then
NewPlugin.Init();
So... you can have a pointer to a instance of a class you created (or
something). GetUserData() and SetUserData() should return and set this
pointer of yours. If, in Init(), you detect that it's the Master plugin,
you allocate memory and set up this pointer of yours. If it's not the Master,
the pointer will already been set to the same as the Master's pointer and
you can start using it!
--- Thread A is calling the following functions
---
About() - Thread
A
Prefs() - Thread
A
Edit() - Thread
A
bool About (bool Question);
bool Prefs (bool Question);
bool Edit (char *FileName, bool Question);
[These functions doesn't have to be provided. A empty function returning
false is enough!]
About() - To show a About window.
Make your own window and display it as you like... Telling a little about
the plugin and its creator!?
Prefs() - If there are preferences
that can be adjusted, it should be done from a window which you can display
here...
Edit() - If there is something
that can be viewed and (perhaps) edited regarding a specific song. Here
is a chance to pop up a window to let the user do so...
Please, dont hang in any of these functions!! Display your window and
return. Let the window take care of itself!
If Question is TRUE the call is only a question to get to know if this
function is supported or not!
ONLY make your window show up if Question is FALSE!
Return value:
-
If Question is TRUE
-
TRUE = This function is supported
-
FALSE = This function is NOT supported
-
If Question is FALSE:
-
TRUE = Success
-
FALSE = Something went wrong
GetMimeType() - Thread
A
bool GetMimeType (BMimeType *m, int Nr);
To let CL-Amp know which MimeType(s) the plugin is providing support
for. A example is provided so its easy to fill in the needed information!
The argument 'm' should be filled in with mime type, possible extensions
and a long description.
The argument 'Nr' is to make it possible to make a plugin that handles
many file types. CL-Amp will call this function first time with a Nr=0.
If the function returns TRUE it will be called again! This time with Nr=Nr+1.
This will be repeated until GetMimeType return FALSE!
A TRUE return value means that there is valid information to be found
in '*m';
IsOur() - Thread
A
bool IsOur (char *FileName);
This is a function that should tell if the named file could be handled
by the plugin. A Wave handling plugin would perhaps check if the file name
is ending with a .wav extension or if the mime type for the file is "audio/wave"!
Should return TRUE if the named file could be handled by the plugin.
GetSongInfo() - Thread
A
bool GetSongInfo (char *FileName, struct PlayerInfoStruct
*Info);
This is perhaps the only function that really needs some considerations!!
Since GetSongInfo() is called from thread A, it needs to be isolated from
the playing thread B. It means that this has to be an own function with
its own data. It is made like this to let the playlist collect SongInfo
while the Player is playing.
The Info variable is zero'ed before GetSongInfo() is called!
AbortPlaying() - Thread
A
void AbortPlaying ();
Some special kind of plugins perhaps needs to know when its supposed
to abort the playing. I use it in my streaming mp3 code! It can hang up
inside GetAudio() when its waiting for bytes from the web server, and when
its prebuffering. To get it to return I set a flag with this function.
But normally when a plugin is reading its data from a file, this should
not be necessary. I think most plugins can leave this function empty!
Pause() - Thread
A
void Pause (bool On);
Some special kind of plugins perhaps needs to know when its supposed
to make a Pause(). Normally its enough that CL-Amp stops calling GetAudio()
to get audio data to make a pause but perhaps there is things running around
in your plugin code that needs to be told to pause.
CL-Amp calls this with On=true when the pause is started, and On=false
when the pause is over!
NewSpeed() - Thread
A
void NewSpeed (long Promille);
Some special kind of plugins perhaps needs to handle the speed adjustment
by themselfs. Normally CL-Amp is doing this and this function could be
left empty!
But some plugins, as a midi plugin that calls MidiKit instead of the
MediaKit that CL-Amp uses, must perhaps handle the speed by themselfs.
By giving the flag INPLUG_HANDLE_SPEED in InitPlaying(), you make CL-Amp
call this function and its also not trying to do something by itself to
try to adjust the speed.
The value Promille will be 1000 when a normal speed is requested. 500
= half speed and 2000 = double speed.
NewVolume() - Thread
A
void NewVolume (long Promille);
Some special kind of plugins perhaps needs to handle the volume adjustment
by themselfs. Normally CL-Amp is doing this and this function could be
left empty!
But some plugins, as a midi plugin that calls MidiKit instead of the
MediaKit that CL-Amp uses, must perhaps handle the volume by themselfs.
By giving the flag INPLUG_HANDLE_VOLUME in InitPlaying(), you make CL-Amp
call this function and its also not trying to do something by itself to
try to adjust the volume.
The value Promille will be 1000 when full volume is requested. 500
= half volume and 0 = silence.
NewPanning() - Thread
A - (New in CL-Amp 3.0 and later...)
void NewPanning (long Promille);
(In CL-Amp 3.0 the Panning is not supported!
I have added this function to be prepared for future upgrades :-)
Some special kind of plugins perhaps needs to handle the panning adjustment
by themselfs. Normally this function could be ignored (the InputPlugin
class has a dummy function for this one)!
The value Promille will be 1000 when right speaker is requested. 500
= equal volume in both speakers and 0 = only left speaker shall sound.
CanCrossFade() - Thread
A - (New in CL-Amp 3.0 and later...)
bool CanCrossFade(char *FileName1, char *FileName2);
(In CL-Amp 3.0 the CanCrossFade is not supported!
However, it will be added soon!)
Some special kind of plugins perhaps needs to tell CL-Amp that some
files can't be cross faded. Normally this function could be ignored (the
InputPlugin class has a dummy function for this one. It always returns
true!)
CL-Amp will call this function to determine if FileName1 can be cross
faded with FileName2.
Returning true means that cross
fading is okay!
--- Thread B is calling the following functions
---
InitPlaying() - Thread
B
bool InitPlaying (char *FileName, struct PlayerInfoStruct
*Info);
Opens the suggested file and prepares the plugin for a playing session.
When CL-Amp doesn't want to play anymore, it calls CleanupPlaying()!
The Info variable is zero'ed before InitPlaying() is called!
GetAudio() - Thread
B
int GetAudio (char **Buff, int Size);
CL-Amp need some Audio data (surprise :). The data shall be of the
format stated in the PlayerInfoStruct. Note that the plugin is owning the
data buffer and only returns a pointer and the length of the data. CL-Amp
will never ask for more than MAX_GETAUDIO_SIZE
bytes of data!
The argument Size is only a maximum length, so its free to return whatever
amount of data that feels natural! A mp3 decoder reads one block and returns
that, as an example! If the format of the data changes while playing it
should be reflected in the PlayerInfoStruct that was given to you when
InitPlaying() was called! Also the progress should be updated in that structure
(CurrTime).
If the return value is 0 (zero) it's considered as End of file and
CL-Amp will stop playing this file. If you want to return the control to
CL-Amp for a moment but dont have any sound data, set *Buff to a buffer
containing 0 (zero) and return the length 1!
JumpTo() - Thread
B
void JumpTo (long NewTime);
CL-Amp wants you to start playing at the Newtime position of the file.
The time is given in milliseconds.
(If you set the flag INPLUG_JUMP_FILEPOS,
it will give you a promille value instead! 0 is the beginning of the file
and 1000 is the end of the file.)
CleanupPlaying() - Thread
B
void CleanupPlaying ();
Called when the Playing session is over. A chance to close the file
and clean up things...
The PlayerInfoStruct
This structure is used to let CL-Amp know about the audio format and
the progress of playing.
struct PlayerInfoStruct {
char Title[MAX_INPLUG_FNAME_LEN];
unsigned long Flags;
long CurrTime, TotTime;
// milliseconds.
long BitRate, Frequency;
bool Stereo;
long BufferVolume; //
Promille
bool BufferOn, PreBuffering;
bool SampleIsOnly8Bits;
// Normally a sample should be 16 bits!
};
-
Title - A better title could be found
than just the filename that CL-Amp normally use. A empty string indicates
that no Title is given.
-
Flags - Is described further below
-
CurrTime - The current position of
the file in milliseconds (If you set the flag INPLUG_CURRTIME_FILEPOS,
you could give a promille value instead! 0 is the beginning of the file
and 1000 is the end of the file)
-
TotTime - The length of the file
in milliseconds
-
BitRate - The current bitrate (Observe:
kilo Bits per second)
-
Frequency - The current frequency
-
Stereo - If the audio is in stereo
or not. Stereo=true is telling that the audio is in stereo.
-
SampleIsOnly8Bits - If this is TRUE
it means that every sound sample will be only 8 bits instead of normal
16 bits.
-
BufferOn - Tells CL-Amp to show the
little bar in the spectrum analyzer area. Used for double buffering plugins
like Http handling ones!
-
BufferVolume - Is used to give information
to the little bar that shows up in the spectrum analyzer area some times...
Its given in promile and 0 means empty buffer and 1000 means full buffer.
-
PreBuffering - If this is true the
bar is drawn RED, otherwise its drawn GREEN. Green should indicate a normal
playing condition and red should mean that the play process is halted for
some reason.
The PlayerInfoStruct Flags
The different values that can be OR'ed together is:
-
INPLUG_NO_TOTTIME
The plugin can't estimate a total time for the current file
-
INPLUG_NO_CURRTIME
The plugin will not provide any information in CurrTime
-
INPLUG_JUMP_OK
The plugin can jump around in the song. (Observe: Jumping can not be
done if INPLUG_NO_CURRTIME is given!!)
-
INPLUG_JUMP_FILEPOS
Makes JumpTo() give the new position in file position promille instead
of milliseconds as it is default
-
INPLUG_CURRTIME_FILEPOS
The plugin will set CurrTime to the current file position promille
instead of milliseconds as it is default
-
INPLUG_HANDLE_SPEED
CL-Amp will call NewSpeed() to ask for a new speed and will not try
to adjust it by itself! (CL-Amp is otherwise taking care of speed adjustment
by itself!)
-
INPLUG_HANDLE_VOLUME
CL-Amp will call NewVolume() to ask for a new speed and will not try
to adjust it by itself! (CL-Amp is otherwise taking care of volume adjustment
by itself!)
-
INPLUG_HANDLE_PANNING
CL-Amp will call NewPanning() to ask for a new panning and will not
try to adjust it by itself! (Not implemented in CL-Amp
3.0)
-
INPLUG_INDEPENDENT
The plugin will remain in GetAudio() while playing this song
CL-Amp will call JumpTo() from thread A instead of thread B
Copyright Claes
Löfqvist