............ _________ _________ '::::::::;::_\ ¬/_._\_ _/_. ::| - | | | ¬| OOOoOo. :;| | | | | OOoo:;: ;:|. . |. | | | Oo::;O::o::|:.. | |:. | | | 'Oo:o::::://_____|____//___|___|mcL! J.ust a.nother M.usic Player SDK Plug-in(Api) Description v1.0 www.creamhq.de The information in this document is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Cream. Cream assumes no respon- sibility or liability for any errors or inaccuracies that may appear in this document. The software described in this doc- ument is furnished under license and may only be used or copied in accordance with the terms of such license. ;) Candyman/Cream 25.04.2000 1. Introduction 2. Getting Started 3. The Anatomy of a Plug-in 3.1 Life Cycle of a Plug-in 4. Messages Overview 5. Plug-In Information Structure 6. Song Information Structure 7. Why i Hate to Write Documantations --------------------------------------------------------------- 2. Getting Started --------------------------------------------------------------- To get started you will need an assembler of course. The source templates for both Turboass and Devpac are included. You should use a template as starter source to build up your own plugin, because it's important, that some structures inside the plugins are correct. If not, hasta la vista baby ;) A PlugIn source template for C is not included yet. If someone needs it, we could do one. Hmm... or better do it for your own. Isn't too much work. It isn't that hard to do a PlugIn for JAM. U just need to load the source template and concat the replayer source at the end. For a minimum implementation of a replayer you only need to change some things and voila...u've mastered your first Plug-In for JAM. IMPORTANT: Never pack your Plug-In. This is not possible because JAM calls the Plug-In more than once and i'm not sure what will happen if the depacker code is still there. MUCH MORE IMPORTANT: Be smart, code cleanly! (Mmm i guess "Evil" can't avoid a smile here anyway ;) ) JAM is available as a GEM application, so your Plug-In should use code as clean as possible!. Unproper code could probably cause conflicts with other applications. Try to avoid big BSS segments. If you need a big memory-block, then better allocate it. Jam allows to load all plug-ins into memory at the same time (depending on a JAM preference (static or dynamic loading of plug-ins)). If u place all into your BSS segment, the memory will not be used, until the plug-in gets activated. Wasted memory could probably cost you another plugin which woould not be loaded then. There are some special calls for the plug-ins for activation and deactivation. Use these calls toallocate the your memory.... Never place your sound DMA buffer into the BSS segment of your plug-in. Perhaps it will work on your computer. But keep mind, that there are computers with fastram. So be sure, that strange noises are coming up if u do this !!! MEGA IMPORTANT: Never use Timer C in your replayer! The system uses it to handle for example mouse clicks or 200hz timer. ---------------------------------------------------------------- 3. The Anatomy of a Plug-In ---------------------------------------------------------------- A JAM plug-in needs to be an executable file. The executable is needed to handle the relocation of the code. U don't need to set the FastLoadBit or AlternativeMemoryUseBit. JAM has got its own loader for the plugins and handles this for you. The plugin architecture of JAM is message-based. The shell sends out a package with commands (opcodes) and data, and the plug-in has to serve them. The entire communication / data movement is handled by registers. On entry (To the Plug-In): -------------------------------- a0 = void* ( data ); d0 = long ( value ) d1 = long ( msg ) -> Plug-In call On exit (From the Plug-In): -------------------------------- a0 = void* ( data ); The plug-in has got one main entry point. Based on the value in the command-register d1, it has to offer the different routines which are needed to handle the idividual music-formats. ---------------------------------------------------------------- 3.1 Life Cycle of a Plug-In ---------------------------------------------------------------- At startup JAM scans the plugin-folder for existing plugins. The plug-ins are loaded, relocated and executed. By this, the shell gets informations about the plug-in, like e.g.: - supported file-extensions - name of the plug-in, etc. - informations of supported features, like songname, playtime... - and some more... However, without this call the plug-in is not useable for JAM. Directly after this call the plug-in is kicked out of memory. JAM is able to handle two different kinds of plug-ins after startup: 1. Static Loading: After startup, all plug-ins are unloaded to perform a minimun memory usage. The plug-in will be loaded when it's needed. It is kept in memory until JAM is left (crashed?;)) or the user changes to the other mode. The advantage if this mode should be clear. It is just to speed up the entire handling of the slug-ins a bit. Some plug-ins are preparing tables at init time (e.g the AHX replayer). In static mode this is only done once. 2. Dynamic Loading: The plug-in is only loaded, when when it is needed, but it will be kicked from memory when another plugin is restarted. Advantage: minmum memoryusage. ---------------------------------------------------------------- 4. Messages Overview ---------------------------------------------------------------- As described above, JAM sends messages to the plug-ins and the plugin has to decide what to do depending on the message-opcode. Here is a short overview of supported commands: PLUGINEXTINFO EQU 1 PLUGINEXTINIT EQU 2 PLUGINEXTACTIVATE EQU 3 PLUGINEXTSONGSELECT EQU 4 PLUGINEXTSONGINFO EQU 5 PLUGINEXTSONGPLAY EQU 6 PLUGINEXTSONGSTOP EQU 7 PLUGINEXTDEACTIVATE EQU 8 PLUGINEXTDEINIT EQU 9 PLUGINEXTNEXTSONGHOOK EQU 10 Let's have a closer look on the messages and how to handle them: ***************************** PLUGINEXTINFO message ***************************** This message is sent directly after the plugin is loaded on startup. As described above, it's just to get some informations about the plug-in itself. The only thing for you to do is to return a pointer to the pluginfo-structure in a0. You can find a closer description of the pluginfo-structure in chapter "Plug-In Information Structure". IMPORTANT: Never place any init routines in this message, because the stuff which u are doing is not persistent, so it will be lost ! Register overview: In = - Out = A0: pointer to the pluginfo-structure ***************************** PLUGINEXTINIT message ***************************** This message is sent to init the plug-in direclty after it has been loaded. If u need some special static precalcs, like wave- tables or so, place it in this routine. If possible do not place big memory allocs for example buffers because, if static loading of plug-ins is activated, the memory is allocated all the time. Register overview: In = - Out = - ***************************** PLUGINEXTDEINIT message ***************************** This message is sent directly before the plug-in is kicked off from memory. It's just to clean up your stuff. Register overview: In = - Out = - ***************************** PLUGINEXTACTIVATE message ***************************** This is a special message for static loading of plug-ins. It is called when the plug-in gets activated. If, for example all plug -ins are already loaded and resident in memory, and if the user selects a song, JAM sents this message before your plugin starts to play. It's ideal to place memory allocs here. Of course this message is also sent, when JAM is running in the dynamic plugin-mode. Register overview: In = - Out = - ***************************** PLUGINEXTDEACTIVATE message ***************************** Is sent, when JAM has to change the Plug-In. Include here your memory-cleanups. One thing is important. Never mix PLUGINEXTINIT mallocs ( if u really need to alloc in this message) and PLUGINEXTDEACTIVATE frees. Just keep in mind PLUGINEXTDEACTIVATE can be called more than once! So only free stuff in PLUGINEXTDE- ACTIVATE if u alloced it in PLUGINEXTACTIVATE. Register overview: In = - Out = - ***************************** PLUGINEXTSONGSELECT message ***************************** This is called from JAM to select a song. If your plugin is stream oriented, you will get the file name in A0. Otherwise it the pointer to the music data will be returned. You have to save this pointer to remember where the musicdata is placed in memory Register overview: In = A0 Pointer to the music data. Save it for later use. D0 Song number Out = - ***************************** PLUGINEXTSONGPLAY message ***************************** Should be clear i guess. But one important thing. You have to do an irq-rout for your own, that means JAM doesn't handle irqs..!! Please do not use vbl or vbl query. There are some people using vga ;) And to use a normal VBL vector is a bit unclean....So use a timer instead !!! In = - Out = - ***************************** PLUGINEXTSONGSTOP message ***************************** This should stop the entire song activity. Remove all irqs and timers and switch the sound off. In = - Out = - ***************************** PLUGINEXTNEXTSONGHOOK message ***************************** This is to let JAM know, wether your replayer recognised, that the song has reached its end. JAM calls the plugin and gives you a pointer in a0. If your replayer recognises, that the song has been finished, you just have to write a move.w #1,(a0) to that adress. If JAM recognises a '1' in that adress, it jumps to the next song in the playlist. In = A0: a word pointer. Save this pointer for later use. Out = - ***************************** PLUGINEXTSONGINFO message ***************************** This is to provide some special informations about the song. In = A0: a pointer to the Song Information Structure. You can modify the structure but u don't need to fill out all. Out = - For a closer description of the structure have a look to the "Song Information Structure" in chapter 6. ---------------------------------------------------------------- 5. Plug-In Information Structure ---------------------------------------------------------------- The plug-in information structure carries all Information JAM needs to know about the plug-in. You just have to fill the structure with life and return the pointer to it when the PLUGIN EXTINFO was sent. Very easy ;) Example: ;--------------------------------------------------------------- ;be careful with the lengthes of the strings ;for example turboass don't show an error if the ;string is too long...it only shows in ;the status line something like "turns to negative" or so PLUGININFO: INTERFACEVERSION:dc.w $0100 ; api version VERSION: DC.W $0100 ; e.g. 1.0 DATE: DC.B "20.07.2000" ; date of the Plug-In DATEE: DS.B 12-(DATEE-DATE) JAM can handle up to 8 file extensions per plug-in, but only use 6 of the 8 because the last 2 are user-file-extenions. The user can set them up in the preference dialog.! FILEEXT: DC.B ".TFX" FILEEXTE: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT2: DC.B " " FILEEXTE2: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT3: DC.B " " FILEEXTE3: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT4: DC.B " " FILEEXTE4: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT5: DC.B " " FILEEXTE5: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT6: DC.B " " FILEEXTE6: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT7: DC.B " " FILEEXTE7: DS.B 6-(FILEEXTE-FILEEXT) FILEEXT8: DC.B " " FILEEXTE8: DS.B 6-(FILEEXTE-FILEEXT) NAME: DC.B "Tfmx Replay" ;Standard infos etc.. NAMEE: DS.B 128-(NAMEE-NAME) CODER: DC.B "Candyman" CODERE: DS.B 128-(CODERE-CODER) EMAIL: DC.B "Candyman@atari.org" EMAILE: DS.B 128-(EMAILE-EMAIL) WWW: DC.B "cream.atari.org" WWWE: DS.B 128-(WWWE-WWW) COMMENT: DC.B "cream.atari.org" COMMENTE: DS.B 128-(COMMENTE-COMMENT) ******************************** ;1 = plugin uses dsp isdsp: dc.w 0 ******************************** ;Tells JAM for which machines is the plugin. this is a bit field ;1 = st ;2 = ste ;4 = tt ;8 = mega ste ;16 = falcon support: dc.w 0 ******************************** Used at the moment. Should be always 0. datastart: dc.l 0 ******************************** This is to tell JAM, that the plugin handles the end of the song recognation. Otherwise JAM has to handle it via replaytime. ; 1 = true ; 0 = false supportsnextsonghook: dc.w 0 ******************************** This is to tell JAM that the plugin handles the songinfo for the name of the song otherwise JAM has to handle it. If true, the field in the Songinfo-Dialog is disabled. ; via inf-file. ; 1 = true ; 0 = false supportsname: dc.w 0 ******************************** This is to tell JAM that the plugin handles the songinfo for the composer of the song. Otherwise JAM has to handle it. If true, the field in the Songinfo-dialog is disabled. ; via inf-file. ; 1 = true ; 0 = false supportscomposer:dc.w 0 ******************************** This is to tell JAM that the plugin handles the songinfo for the songcount of the song. Otherwise JAM has to handle it. If true, the field in the Songinfo-dialog is disabled. supportssongcount:dc.w 0 ******************************** This is to tell JAM that the plugin handles the songinfo for the preselect of the song otherwise JAM has to handle it. If true, the field in the Songinfo-dialog is disabled. supportspreselect:dc.w 0 ******************************** This is to tell JAM that the plugin handles the songinfo for the comment of the song otherwis JAM has to handle it. If true, the field in the Songinfo-Dialog is disabled. supportscomment:dc.w 0 ******************************** Tells Jam if the plugin is fastram compatible... 1 = true 0 = false fastram:dc.w 0 ******************************** ---------------------------------------------------------------- 6. Song Information Structure ---------------------------------------------------------------- The song information structure is to get special informations about the currently replayed song. If JAM calls the plugin with the PLUGINEXTSONGINFO message, the song is already located in memory. There has already been a PLUGINEXTSONGSELECT, so u know where the song is placed in memory. You can now send all special informations about the song to the shell and they will be dis- played at the gui. U will get a pointer in A0 to that structure. If the message is send to your plugin, JAM fills the structure with all infos it has about the song. If an 'inf' - file of that song exsits, it will be loaded and the structure be filled. If you don't have any informations about the song, just ignore that message. Here's the definition of the information structure. All strings are 'c' - formatted strings. That means, you have to add a '0' (false) byte to terminate the string. SI_TITLE: rs.b 256 SI_COMPOSER: rs.b 256 SI_RIPPER: rs.b 256 SI_EMAIL: rs.b 256 SI_WWW: rs.b 256 SI_COMMENTS: rs.b 256 SI_SONGHZ: rs.w 1 SI_SONGCOUNT: rs.w 1 SI_SONGPRESELECT: rs.w 1 SI_ISYMSONG: rs.w 1 SI_DMAHZ: rs.l 1 SI_FILENAME: rs.w 256 SI_PLAYTIME_MIN: rs.w 99 SI_PLAYTIME_SEC: rs.w 99 If u want to modify the title of the song, u can do it like this. lea SI_TITLE(a0),a1 move.l #'Rob!',(a1)+ move.b #0,(a1)+ This will display the master's name "Rob!" ;) as the song title. ---------------------------------------------------------------- 7. Why i Hate to Write Documantations ---------------------------------------------------------------- Well that's easy...It's just boring. ;)