home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / MM1 / SOUNDUTILS / mm1_tracker.lzh / TRACKER4.6 / Amiga / client.c < prev    next >
Text File  |  1994-11-24  |  7KB  |  295 lines

  1. /* amiga/client.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: client.c,v 1.9 1994/06/22 21:54:12 Espie Exp Espie $
  6.  * $Log: client.c,v $
  7.  * Revision 1.7  1994/01/08  19:45:29  Espie
  8.  * Uncentralized event handling using event management functions.
  9.  * Priority lowered.
  10.  * Added check_type call for non-blocking processing.
  11.  * Fully working asynchronous interface.
  12.  */
  13.  
  14. /* client to the audio server */
  15.  
  16.  
  17. #include <exec/types.h>
  18. #include <exec/tasks.h>
  19. #include <exec/memory.h>
  20. #include <exec/ports.h>
  21.  
  22. #include <proto/exec.h>
  23.  
  24. #include <stdio.h>
  25.  
  26. #include "defs.h"
  27. #include "extern.h"
  28. #include "song.h"
  29. #include "amiga/amiga.h"
  30.  
  31. ID("$Id: client.c,v 1.9 1994/06/22 21:54:12 Espie Exp Espie $")
  32. XT unsigned int inhibit_output;
  33.  
  34. LOCAL void init_client(void);
  35. LOCAL void (*INIT)(void) = init_client;
  36.  
  37. #define STACK_SIZE 4000
  38. #define HIPRI 50     /* should be higher than intuition's */
  39. #define SUBNAME "Tracker sound server"
  40.  
  41. LOCAL struct MsgPort *subport = 0;
  42.  
  43. LOCAL struct MsgPort *myport = 0;
  44.  
  45. LOCAL struct ext_message *chunk = 0;
  46.  
  47. LOCAL struct MinList buffer;
  48. LOCAL int live_task = FALSE;
  49. LOCAL int watched_type = TYPE_INVALID; 
  50. LOCAL struct ext_message *watched_message;
  51.  
  52. LOCAL void handle_subtask_events(GENERIC nothing)
  53.    {
  54.    struct ext_message *msg;
  55.    
  56.    while (msg = GetMsg(myport))
  57.       {
  58.       if (msg->type == TYPE_SYNC_DO)
  59.          (msg->data.hook.func)(msg->data.hook.p);
  60.       AddTail(&buffer, msg);
  61.       if (msg->type == watched_type)
  62.          {
  63.          watched_message = msg;
  64.          watched_type = TYPE_INVALID;
  65.          }
  66.       }
  67.    }
  68.  
  69. struct ext_message *obtain_message()
  70.    {
  71.    struct ext_message *msg;
  72.    
  73.    INIT_ONCE;
  74.  
  75.    forever
  76.       {
  77.          /* get messages from port first: best synchronization */
  78.       check_events();
  79.             /* message available ? */
  80.       if (msg = RemHead(&buffer))
  81.          return msg;
  82.       else  /* no-> wait for one */
  83.          await_events();
  84.       }
  85.    }
  86.  
  87.  
  88. void send(struct ext_message *msg, int type)
  89.    {
  90.       /* valid only for messages obtained through obtain_message ! */
  91.    msg->type = type;
  92.    msg->msg.mn_ReplyPort = myport;
  93.    PutMsg(subport, msg);
  94.    }
  95.  
  96.  
  97. struct ext_message *check_type(int type)
  98.    {
  99.    struct ext_message *msg;
  100.  
  101.    watched_type = type;
  102.    check_events();
  103.    if (watched_message)
  104.       {
  105.       msg = watched_message;
  106.       watched_message = 0;
  107.       return msg;
  108.       }
  109.    else
  110.       return 0;
  111.    }
  112.    
  113. /* Note that await_type returns a message for checking purposes.
  114.  * This message is NOT available
  115.  */
  116. struct ext_message *await_type(int type)
  117.    {
  118.    struct ext_message *msg;
  119.  
  120.    forever
  121.       {
  122.       watched_type = type;
  123.       check_events();
  124.       if (watched_message)
  125.          {
  126.          msg = watched_message;
  127.          watched_message = 0;
  128.          return msg;
  129.          }
  130.       await_events();
  131.       }
  132.    }
  133.  
  134. LOCAL void kill_subtask()
  135.    {
  136.    struct ext_message *msg;
  137.       /* tell the subtask to die */
  138.    msg = obtain_message();
  139.    send(msg, TYPE_DIE);
  140.       /* and wait for it to be in a dying state (Wait(0)) */
  141.    msg = await_type(TYPE_DIE);
  142. #ifndef EXTERNAL
  143.       /* then kill it */
  144.    RemTask(msg->data.comm.task);
  145. #endif
  146.    live_task = FALSE;
  147.    }
  148.  
  149.  
  150.  
  151. LOCAL struct Task *newtask = 0;
  152. LOCAL void *stack = 0;
  153.  
  154. /* We build up the task structure by ourselves. That way, we can
  155.  * easily pass a message around by pushing it on the stack
  156.  */
  157. LOCAL void create_subtask()
  158.    {
  159.    ULONG *p;
  160.    struct ext_message *msg;
  161.  
  162. #ifdef EXTERNAL
  163.       /* we just have to find the task */
  164.    struct MsgPort *pubport;
  165.  
  166.    pubport = FindPort(PUBLIC_PORT_NAME);
  167.    if (!pubport)
  168.       end_all("Could not rendez-vous");
  169.       /* it's there: get it in working order */
  170.    msg = obtain_message();
  171.    msg->type = TYPE_COMM;
  172.    msg->msg.mn_ReplyPort = myport;
  173.    PutMsg(pubport, msg);
  174.    msg = await_type(TYPE_COMM);
  175.       /* check it's running correctly */
  176.    if (msg->data.comm.port)
  177.       {
  178.       subport = msg->data.comm.port;
  179.       live_task = TRUE;
  180.       }
  181.    else
  182.       {
  183.       end_all("subtask creation failed");
  184.       }
  185. #else
  186.       /* build the new task from scratch */
  187.    newtask = AllocVec(sizeof(struct Task), MEMF_CLEAR | MEMF_PUBLIC);
  188.    if (!newtask)
  189.       end_all("No task struct");
  190.    stack = AllocVec(STACK_SIZE, MEMF_CLEAR);
  191.    if (!stack)
  192.       end_all("No stack");
  193.    newtask->tc_SPLower = stack;
  194.    newtask->tc_SPUpper = (APTR)((ULONG)(newtask->tc_SPLower) + STACK_SIZE);
  195.    newtask->tc_Node.ln_Type = NT_TASK;
  196.    newtask->tc_Node.ln_Pri = HIPRI;
  197.    newtask->tc_Node.ln_Name = SUBNAME;
  198.  
  199.       /* ready to run: set it up for answering */      
  200.    msg = obtain_message();
  201.    msg->type = TYPE_COMM;
  202.    msg->msg.mn_ReplyPort = myport;
  203.       /* push message on the stack */
  204.    p = newtask->tc_SPUpper;
  205.    *(--p) = (ULONG)msg;
  206.    newtask->tc_SPReg = p;
  207.    
  208.    if (!AddTask(newtask, subtask, 0))
  209.       end_all("No subtask");
  210.       /* Check it started up okay */
  211.    msg = await_type(TYPE_COMM);
  212.    if (msg->data.comm.port)
  213.       {
  214.       subport = msg->data.comm.port;
  215.       live_task = TRUE;
  216.       }
  217.    else
  218.       {
  219.       RemTask(msg->data.comm.task);
  220.       end_all("subtask creation failed");
  221.       }
  222. #endif
  223.    }
  224.  
  225.  
  226. /* right now, messages are statically allocated.
  227.  * It might be a good idea to start with a SMALL
  228.  * fixed number of messages (say 50) and increase
  229.  * the queue on timing faults. A bit tricky, though.
  230.  */
  231. LOCAL void alloc_messages()
  232.    {
  233.    int i;
  234.    
  235.    myport = CreateMsgPort();
  236.    if (!myport)
  237.       end_all("Couldn't open message port");
  238.    install_signal_handler(myport->mp_SigBit, handle_subtask_events, 0);
  239.    chunk = AllocVec(sizeof(struct ext_message) * BUFFER_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
  240.    if (!chunk)
  241.       end_all("Message allocation failed");
  242.    for (i = 0; i < BUFFER_SIZE; i++)
  243.       {
  244.          /* don't forget this ! */
  245.       chunk[i].msg.mn_Node.ln_Type = NT_MESSAGE;
  246.       chunk[i].msg.mn_Length = sizeof(struct ext_message);
  247.       AddTail(&buffer, chunk+i);
  248.       }
  249.    }
  250.  
  251. LOCAL void end_client()
  252.    {
  253.    if (live_task)
  254.       kill_subtask();
  255.       /* note that the subtask is already dead when end_client is called */
  256.    if (chunk)
  257.       FreeVec(chunk);
  258.    if (newtask)
  259.       FreeVec(newtask);
  260.    if (stack)
  261.       FreeVec(stack);
  262.    if (myport)
  263.       {
  264.       remove_signal_handler(myport->mp_SigBit);
  265.       DeleteMsgPort(myport);
  266.       }
  267.    }
  268.       
  269. LOCAL void init_client()
  270.    {
  271.    NewList(&buffer);
  272.    at_end(end_client);
  273.    alloc_messages();    /* note we must call alloc_messages BEFORE create_subtask
  274.                          * since create_subtask depends on obtain_message
  275.                          */
  276.    create_subtask();    /* this hooks kill_subtask, AFTER end_client,
  277.                          * so it will be called BEFORE.
  278.                          */
  279.    }
  280.  
  281. void close_audio(void)
  282.    {
  283.    if (live_task)
  284.       {
  285.       struct ext_message *msg;
  286.  
  287.       msg = obtain_message();
  288.       msg->data.info.channel_mask = 15;
  289.       send(msg, TYPE_FLUSH_CHANNEL);
  290.       while (msg != await_type(TYPE_FLUSH_CHANNEL))
  291.          ;
  292.       }
  293.    }
  294.  
  295.