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!

 To do this I have created a class (InputPlugin) that has a set of virtual functions.

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!
  1. 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...
  2. 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:


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!
};

 The PlayerInfoStruct Flags

The different values that can be OR'ed together is:

 

Copyright Claes Löfqvist