home *** CD-ROM | disk | FTP | other *** search
- /* FXDEMO
- * A simple example for an EFFECTSPROCESSOR xapp application
- * Author : Dominique Lorre
- * $Id$
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/semaphores.h>
- #include <intuition/gadgetclass.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/graphics.h>
- #include <proto/intuition.h>
- #include <proto/gadtools.h>
- #include <clib/macros.h>
-
- #include "/xappmsg.h"
- //#include "mydebug.h"
-
-
- struct FXNode* n ;
- struct List* l ;
- struct Window* xappwin ;
- struct Gadget* glist ;
- struct Gadget* gad ;
- APTR vi ;
- struct Screen *ps ;
- BOOL winopen ;
-
- struct MsgPort* MyPort ;
- struct MsgPort* XAppPort ;
- struct MsgPort* replyPort ;
-
- struct Hook FXProcessor ;
- char MyPortName[XAPPNAMELENGTH] ;
- APTR xHandle ;
-
- struct TagItem ti[] = {
- {XAPP_Name, (ULONG)"FX-DEMO"},
- {XAPP_PortName, (ULONG)MyPortName},
- {XAPP_Type, (ULONG)XAPPTYP_EFFECTSPROCESSOR},
- {FX_Hook, (ULONG)&FXProcessor},
- {TAG_DONE}
- };
-
- struct TagItem th[] = {
- {XAPP_Handle, NULL},
- {TAG_DONE}
- };
-
- struct fxDemoData {
- struct SignalSemaphore *fxd_Semaphore ;
- LONG fxd_Len ;
- WORD fxd_Repeat ;
- WORD fxd_Variation ;
- WORD fxd_Volume ;
- BOOL fxd_ByPass ;
- } fData ;
-
- struct SignalSemaphore *MySemaphore ;
-
- static ULONG winsig, msig, signal ;
- BOOL fin ;
- #define HIGHPRI 21
-
- struct XAppMsg *xmsg, *replymsg, *emsg ;
-
- extern __stdargs ULONG HookEntry() ;
-
- VOID main(VOID) ;
- BOOL InitAll(void) ;
- BOOL CloseAll(WORD level) ;
- void ProcessEvents(void) ;
- BOOL InitWin(void) ;
- BOOL CloseWin(WORD level) ;
- void ProcessWinEvents(void) ;
- VOID StripWindow(struct Window *win) ;
- VOID StripIntuiMessages( struct MsgPort *mp, struct Window *win ) ;
- VOID StripMessages( struct MsgPort *mp ) ;
-
- ULONG __saveds __asm FX(register __a0 struct Hook *h,
- register __a2 APTR Object,
- register __a1 struct FXParams *fp) ;
-
- /****** fxdemo.c/FX ********************************************************
- *
- * NAME
- * FX -- Hook function for effects processing
- *
- * SYNOPSIS
- * result = FX(h, Object, fp)
- * ULONG __stdargs FX(struct Hook *, APTR, struct FXParams *)
- *
- * FUNCTION
- * This is the Hook function that will be invoked by Euterpe when processing
- * events for effects.
- *
- * INPUTS
- * h The Hook initialized by this module
- * Object Currently NULL
- * fp A FXParams structure described in xappmsg.h
- *
- * RESULTS
- * result 1 if everything ok and 0 if failure (other effects will be
- * skipped)
- *
- * NOTES
- * All the new events have to be placed on the same List, the best way
- * to do this is to use exec.library/AddHead(). Do NOT expect the list
- * to be sorted by time since effects might be chained. This function
- * will be called in the heart of a realtime process running at a high
- * priority (actually 21), so slow functions involving disk access,
- * keyboard input or the like must be invoked externally, by signalling.
- * If your window is providing parameters, a Semaphore protection
- * will be needed.
- * NEVER EVER INSERT NOTEOFF EVENTS IN THE LIST
- * Inserting a NoteOff is a bad idea because these events must be linked to
- * the correct NoteOn. For the control of NoteOff, use the x_Len field which
- * set the duration of a NoteOn and the x_Data[3] field which set the
- * velocity of the released note.
- * NoteOff events will be inserted by Euterpe at the end of the FX parsing.
- * NoteOn with x_Len = 0 are subject to crashes
- * DO NOT EXPECT TO UNDERSTAND ALL EVENTS
- * Events will be documented in the future because some are really special
- * such as tempochanges. For allowing your effect to work in the future, just
- * keep the unknowned events unchanged. You can of course modify their pos
- * but timesig events might be moved by Euterpe at the beginning of a
- * measure.
- * DO NOT MAKE ANY ASSUMPTIONS ON WHAT WILL BE DONE WITH THIS EFFECT
- * If you can. Because the effects might be modified in the future
- * to operate on input flow, to write themselves to a track or even to be
- * lended as services to other tasks.
- * SEE ALSO
- * utility/hooks.h utility.library/CallHookPkt
- ****************************************************************************
- *
- */
-
- ULONG __saveds __asm FX(register __a0 struct Hook *h,
- register __a2 APTR Object,
- register __a1 struct FXParams *fp)
- {
- struct FXNode *n, *c, *s ;
- struct fxDemoData *fxd ;
- UBYTE type ;
- LONG val, r ;
-
- fxd = (struct fxDemoData *)h->h_Data ;
-
- // Semaphore protection is a must if you want to allow the user
- // to modify the parameters while playing.
-
- ObtainSemaphore(fxd->fxd_Semaphore) ;
-
- if (!IsListEmpty((struct List *)fp->fp_List)) {
-
- // if we are the first effect the list will contain one event
- // the linked effects will found what has been put by their
- // predecessors
-
- n = (struct FXNode *)fp->fp_List->mlh_Head ;
- while (n->x_Node.mln_Succ) {
- s = (struct FXNode *)n->x_Node.mln_Succ ;
- if (!fxd->fxd_ByPass) {
- type = n->x_Data[0] & 0xF0 ;
- // This is a noteon
- if (type == 0x90) {
- // Note transposition
- val = n->x_Data[1] + fxd->fxd_Variation ;
- n->x_Data[1] = (val > 0) ? MIN(val, 0x7F) : 0 ;
-
- for (r = 0; (r < fxd->fxd_Repeat); r++) {
-
- // Since we are in a RealTime application
- // we do not lose time by doing some garbage
- // collection. This code is safe because the array
- // will be reset by Euterpe when a new event will
- // appear
-
- fp->fp_Pos++ ;
- c = (fp->fp_Pos < fp->fp_Size) ? &(fp->fp_Array[fp->fp_Pos]) : NULL ;
-
- if (c) { // We have the new event node
- c->x_Msg = n->x_Msg ; // fast copy of the data
-
- if (fxd->fxd_Len>1) {
- c->x_Pos = n->x_Pos + fxd->fxd_Len ;
- c->x_Len = n->x_Len ;
- if (n->x_Len > fxd->fxd_Len) {
- n->x_Len = fxd->fxd_Len-1 ; // len > 0 !
- }
- }
- // Volume handling
- if (fxd->fxd_Volume > 0) {
- val = c->x_Data[2] * (fxd->fxd_Volume+1) ;
- c->x_Data[2] = MIN(val, 0x7F) ;
- val = c->x_Data[3] * (fxd->fxd_Volume+1) ;
- c->x_Data[3] = MIN(val, 0x7F) ;
- }
- else if (fxd->fxd_Volume < 0) {
- c->x_Data[2] /= -fxd->fxd_Volume+1 ;
- c->x_Data[3] /= -fxd->fxd_Volume+1 ;
- }
- // Add to list
- // Keeping the list sorted might allow quicker
- // effects if the sorting operation is really fast
- AddHead((struct List *)fp->fp_List, (struct Node *)c) ;
- }
- }
- }
-
- }
- n = s ;
- }
- }
- ReleaseSemaphore(fxd->fxd_Semaphore) ;
- return 1 ;
- }
-
- VOID main(VOID)
- {
- int retval ;
-
- if (InitAll()) {
- ProcessEvents() ;
- retval = CloseAll(0)?RETURN_OK:RETURN_FAIL;
- }
- else
- retval = RETURN_FAIL ;
- exit(retval) ;
- }
-
- /****** fxdemo.c/InitAll ***************************************************
- *
- * NAME
- * InitAll -- Main Initializations
- *
- * SYNOPSIS
- * success = InitAll()
- * BOOL InitAll(void)
- *
- * FUNCTION
- * InitAll allocates all needed resources step by step and is responsible
- * for the initialization of the communication with Euterpe. CloseAll will
- * be called in case of failure.
- *
- * INPUTS
- * None
- *
- * RESULTS
- * success TRUE if the initialization succeed, FALSE if not
- *
- * BUGS
- * This function has a weak point because it may fail if Euterpe is closing
- * when this task is loading. Forbid()/Permit() might solve the problem.
- * Anyway, under normal use effects will not be loaded when Euterpe is
- * exiting and developers have been asked not to use Forbid(). If
- * someone has an idea...
- *
- * SEE ALSO
- * fxdemo.c/CloseAll
- ****************************************************************************
- *
- */
- BOOL InitAll(void)
- {
- // First, create a ReplyPort for communication with Euterpe
-
- replyPort = CreateMsgPort() ;
- if (!replyPort)
- return CloseAll(1) ;
-
- // Now, initialize the Message
-
- if (xmsg = (struct XAppMsg *)AllocVec(sizeof(struct XAppMsg), MEMF_CLEAR|MEMF_PUBLIC)) {
- xmsg->xm_Message.mn_Node.ln_Type = NT_MESSAGE ;
- xmsg->xm_Message.mn_Length = sizeof( struct XAppMsg ) ;
- xmsg->xm_Message.mn_ReplyPort = replyPort ;
- }
- else
- return CloseAll(2) ;
-
- // Our private semaphore
-
- if (MySemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore), MEMF_CLEAR|MEMF_PUBLIC)) {
- InitSemaphore(MySemaphore) ;
- }
- else
- return CloseAll(3) ;
-
- // Parameters initialization
- fData.fxd_Semaphore = MySemaphore ;
- fData.fxd_Repeat = 2 ;
- fData.fxd_Len = 192 ;
- fData.fxd_Volume = -2 ;
- fData.fxd_Variation = 12 ;
- fData.fxd_ByPass = FALSE ;
-
- // Hook initialization
- FXProcessor.h_Entry = (HOOKFUNC)FX ;
- FXProcessor.h_SubEntry = NULL ;
- FXProcessor.h_Data = &fData ;
-
- // Look at Euterpe's xapp port
-
- if (XAppPort = FindPort((UBYTE *)XAPPPORTNAME)) {
- // Euterpe is here, let's register
- xmsg->xm_Action = XAPPACT_ADD ;
- xmsg->xm_Tags = ti ;
- PutMsg(XAppPort, (struct Message *)xmsg);
- WaitPort(replyPort) ;
- replymsg = (struct XAppMsg *)GetMsg(replyPort) ;
- // Euterpe has given us a name for our port
- xHandle = replymsg->xm_Result ;
- if (!xHandle)
- return CloseAll(4) ;
- th[0].ti_Data = (ULONG)xHandle ;
- }
- else
- return CloseAll(4) ;
-
- // Now, create our Port with the name given by Euterpe
-
- MyPort = CreatePort(MyPortName, NULL);
-
- // We are ready now, tell Euterpe how the init was
-
- xmsg->xm_Action = MyPort ? XAPPACT_INIT : XAPPACT_FAILURE ;
- xmsg->xm_Tags = th ;
- PutMsg(XAppPort, (struct Message *)xmsg);
- WaitPort(replyPort) ;
- replymsg = (struct XAppMsg *)GetMsg(replyPort) ;
-
- if (!MyPort)
- return CloseAll(5) ;
-
- msig = 1 << MyPort->mp_SigBit ;
- return TRUE ;
- }
- /****** fxdemo.c/CloseAll **************************************************
- *
- * NAME
- * CloseAll -- Deallocates the resources
- *
- * SYNOPSIS
- * success = CloseAll(level)
- * BOOL CloseAll(WORD)
- *
- * FUNCTION
- * CloseAll() will deallocate all the successfully allocated resources
- *
- * INPUTS
- * level 0 if normal deallocation or the step where allocation failed
- *
- * RESULTS
- * success TRUE if called with level=0 FALSE in other cases
- *
- ****************************************************************************
- *
- */
-
- BOOL CloseAll(WORD level)
- {
- switch(level) {
- case 0:
- DeletePort(MyPort) ;
- case 5:
- case 4:
- FreeVec(MySemaphore) ;
- case 3:
- FreeVec(xmsg) ;
- case 2:
- DeleteMsgPort(replyPort) ;
- }
- return (BOOL) ( level ? FALSE : TRUE ) ;
- }
-
- void ProcessEvents(void)
- {
- ULONG sigmask ;
- BOOL end ;
- enum XAppAction action ;
-
- end = winopen = FALSE ;
-
- while (!end) {
- sigmask = msig ;
- if (winopen) sigmask |= winsig ;
- signal = Wait(sigmask) ;
- if (signal & winsig) {
- // A better way of doing this could be to place the semaphore
- // calls at the beginning of each modification of the fData fields
- ObtainSemaphore(MySemaphore) ;
- ProcessWinEvents() ;
- if (!winopen)
- CloseWin(0) ;
- ReleaseSemaphore(MySemaphore) ;
- }
- if (signal & msig) {
- while (emsg = (struct XAppMsg *)GetMsg(MyPort)) {
- action = emsg->xm_Action ;
- // Do not reply to a remove msg
- // since Euterpe do not wait for it
- if (action != XAPPACT_REMOVE)
- ReplyMsg((struct Message *)emsg) ;
- switch (action) {
- case XAPPACT_SHOW:
- if (!winopen && InitWin())
- winopen = TRUE ;
- break ;
- case XAPPACT_REMOVE:
- end = TRUE ;
- case XAPPACT_HIDE:
- if (winopen) {
- CloseWin(0) ;
- }
- break ;
- }
- }
- }
- }
- }
-
- LONG __saveds VolumeLevel(struct Gadget *g, WORD level)
- {
- static char s[30] ;
- static char v[8] ;
-
- if (level < 0) {
- stci_d(v, -level+1) ;
- strcpy(s, "Divide Volume by ") ;
- strcat(s, v) ;
- }
- else if (level > 0) {
- stci_d(v, level+1) ;
- strcpy(s, "Multiply Volume by ") ;
- strcat(s, v) ;
- }
- else strcpy(s, "Keep Volume") ;
- return (LONG)s ;
- }
-
- BOOL InitWin(void)
- {
- struct NewGadget ng ;
- UWORD winZoom[4] = { 50, 50, 300, 20 } ;
-
- ps = LockPubScreen((UBYTE *)"Euterpe") ; // Get the Euterpe public screen
- if (!ps)
- return CloseWin(1) ;
-
- winZoom[0] = winZoom[3] = ps->BarHeight ; // cosmetic details
-
- vi = GetVisualInfo(ps, NULL) ;
- if (!vi)
- return CloseWin(2) ;
-
- glist = NULL ;
- gad = CreateContext(&glist) ;
- if (!gad)
- return CloseWin(3) ;
-
- ng.ng_VisualInfo = vi ;
- ng.ng_TextAttr = ps->Font ;
-
- ng.ng_TopEdge = ps->BarHeight + 8 ; // font adaptative method
- ng.ng_LeftEdge = 20 ;
- ng.ng_Width = 10 ;
- ng.ng_Height = ng.ng_TextAttr->ta_YSize * 3 / 2 ;
- ng.ng_GadgetID = 1 ;
- ng.ng_GadgetText = (UBYTE *)"ByPass" ;
- ng.ng_Flags = PLACETEXT_RIGHT ;
-
- gad = CreateGadget(CHECKBOX_KIND, gad, &ng,
- GTCB_Checked, fData.fxd_ByPass,
- TAG_DONE);
-
- if (!gad)
- return CloseWin(4);
-
- ng.ng_TopEdge += ng.ng_Height + 8 ;
- ng.ng_LeftEdge = 20 ;
- ng.ng_Width = 128 ;
- ng.ng_Height = 20 ;
- ng.ng_GadgetID = 2 ;
- ng.ng_Flags = PLACETEXT_RIGHT ;
-
- gad = CreateGadget(SLIDER_KIND, gad, &ng,
- GTSL_Min, -64,
- GTSL_Max, 64,
- GTSL_Level, fData.fxd_Variation,
- GTSL_LevelFormat, "Transposition : %ld",
- GTSL_MaxLevelLen, 20,
- GTSL_LevelPlace, PLACETEXT_RIGHT,
- GA_RelVerify, TRUE,
- TAG_DONE);
- if (!gad)
- return CloseWin(4);
-
- ng.ng_TopEdge += ng.ng_Height + 8 ;
- ng.ng_GadgetID = 3 ;
-
- gad = CreateGadget(SLIDER_KIND, gad, &ng,
- GTSL_Min, 0,
- GTSL_Max, 192*4,
- GTSL_Level, fData.fxd_Len,
- GTSL_LevelFormat, "Delay Length : %ld",
- GTSL_MaxLevelLen, 19,
- GTSL_LevelPlace, PLACETEXT_RIGHT,
- GA_RelVerify, TRUE,
- TAG_DONE);
- if (!gad)
- return CloseWin(4);
-
- ng.ng_TopEdge += ng.ng_Height + 8 ;
- ng.ng_GadgetID = 4 ;
- ng.ng_Flags = PLACETEXT_RIGHT ;
-
- gad = CreateGadget(SLIDER_KIND, gad, &ng,
- GTSL_Min, 0,
- GTSL_Max, 10,
- GTSL_Level, fData.fxd_Repeat,
- GTSL_LevelFormat, "Repeat : %ld times",
- GTSL_MaxLevelLen, 19,
- GTSL_LevelPlace, PLACETEXT_RIGHT,
- GA_RelVerify, TRUE,
- TAG_DONE);
- if (!gad)
- return CloseWin(4);
-
- ng.ng_TopEdge += ng.ng_Height + 8 ;
- ng.ng_GadgetID = 5 ;
- ng.ng_Flags = PLACETEXT_RIGHT ;
-
- gad = CreateGadget(SLIDER_KIND, gad, &ng,
- GTSL_Min, -8,
- GTSL_Max, 8,
- GTSL_Level, fData.fxd_Volume,
- GTSL_LevelFormat, "%s", /* Did you knew this trick ? :) */
- GTSL_DispFunc, VolumeLevel,
- GTSL_MaxLevelLen, 25,
- GTSL_LevelPlace, PLACETEXT_RIGHT,
- GA_RelVerify, TRUE,
- TAG_DONE);
- if (!gad)
- return CloseWin(4);
-
- /* Open a simple window */
- xappwin = OpenWindowTags(NULL,
- WA_Left, 50,
- WA_Top, ps->BarHeight,
- WA_Width, 300,
- WA_Height, ng.ng_TopEdge + ng.ng_Height + 8, // font adaptative
- WA_Title, MyPortName,
- WA_CloseGadget, TRUE,
- WA_DepthGadget, TRUE,
- WA_Gadgets, glist,
- WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW|
- CHECKBOXIDCMP|SLIDERIDCMP,
- WA_DragBar, TRUE,
- WA_Activate, TRUE,
- WA_PubScreen, ps,
- WA_Zoom, winZoom,
- TAG_DONE) ;
-
- if (xappwin) {
- GT_RefreshWindow(xappwin, NULL) ;
- winsig = 1 << xappwin->UserPort->mp_SigBit ;
- return TRUE ;
- }
- else
- return CloseWin(5) ;
-
- }
-
- BOOL CloseWin(WORD level)
- {
- winopen = FALSE ;
- switch(level) {
- case 0:
- StripWindow(xappwin) ;
- CloseWindow(xappwin) ;
- xappwin = NULL ;
- winsig = 0 ;
- case 5:
- case 4:
- FreeGadgets(glist) ;
- case 3:
- FreeVisualInfo(vi) ;
- case 2:
- UnlockPubScreen(NULL, ps) ;
- }
- return (BOOL) ( level ? FALSE : TRUE ) ;
- }
-
- void ProcessWinEvents(void)
- {
- ULONG classe ;
- UWORD code ;
- struct IntuiMessage* imsg ;
- struct Gadget* gad ;
-
- while (imsg = GT_GetIMsg(xappwin->UserPort)) {
- classe = imsg->Class ;
- code = imsg->Code ;
- gad = (struct Gadget *)imsg->IAddress ;
- GT_ReplyIMsg(imsg) ;
- switch (classe) {
- case IDCMP_REFRESHWINDOW:
- GT_BeginRefresh(xappwin) ;
- GT_EndRefresh(xappwin, TRUE) ;
- break ;
- case IDCMP_GADGETUP:
- switch (gad->GadgetID) {
- case 1:
- fData.fxd_ByPass = code ;
- break ;
- case 2:
- fData.fxd_Variation = code ;
- break ;
- case 3:
- fData.fxd_Len = code ;
- break ;
- case 4:
- fData.fxd_Repeat = code ;
- break ;
- case 5:
- fData.fxd_Volume = code ;
- break ;
- }
- break ;
- case IDCMP_CLOSEWINDOW:
- winopen = FALSE ;
- break ;
- }
- }
- }
-
- /* Useful C= functions */
-
- VOID StripWindow(struct Window *win)
- {
- Forbid();
- StripIntuiMessages(win->UserPort, win);
- win->UserPort = NULL;
- ModifyIDCMP(win, NULL);
- Permit();
- }
-
- VOID StripIntuiMessages( struct MsgPort *mp, struct Window *win )
- {
- struct IntuiMessage *msg;
- struct Node *succ;
-
- msg = (struct IntuiMessage *) mp->mp_MsgList.lh_Head;
-
- while( succ = msg->ExecMessage.mn_Node.ln_Succ ) {
-
- if( msg->IDCMPWindow == win ) {
-
- /* Intuition is about to free this message.
- * Make sure that we have politely sent it back.
- */
- Remove( (struct Node *)msg );
-
- ReplyMsg( (struct Message *)msg );
- }
-
- msg = (struct IntuiMessage *) succ;
- }
- }
-
- /* Another one for a private MsgPort */
-
- VOID StripMessages( struct MsgPort *mp )
- {
- struct Message *msg;
- struct Node *succ;
-
- msg = (struct Message *) mp->mp_MsgList.lh_Head;
-
- while( succ = msg->mn_Node.ln_Succ ) {
-
- Remove( (struct Node *)msg );
-
- ReplyMsg( msg );
-
- msg = (struct Message *) succ;
- }
- }
-