		mxPlay Programmer's Plugin API Reference
		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. Introduction

2. Structures

	2.1 Header
		2.1.1 MXP_PLUGIN_ID
		2.1.2 MXP_PLUGIN_PARAMETER
		2.1.3 MXP_PLUGIN_REGISTER_MOD
		2.1.4 MXP_PLUGIN_PLAYTIME
		2.1.5 MXP_PLUGIN_INIT
		2.1.6 MXP_PLUGIN_SET
		2.1.7 MXP_PLUGIN_UNSET
		2.1.8 MXP_PLUGIN_DEINIT
		2.1.9 MXP_PLUGIN_MUSIC_FWD
		2.1.10 MXP_PLUGIN_MUSIC_RWD
		2.1.11 MXP_PLUGIN_MUSIC_PAUSE
		2.1.12 MXP_PLUGIN_INFO
		2.1.13 MXP_PLUGIN_EXTENSIONS
		2.1.14 MXP_PLUGIN_SETTINGS

	2.2 Info Structure
		2.2.1 mxp_struct_info_plugin_author
		2.2.2 mxp_struct_info_plugin_version
		2.2.3 mxp_struct_info_replay_name
		2.2.4 mxp_struct_info_replay_author
		2.2.5 mxp_struct_info_replay_version
		2.2.6 mxp_struct_info_flags

	2.3 Settings Structure
		2.3.1 mxp_struct_settings_name
		2.3.2 mxp_struct_settings_type
		2.3.3 mxp_struct_settings_routine_set
		2.3.4 mxp_struct_settings_routine_get

	2.4 Extensions Structure
		2.4.1 mxp_struct_extensions_string
		2.4.2 mxp_struct_extensions_name

3. Functions
	3.1 Register()
	3.2 Playtime()
	3.3 Init()
	3.4 Set()
	3.5 Unset()
	3.6 Forward()
	3.7 Rewind()
	3.8 Pause()

4. Remarks
	4.1 Startup Process
	4.2 Communication Issues
	4.3 Stability
	4.4 What You Don't Need To Do

5. Contact

----------------------------------------------------------------------

*******************
* 1. Introduction *
*******************

Writing any plugin-based application is always very tricky. You have 
to provide some universal, in the future expandable, easy to 
understand and, at last but not least, working interface between 
'server' application and 'client' plugin.

My goal was to remove as much work from programmer as possible. I 
think this approach is not only good for programmer but it increases 
overall stability since application has control over more things.

All mentioned constants and structures are defined in the file 
MXP_INC.S.


*****************
* 2. Structures *
*****************

Each plugin should be compiled as normal .PRG binary, for example 
from Devpac.


2.1 Header
==========

Offsets are relative to the begin of text segment. So it's very 
useful to create some label at the begin of your code and to use 
predefined offets.

For example:

ogg_header:
	dc.l	"MXP1"
	ds.l	1
	bra.w	register_module
	:
	:

and then access to the members using:

	lea	ogg_header,a0
	move.l	d0,(a0,MXP_PLUGIN_PARAMETER)

	or:

	move.l	d0,ogg_header+MXP_PLUGIN_PARAMETER


Please note all entries are 4 bytes long.


2.1.1 MXP_PLUGIN_ID
-------------------

Characters 'MXP1', i.e. ASCII identifier.


2.1.2 MXP_PLUGIN_PARAMETER
--------------------------

Storage place for both application and plugin. This is the only place 
where they are allowed to write. For more about this, see chapter 4.2 
'Communication Issues'. The content can be either constant or 
pointer, depending on the passed data, see discussion about 
structures bellow.

I didn't want to use register-based communication since every C 
compiler passes parameters on stack differently and I wanted to do 
portable code.


2.1.3 MXP_PLUGIN_REGISTER_MOD
-----------------------------

Relative jump to Register() function.


2.1.4 MXP_PLUGIN_PLAYTIME
-------------------------

Relative jump to Playtime() function.


2.1.5 MXP_PLUGIN_INIT
---------------------

Relative jump to Init() function.


2.1.6 MXP_PLUGIN_SET
--------------------

Relative jump to Set() function.


2.1.7 MXP_PLUGIN_UNSET
----------------------

Relative jump to Unset() function.


2.1.8 MXP_PLUGIN_DEINIT
-----------------------

Relative jump to Deinit() function.


2.1.9 MXP_PLUGIN_MUSIC_FWD
---------------------------

Relative jump to Forward() function.


2.1.10 MXP_PLUGIN_MUSIC_RWD
---------------------------

Relative jump to Rewind() function.


2.1.11 MXP_PLUGIN_MUSIC_PAUSE
-----------------------------

Relative jump to Pause() function.


2.1.12 MXP_PLUGIN_INFO
----------------------

Pointer to the 'Info' structure.


2.1.13 MXP_PLUGIN_EXTENSIONS
----------------------------

Pointer to the list of 'Extensions' structures.


2.1.14 MXP_PLUGIN_SETTINGS
--------------------------

Pointer to the list of 'Settings' structures.


2.2 Info Structure
==================

Defined as 'mxp_struct_info'. Each entry is 4 bytes long. The 
number of structures is limited to one. Best approach is to use it 
for example as:

	lea	ogg_header,a0
	movea.l	(a0,MXP_PLUGIN_INFO),a0

	move.l	(a0,mxp_struct_info_plugin_author),d0
	:
	:


2.2.1 mxp_struct_info_plugin_author
-----------------------------------

Pointer to NULL terminated string with plugin author's name.


2.2.2 mxp_struct_info_plugin_version
------------------------------------

Pointer to NULL terminated string with plugin version.


2.2.3 mxp_struct_info_replay_name
---------------------------------

Pointer to NULL terminated string with replay routine's name.


2.2.4 mxp_struct_info_replay_author
-----------------------------------

Pointer to NULL terminated string with replay routine's author name.


2.2.5 mxp_struct_info_replay_version
------------------------------------

Pointer to NULL terminated string with replay routine's version.


2.2.6 mxp_struct_info_flags
---------------------------

This bitfield tells plugin which resources wish to use. Currently 
defined are:

- MXP_FLG_USE_DSP: plugin uses DSP
- MXP_FLG_USE_DMA: plugin uses DMA sound system
- MXP_FLG_USE_020: plugin uses 020+ CPU
- MXP_FLG_USE_FPU: plugin uses FPU

So you use for example:

	dc.l	MXP_FLG_USE_DSP|MXP_FLG_USE_DMA|MXP_FLG_USE_020


2.3 Settings Structure
======================

Defined as 'mxp_struct_settings'. Each entry is 4 bytes long. The 
number of structures is unlimited.


2.3.1 mxp_struct_settings_name
------------------------------

Pointer to NULL terminated string with parameter's name. If NULL, no 
more parameters are read. This name is used as unique identifier so 
you can't use two parameters with the same name.

 
2.3.2 mxp_struct_settings_type
------------------------------

Type of parameter. Currently defined are:

- MXP_PAR_TYPE_BOOL: handle as 1 / 0 switch.

- MXP_PAR_TYPE_CHAR: handle as string parameter

- MXP_PAR_TYPE_INT:  handle as signed integer parameter

These types tell player what value will get after calling 'get' 
function or to what type should convert value which is on input of 
'set' function.

Please, don't use very long names for these parametes, you wont break 
anything, but you can get to the situation when you will have 
'very_long_parameter_name1' and 'very_long_parameter_name2' and 
application will see one 'very_long_parame' parameter).

There's a little different behaviour by interpreting values of these 
parameters according to the group they belong to.

For plugin parametes applies one general rule: output size is limited 
by the size of Plugin Info dialog. It's simply because there's a very 
small chance you will ever need more than a few charactes (in fact I 
can't imagine what kind of parameter you could pass to the plugin as 
CHAR type). Except this, there's a different interpretation of the 
BOOL parameter (comparing to module parameters): it's shown as 
checkable custom defined colour icon. So state '1' means icon checked 
and vice versa.

However, module parameters give the user possibility to scroll these 
values. So your parameter value (e.g. songname) can contain unlimited 
number of characters. Around this value will be shown left/right 
arrows which allow user to view te rest of text. Please note EVERY 
parameter will be converted to the string - both BOOL type (as 'Yes' 
/ 'No') and integer.

Each parameter type could/should be ORed with one or more flags:

- MXP_FLG_INFOLINE: parameter + its value will be shown on panel in 
                    scrolling infoline

- MXP_FLG_MOD_PARAM: parameter + its value will be shown in Module 
                     Info window

- MXP_FLG_PLG_PARAM: parameter + its value will be shown in Plugin 
                     Info window

For example:
		dc.l	param_original
		dc.l	MXP_PAR_TYPE_BOOL|MXP_FLG_MOD_PARAM
		:
		:

param_original:
		dc.b	'Original',0

and when 'get' will return 0, in the Module Info window you will see 
'Original: No'.


2.3.3 mxp_struct_settings_routine_set
-------------------------------------

Pointer to the 'Set' function. As was mentioned, if NULL, parameter 
will be marked as 'read only' (will be shaded in info window). Of 
course, this has some sense only in plugin parameters.

Please, don't mess up this function with the one discussed in chapter 
3.

Typical use of this function is to switch on/off some parameter 
(interpolation, surround, ...) or to pass some integer value (e.g. 
playtime if plugin doesn't provide accurate playtime determination). 
However, there's also text parameter for some special use.

After calling this function from application, plugin should expect 
value at MXP_PLUGIN_PARAMETER place. Application doesn't check any 
return code.


2.3.4 mxp_struct_settings_routine_get
-------------------------------------

Pointer to 'Get' function. This pointer can never be NULL! Plugin 
should return wanted value at MXP_PLUGIN_PARAMETER place. Application 
doesn't check any return code.


2.4 Extensions Structure
========================

Defined as 'mxp_struct_extensions'. Each entry is 4 bytes long. The 
number of structures is unlimited.


2.4.1 mxp_struct_extensions_string
----------------------------------

Pointer to NULL terminated string with supported module file 
extension. If NULL, no more parameters are read.


2.4.2 mxp_struct_extensions_name
--------------------------------

Pointer to NULL terminated string with the module extension full name.

For example:
	dc.l	am_extension_string
	dc.l	am_extension_name
	:
	:

am_extension_string:
	dc.b	"AM",0
am_extension_name:
	dc.b	"ACE Module",0


****************
* 3. Functions *
****************

This is the base interface between application and plugin. All 
functions except Playtime() should return result status in d0 
register - MXP_OK or MXP_ERROR.


3.1 Register()
==============

Register module. On the input (in the input buffer) plugin should 
expect pointer to two another pointers:

- buffer with module binary
- length of this buffer

Correct handling of this input is as follows:

		movea.l	ogg_header+MXP_PLUGIN_PARAMETER,a0
		move.l	(a0)+,ogg_buffer
		move.l	(a0),ogg_buffer_length

Please note you have to fill all things in Settings structure *NOW* ! 

Return MXP_OK if plugin is able to replay given module. Return 
MXP_ERROR if not. This could occur when you compare file header to 
some expected value and the values don't match.


3.2 Playtime()
==============

Return playtime for given module - some plugins are able to calculate 
it. If your plugin isn't able to do it, return let's say 2 minutes 
and allow user to change this value.


3.3 Init()
==========

Initialize plugin. Allocate space, precalc tables etc. Don't do 
anything with HW registers!


3.4 Set()
=========

Set module, i.e. save HW registers, set new ones, activate playing.


3.5 Unset()
===========

Opaque to Set(), i.e. stop playing, restore HW registers.


3.6 Forward()
=============

Skip some time forward. Currently unimplemented.


3.7 Rewind()
============

Move back some time. Currently unimplemented.


3.8 Pause()
===========

Pause playing. You have to care about on/off state, application will 
just call this function. Don't forget to deactivate pause status when 
Unset() is called.


**************
* 4. Remarks *
**************

Some important remarks about plugin making.


4.1 Startup Process
===================

1. Load plugin, call Init().

2. When user loads module, call Register(). [after this step infoline 
   will be filled via Get() functions in Settings structure]

3. If Register() was OK, call Set(); if not, release module from 
   memory (!)

4. When user stops playing, call Unset().

5. When user presses pause key, call Pause().

6. [Currently unimplemented] When user request to remove plugin, call 
   Deinit().


4.2 Communication Issues
========================

The application and plugin behave as classical client/server model. 
Each plugin is handled as new process (using Pexec() call). That 
means they are independent processes which theoretically can't share 
any memory. There are some solutions how to do it, I chose probably 
the simplest one - they share some global memory. This applies to two 
buffers:

- module buffer, which has to be accessible by both plugin and 
  application

- communication buffer, where plugin and application exchange data

Since plugin has no reason to access any of application's data, 
there's no problem to set memory model as 'Private' for the 
application. However, application needs some access to plugin's 
structures (parameters) so *YOU HAVE TO SET AT LEAST READABLE ACCESS 
TO THE PLUGIN*. This can by done by many tools, from CPX to Jinnee's 
info dialog.


4.3 Stability
=============

In the ideal case when application is free of bugs there's still very 
important thing which applies to overall application stability: 
stability of plugins.

Typical example, how to hang FreeMiNT kernel and/or XaAES is to use 
some custom exception vector, e.g. Timer A/B/C/D. If there is no way 
how to avoid using it, please (PLEASE!) use following approach:

- always save/restore everything you use

- try to call original exception vector after you finished your stuff 
  (yes, there are some potential problems with the situation if some 
  other application uses similar approach and then such application 
  restore original exception pointer... this is trying to solve XBRA 
  protocol but... you know ;)

- set memory model to 'Super'. This means except your plugin you 
  provide access to your application space also for all applications 
  in Supervisor mode (i.e. FreeMiNT kernel). This fix well know FATAL 
  ERRORs in FreeMiNT with memory protection.

I have to say, it's not ideal solution but there's no other way. MiNT 
guys are very upset when comes a talk to similar practices but do we 
want some good player or not?


4.4 What You Don't Need To Do
=============================

Application try to do some work for you, concretly:

- lock/unlock resources you've specified in the info structure. So 
  you don't need to do it by hand. Or... you MUST NOT to do it ;)

- convert bools and ints to strings and vice versa. So if you want to 
  show your plugin replays 8 channel module you don't need to convert 
  the number '8' to the string.

- Mshrink(). Avoid using of this call, this is called on the startup 
  time.

- Super() calls. You don't need to call this call anytime. Every 
  function as called via Supexec(). Yeah yeah, I know, not very safe 
  but I have the control over super/user stack which I found as the 
  most important factor.


**************
* 5. Contact *
**************

Since I'm the author of this API it comes to me as very easy and 
understable. However, don't hesistate to contact me with ANY your 
question, I'm open to answer even the most primitive one you can 
imagine ;) The main goal is to motivate people to code as much 
plugins as possible. So don't wait, take your favorite replay routine 
and make new MXP plugin!

You can reach me 7 days of week at:

mikro@hysteria.sk

In case of some unexpected things (server crash etc) you can contact 
Xi, the author of the most of plugins in this release:

xi@napri.sk



... happy plugging!


      -----------         Don't forget to visit    -----------
      -----------        http://mxplay.atari.org   -----------

MiKRO / Mystic Bytes                      -XI- / Satantronic
http://mikro.atari.org                    http://satantronic.atari.org
http://msb.neostrada.pl

      -----------         Don't forget to visit    -----------
      -----------            http://atari.sk       -----------
