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 / server / sound.c < prev    next >
Text File  |  1994-11-24  |  11KB  |  380 lines

  1. /* amiga/server/sound.c */
  2.  
  3. /* internal operations for the sound server itself */
  4.  
  5. /* $Id: sound.c,v 1.12 1994/01/08 20:26:45 Espie Rel Espie $
  6.  * $Log: sound.c,v $
  7.  * Revision 1.12  1994/01/08  20:26:45  Espie
  8.  * Added pause gadget.
  9.  *
  10.  * Revision 1.11  1994/01/07  15:12:26  Espie
  11.  * *** empty log message ***
  12.  *
  13.  * Revision 1.10  1994/01/07  01:01:49  Espie
  14.  * Id.
  15.  *
  16.  * Revision 1.9  1994/01/05  16:11:43  Espie
  17.  * Made TYPE_xxxSYNC explicit.
  18.  *
  19.  * Revision 1.8  1994/01/05  14:56:02  Espie
  20.  * *** empty log message ***
  21.  *
  22.  * Revision 1.7  1994/01/05  04:35:23  Espie
  23.  * Found spurious bug: I had to track through the various
  24.  * possibilities of CMD_WRITE to finally realize I was losing my
  25.  * messages... So when the queue was empty, I could not allocate
  26.  * any channel...
  27.  * Needed external program capability back in order though.
  28.  * Problem was coming from data faronly, which is very incompatible
  29.  * with printf.
  30.  *
  31.  * Note that now, we only care about reallocating channels when we're
  32.  * doing a CMD_WRITE. doing it for ADCMD_PERVOL or CMD_FLUSH is pointless
  33.  * since our old data have been completely forgotten in between...
  34.  *
  35.  * Some tests and masking are probably unnecessary. On the other hand, the
  36.  * error code MUST be checked correctly. Maybe I'll try and make the
  37.  * CMD_WRITE part clearer.
  38.  *
  39.  * Revision 1.6  1994/01/05  02:03:14  Espie
  40.  * Mostly correct check for losing audio channels.
  41.  *
  42.  * Revision 1.5  1994/01/04  22:05:35  Espie
  43.  * Cosmetic changes, mostly.
  44.  *
  45.  * Revision 1.4  1994/01/04  20:46:23  Espie
  46.  * Plainly working version with all checks...
  47.  *
  48.  * Revision 1.3  1994/01/04  20:33:20  Espie
  49.  * Mostly working version
  50.  *
  51.  * Revision 1.2  1994/01/04  19:13:21  Espie
  52.  * Corrected most of the audio allocation/free muck-up.
  53.  *
  54.  * Revision 1.1  1994/01/04  15:45:37  Espie
  55.  * Initial revision
  56.  *
  57.  */
  58.  
  59. #include <hardware/cia.h>
  60. #include <hardware/intbits.h>
  61. #include <hardware/dmabits.h>
  62. #include <exec/nodes.h>
  63. #include <exec/memory.h>
  64. #include <devices/audio.h>
  65. #include <proto/exec.h>
  66. #include <stddef.h>
  67.  
  68. #include <stdio.h>
  69.  
  70.  
  71. #include "defs.h"
  72. #include "amiga/amiga.h"
  73. #include "amiga/server/server.h"
  74.  
  75. ID("$Id$")
  76. extern volatile struct CIA __far ciaa;
  77.  
  78. UBYTE saved_filter, current_filter;
  79.  
  80. /* we allow for lots more audio requests than we need */
  81. #define QUEUE_LENGTH 50
  82.  
  83.  
  84. LOCAL struct ext_audio
  85.    {
  86.    struct MinNode node;
  87.    struct IOAudio request;
  88.    }
  89. /* for sending immediate commands */
  90.  *immediate = 0;
  91. /* the specific request that gets used for closing/opening */
  92. struct IOAudio *req = 0;
  93.  
  94. /* the audio queue */
  95. struct MinList queue;
  96.  
  97. /* keep track of progress */
  98. struct MinList pending;
  99.  
  100. LOCAL struct MsgPort *aport = 0;
  101. /* in order to clean up afterwards: */
  102. LOCAL int audio_opened = FALSE;
  103.  
  104. void send_immediate(ULONG command, int mask);
  105. LOCAL void get_requests(void);
  106.  
  107. /* mask for allocation */
  108. LOCAL UBYTE whichchannel[1];
  109. /* mask of owned channels */
  110. LOCAL UBYTE owned;
  111.  
  112. /* allocate_channels(mask): sends a request to the audio.device for
  113.  * the channels described by mask
  114.  */
  115. LOCAL void allocate_channels(UBYTE mask)
  116.    { 
  117.    whichchannel[0] = mask & ~owned;
  118.    req->ioa_Request.io_Command = ADCMD_ALLOCATE;
  119.    req->ioa_Data = whichchannel;
  120.    req->ioa_Length = sizeof(whichchannel);
  121.    req->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  122.    BeginIO(req);
  123.    WaitIO(req);
  124.    if (!req->ioa_Request.io_Error)     /* update owned channels mask */
  125.       {
  126.       owned |= (int)req->ioa_Request.io_Unit;
  127. #ifdef EXTERNAL
  128.       printf("Allocated: %d (%d) = %d\n", (int)mask, (int)req->ioa_Request.io_Unit, (int)owned);
  129.       fflush(stdout);
  130. #endif
  131.       }
  132. #ifdef EXTERNAL
  133.    else
  134.       printf("Failed: %d (%d) = %d\n", req->ioa_Request.io_Error, mask, owned);
  135. #endif
  136.    ciaa.ciapra = (ciaa.ciapra & ~ CIAF_LED) | current_filter;
  137.    }
  138.  
  139. /* free_channels(): give back all channels.
  140.  */ 
  141. LOCAL void free_channels(void)
  142.    {
  143.    if (req->ioa_AllocKey)
  144.       {
  145.       req->ioa_Request.io_Command = ADCMD_FREE;
  146.       req->ioa_Request.io_Unit = owned;
  147.       BeginIO(req);
  148.       WaitIO(req);
  149. #ifdef EXTERNAL
  150.       printf("Freed !\n");
  151.       fflush(stdout);
  152. #endif
  153.       owned = 0;
  154.       }
  155.    }
  156.  
  157. LOCAL struct ext_audio *create_request(void)
  158.    {
  159.    struct ext_audio *new;
  160.          /* CHECK: no test for failed allocation */
  161.    new = AllocMem(sizeof(struct ext_audio), MEMF_CLEAR|MEMF_PUBLIC);
  162.    if (req && new)
  163.       new->request = *req;
  164.    return new;
  165.    }
  166.  
  167. /* actual = create_queue(n): creates a queue of n audio requests,
  168.  *    returns the actual number
  169.  */   
  170. LOCAL int create_queue(int n)
  171.    {
  172.    int i;
  173.    struct ext_audio *new;
  174.  
  175.    for (i = 0; i < n; i++)
  176.       {
  177.       new = create_request();
  178.       if (!new)
  179.          return i;
  180.       AddTail(&queue, new);
  181.       }  
  182.    return i;
  183.    }
  184.  
  185. /* get back available requests */
  186. LOCAL void get_requests(void)
  187.    {
  188.    struct IOAudio *back;
  189.  
  190.    while(back = GetMsg(aport))
  191.       {
  192.       struct ext_audio *full;
  193.       full = (struct ext_audio *)
  194.          (((UBYTE *)back) - offsetof(struct ext_audio, request));
  195.       Remove(full);           /* no longer pending */
  196.       AddTail(&queue, full);  /* ... and available */
  197.       }
  198.    }
  199.  
  200. /* send immediate command.
  201.  * WARNING: only use send_immediate with commands which
  202.  * are GUARANTEED to be synchronous if IOF_QUICK is set
  203.  */
  204. void send_immediate(ULONG command, int mask)
  205.    {
  206.    immediate->request.ioa_Request.io_Command = command;
  207.    immediate->request.ioa_Request.io_Flags = IOF_QUICK;
  208.    immediate->request.ioa_Request.io_Unit = (void *)(mask & owned);
  209.    immediate->request.ioa_AllocKey = req->ioa_AllocKey;
  210.    BeginIO(&immediate->request);
  211.    return;     
  212.    }
  213.  
  214. void reset_audio(void)
  215.    {
  216.    send_immediate(CMD_FLUSH, 15);
  217.    get_requests();
  218.    free_channels();
  219.    }
  220.  
  221. /* obtain_audio(): allocate all the structures we will need to
  222.  * play with the audio device
  223.  */ 
  224. LOCAL void obtain_audio(void)
  225.    {
  226.    BYTE fail;
  227.    
  228.    aport = CreateMsgPort();
  229.    if (!aport)
  230.       return;
  231.    req = CreateIORequest(aport, sizeof(struct IOAudio));
  232.    if (!req)
  233.       return;
  234.    req->ioa_AllocKey = 0;
  235.    req->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  236.       /* Note that OpenDevice returns 0 on success
  237.        */
  238.    fail = OpenDevice("audio.device", 0L, (struct IORequest *)req, 0L);
  239.    if (!fail)
  240.       audio_opened = TRUE;
  241.    }
  242.  
  243. struct MsgPort *start_audio(void)
  244.    {
  245.    NewList(&queue);     /* initialize these now for correct cleanup */
  246.    NewList(&pending);
  247.  
  248.    owned = 0;           /* we own no channel right now */
  249.    obtain_audio();
  250.    if (!audio_opened || create_queue(QUEUE_LENGTH) < QUEUE_LENGTH)
  251.       return 0;
  252.    immediate = RemHead(&queue);
  253.    saved_filter = ciaa.ciapra & CIAF_LED;
  254.    current_filter = CIAF_LED;
  255.    return aport;  
  256.    }  
  257.  
  258. void end_audio()
  259.    {
  260.    struct ext_audio *sweep, *next;
  261.  
  262.    if (immediate)       /* get immediate back in queue for freeing it */
  263.       AddTail(&queue, immediate);
  264.    if (req)
  265.       free_channels();
  266.    get_requests();
  267.       /* REMOVE ALL REQUESTS FROM THE PENDING LIST */
  268.    SCANLIST(sweep, next, &pending, struct ext_audio *)
  269.       {
  270.       AbortIO(&sweep->request);
  271.       WaitIO(&sweep->request);
  272.       }
  273.       /* Now we can close safely */
  274.    if (audio_opened)
  275.       CloseDevice((struct IORequest *)req);
  276.    if (req)
  277.       DeleteIORequest(req);
  278.    if (aport)
  279.       DeletePort(aport);
  280.  
  281.    SCANLIST(sweep, next, &queue, struct ext_audio *)
  282.       FreeMem(sweep, sizeof(struct ext_audio));
  283.    ciaa.ciapra = (ciaa.ciapra & ~CIAF_LED) | saved_filter;
  284.    }
  285.  
  286.  
  287. /* Perform musical events pertaining to the current time */
  288. void do_events(struct List *e)
  289.    {
  290.    struct ext_message *msg, *msg2;
  291.    
  292.    while (msg = RemHead(e))
  293.       {
  294.       switch (msg->type)
  295.          {
  296.       case TYPE_WAIT:         /* next time to wait for: finished */
  297.          AddHead(e, msg);
  298.          return;
  299.       case TYPE_FLUSH_CHANNEL:
  300.          send_immediate(CMD_FLUSH, msg->data.info.channel_mask);
  301.          break;
  302.       case TYPE_SETUP:        /* setup is a two message command */
  303.          msg2 = RemHead(e);
  304.          
  305.          if (msg2)
  306.             {
  307.             struct ext_audio *new;
  308.             
  309.             new = RemHead(&queue);
  310.             if (new)
  311.                {
  312.                new->request.ioa_Request.io_Command = CMD_WRITE;
  313.                if (msg2->data.info.pitch)
  314.                   {
  315.                   new->request.ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK;
  316.                   new->request.ioa_Period = msg2->data.info.pitch;
  317.                   new->request.ioa_Volume = msg2->data.info.volume;
  318.                   }
  319.                else
  320.                   new->request.ioa_Request.io_Flags = IOF_QUICK;
  321.                if ((owned & msg2->data.info.channel_mask) == 0)
  322.                   allocate_channels(msg2->data.info.channel_mask);
  323.                new->request.ioa_Request.io_Unit = msg2->data.info.channel_mask & owned;
  324.                new->request.ioa_Cycles = msg2->data.info.cycle;
  325.                new->request.ioa_Data = msg->data.sample.start;
  326.                new->request.ioa_Length= msg->data.sample.length;
  327.                new->request.ioa_AllocKey = req->ioa_AllocKey;
  328.                if (new->request.ioa_Request.io_Unit)
  329.                   {
  330.                   BeginIO(&new->request);
  331.                   if (new->request.ioa_Request.io_Flags & IOF_QUICK)
  332.                      {
  333.                      AddTail(&queue, new);
  334.                      if (new->request.ioa_Request.io_Error)
  335.                         {
  336.                         owned &=~ msg2->data.info.channel_mask;
  337. #ifdef EXTERNAL
  338.                         printf("Lost: %d (%d) = %d\n", new->request.ioa_Request.io_Error, msg2->data.info.channel_mask, owned);
  339.                         fflush(stdout);
  340. #endif
  341.                         }
  342.                      }
  343.                   else
  344.                      AddTail(&pending, new);
  345.                   }
  346.                else
  347.                   AddTail(&queue, new);
  348.                }
  349. #ifdef EXTERNAL
  350.             else
  351.                printf("No new\n");
  352. #endif
  353.             ReplyMsg(msg2);
  354.             }        
  355.          break;
  356.       case TYPE_CHANGE:
  357.          immediate->request.ioa_Period = msg->data.info.pitch;    
  358.          immediate->request.ioa_Volume = msg->data.info.volume;
  359.          send_immediate(ADCMD_PERVOL, msg->data.info.channel_mask);
  360.          break;
  361.       case TYPE_COMM:
  362.       case TYPE_SYNC:
  363.       case TYPE_SYNC_DO:
  364.          /* nothing to do there */
  365.          break;
  366.       default:
  367.          /* not implemented yet */
  368.          break;
  369.          }
  370.       ReplyMsg(msg);
  371.       get_requests();
  372.       }
  373.    }
  374.  
  375.    
  376. void handle_audio(struct List *l, int signaled)
  377.    {
  378.    get_requests();
  379.    }
  380.