home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 106 / EnigmaAmiga106CD.iso / software / sviluppo / ahisrc / device / devcommands.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-22  |  43.2 KB  |  1,546 lines

  1. /* $Id: devcommands.c,v 4.18 1999/04/22 19:41:52 lcs Exp $ */
  2.  
  3. /*
  4.      AHI - Hardware independent audio subsystem
  5.      Copyright (C) 1996-1999 Martin Blom <martin@blom.org>
  6.      
  7.      This library is free software; you can redistribute it and/or
  8.      modify it under the terms of the GNU Library General Public
  9.      License as published by the Free Software Foundation; either
  10.      version 2 of the License, or (at your option) any later version.
  11.      
  12.      This library is distributed in the hope that it will be useful,
  13.      but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.      Library General Public License for more details.
  16.      
  17.      You should have received a copy of the GNU Library General Public
  18.      License along with this library; if not, write to the
  19.      Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
  20.      MA 02139, USA.
  21. */
  22.  
  23. //#define DEBUG
  24. //#define DEBUG_R
  25.  
  26. #include <config.h>
  27. #include <CompilerSpecific.h>
  28.  
  29. #include <dos/dos.h>
  30. #include <exec/errors.h>
  31. #include <exec/io.h>
  32. #include <exec/devices.h>
  33. #include <exec/memory.h>
  34. #include <proto/exec.h>
  35. #include <proto/dos.h>
  36. #include <clib/ahi_protos.h>
  37. #include <pragmas/ahi_pragmas.h>
  38. #include <proto/ahi_sub.h>
  39. #include <math.h>
  40.  
  41. #include "ahi_def.h"
  42. #include "misc.h"
  43. #include "devcommands.h"
  44. #include "device.h"
  45. #include "devsupp.h"
  46.  
  47.  
  48. static void TermIO(struct AHIRequest *, struct AHIBase *);
  49. static void Devicequery(struct AHIRequest *, struct AHIBase *);
  50. static void ResetCmd(struct AHIRequest *, struct AHIBase *);
  51. static void ReadCmd(struct AHIRequest *, struct AHIBase *);
  52. static void WriteCmd(struct AHIRequest *, struct AHIBase *);
  53. static void StopCmd(struct AHIRequest *, struct AHIBase *);
  54. static void StartCmd(struct AHIRequest *, struct AHIBase *);
  55. static void FlushCmd(struct AHIRequest *, struct AHIBase *);
  56.  
  57. static void FillReadBuffer(struct AHIRequest *, struct AHIDevUnit *, struct AHIBase *);
  58.  
  59. static void NewWriter(struct AHIRequest *, struct AHIDevUnit *, struct AHIBase *);
  60. static void AddWriter(struct AHIRequest *, struct AHIDevUnit *, struct AHIBase *);
  61. static void PlayRequest(int, struct AHIRequest *, struct AHIDevUnit *, struct AHIBase *);
  62. static void RemPlayers( struct List *, struct AHIDevUnit *, struct AHIBase *);
  63.  
  64.  
  65. /******************************************************************************
  66. ** DevBeginIO *****************************************************************
  67. ******************************************************************************/
  68.  
  69. // This function is called by the system each time exec.library/DoIO()
  70. // is called.
  71.  
  72. void ASMCALL
  73. DevBeginIO ( REG(a1, struct AHIRequest *ioreq),
  74.              REG(a6, struct AHIBase *AHIBase) )
  75. {
  76.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  77.   {
  78.     KPrintF("BeginIO(0x%08lx)\n", ioreq);
  79.   }
  80.  
  81.   ioreq->ahir_Std.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  82.  
  83.   switch(ioreq->ahir_Std.io_Command)
  84.   {
  85.  
  86. // Immediate commands
  87.     case NSCMD_DEVICEQUERY:
  88.     case CMD_STOP:
  89.     case CMD_FLUSH:
  90.       PerformIO(ioreq,AHIBase);
  91.       break;
  92.  
  93. // Queued commands
  94.     case CMD_RESET:
  95.     case CMD_READ:
  96.     case CMD_WRITE:
  97.     case CMD_START:
  98.       ioreq->ahir_Std.io_Flags &= ~IOF_QUICK;
  99.       PutMsg(&ioreq->ahir_Std.io_Unit->unit_MsgPort,&ioreq->ahir_Std.io_Message);
  100.       break;
  101.  
  102. // Unknown commands
  103.     default:
  104.       ioreq->ahir_Std.io_Error = IOERR_NOCMD;
  105.       TermIO(ioreq,AHIBase);
  106.       break;
  107.   }
  108. }
  109.  
  110.  
  111. /******************************************************************************
  112. ** AbortIO ********************************************************************
  113. ******************************************************************************/
  114.  
  115. // This function is called by the system each time exec.library/AbortIO()
  116. // is called.
  117.  
  118. ULONG ASMCALL
  119. DevAbortIO ( REG(a1, struct AHIRequest *ioreq),
  120.              REG(a6, struct AHIBase *AHIBase) )
  121. {
  122.   ULONG rc = NULL;
  123.   struct AHIDevUnit *iounit;
  124.   
  125.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  126.   {
  127.     KPrintF("AbortIO(0x%08lx)", ioreq);
  128.   }
  129.  
  130.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  131.   
  132.   ObtainSemaphore(&iounit->ListLock);
  133.   if(ioreq->ahir_Std.io_Message.mn_Node.ln_Type != NT_REPLYMSG)
  134.   {
  135.     switch(ioreq->ahir_Std.io_Command)
  136.     {
  137.  
  138.       case CMD_READ:
  139.         if(FindNode((struct List *) &iounit->ReadList, (struct Node *) ioreq))
  140.         {
  141.           Remove((struct Node *) ioreq);
  142.           ioreq->ahir_Std.io_Error = IOERR_ABORTED;
  143.           TermIO(ioreq,AHIBase);
  144.         }
  145.         break;
  146.  
  147.       case CMD_WRITE:
  148.       case AHICMD_WRITTEN:
  149.         if(FindNode((struct List *) &iounit->PlayingList, (struct Node *) ioreq)
  150.         || FindNode((struct List *) &iounit->SilentList, (struct Node *) ioreq)
  151.         || FindNode((struct List *) &iounit->WaitingList, (struct Node *) ioreq))
  152.         {
  153.           struct AHIRequest *nextreq;
  154.  
  155.           while(ioreq)
  156.           {
  157.             Remove((struct Node *) ioreq);
  158.  
  159.             if(ioreq->ahir_Extras && (GetExtras(ioreq)->Channel != NOCHANNEL))
  160.             {
  161.               iounit->Voices[GetExtras(ioreq)->Channel].PlayingRequest = NULL;
  162.               iounit->Voices[GetExtras(ioreq)->Channel].QueuedRequest = NULL;
  163.               iounit->Voices[GetExtras(ioreq)->Channel].NextRequest = NULL;
  164.               iounit->Voices[GetExtras(ioreq)->Channel].NextOffset = MUTE;
  165.               if(iounit->AudioCtrl)
  166.               {
  167.                 AHI_SetSound(GetExtras(ioreq)->Channel,AHI_NOSOUND,0,0,
  168.                     iounit->AudioCtrl,AHISF_IMM);
  169.               }
  170.             }
  171.  
  172.             ioreq->ahir_Std.io_Command = CMD_WRITE;
  173.             ioreq->ahir_Std.io_Error   = IOERR_ABORTED;
  174.             nextreq = ioreq->ahir_Link;
  175.             TermIO(ioreq,AHIBase);
  176.             ioreq = nextreq;
  177.           }
  178.         }
  179.  
  180.       default:
  181.         rc = IOERR_NOCMD;
  182.         break;
  183.     }
  184.   }
  185.   ReleaseSemaphore(&iounit->ListLock);
  186.  
  187.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  188.   {
  189.     KPrintF("=>%ld\n",rc);
  190.   }
  191.  
  192.   return rc;
  193. }
  194.  
  195.  
  196. /******************************************************************************
  197. ** TermIO *********************************************************************
  198. ******************************************************************************/
  199.  
  200. // This functions returns an IO request back to the sender.
  201.  
  202. static void
  203. TermIO ( struct AHIRequest *ioreq,
  204.          struct AHIBase *AHIBase )
  205. {
  206.   struct AHIDevUnit *iounit;
  207.   ULONG error = ioreq->ahir_Std.io_Error;
  208.  
  209.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  210.  
  211.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  212.   {
  213.     KPrintF("Terminating IO Request 0x%08lx", ioreq);
  214.   }
  215.  
  216.   if(ioreq->ahir_Extras != NULL)
  217.   {
  218.     int sound = GetExtras(ioreq)->Sound;
  219.  
  220.     if((sound != AHI_NOSOUND) && (sound < MAXSOUNDS))
  221.     {
  222.       AHI_UnloadSound(sound, iounit->AudioCtrl);
  223.       iounit->Sounds[sound] = SOUND_FREE;
  224.     }
  225.     FreeVec((APTR *)ioreq->ahir_Extras);
  226.     ioreq->ahir_Extras = NULL;
  227.   }
  228.  
  229.   if( ! (ioreq->ahir_Std.io_Flags & IOF_QUICK))
  230.   {
  231.       ReplyMsg(&ioreq->ahir_Std.io_Message);
  232.   }
  233.  
  234.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  235.   {
  236.     KPrintF("=>%ld\n", error);
  237.   }
  238. }
  239.  
  240.  
  241. /******************************************************************************
  242. ** PerformIO ******************************************************************
  243. ******************************************************************************/
  244.  
  245. void
  246. PerformIO ( struct AHIRequest *ioreq,
  247.             struct AHIBase *AHIBase )
  248. {
  249.   struct AHIDevUnit *iounit;
  250.  
  251.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  252.   ioreq->ahir_Std.io_Error = 0;
  253.  
  254.   // Just to make sure TermIO won't free a bad address
  255.   ioreq->ahir_Extras = NULL;
  256.  
  257.   switch(ioreq->ahir_Std.io_Command)
  258.   {
  259.     case NSCMD_DEVICEQUERY:
  260.       Devicequery(ioreq, AHIBase);
  261.       break;
  262.     case CMD_RESET:
  263.       ResetCmd(ioreq, AHIBase);
  264.       break;
  265.     case CMD_READ:
  266.       ReadCmd(ioreq, AHIBase);
  267.       break;
  268.     case CMD_WRITE:
  269.       if(iounit->StopCnt)
  270.       {
  271.         AddTail((struct List *) &iounit->RequestQueue,(struct Node *) ioreq);
  272.       }
  273.       else
  274.       {
  275.         WriteCmd(ioreq, AHIBase);
  276.       }
  277.       break;
  278.     case CMD_STOP:
  279.       StopCmd(ioreq, AHIBase);
  280.       break;
  281.     case CMD_START:
  282.       StartCmd(ioreq, AHIBase);
  283.       break;
  284.     case CMD_FLUSH:
  285.       FlushCmd(ioreq, AHIBase);
  286.       break;
  287.     default:
  288.       ioreq->ahir_Std.io_Error = IOERR_NOCMD;
  289.       TermIO(ioreq, AHIBase);
  290.       break;
  291.   }
  292. }
  293.  
  294.  
  295. /******************************************************************************
  296. ** Devicequery ****************************************************************
  297. ******************************************************************************/
  298.  
  299. /****** ahi.device/NSCMD_DEVICEQUERY  ***************************************
  300. *
  301. *   NAME
  302. *       NSCMD_DEVICEQUERY -- Query the device for its capabilities (V4)
  303. *
  304. *   FUNCTION
  305. *       Fills an initialized NSDeviceQueryResult structure with
  306. *       information about the device.
  307. *
  308. *   IO REQUEST INPUT
  309. *       io_Device       Preset by the call to OpenDevice().
  310. *       io_Unit         Preset by the call to OpenDevice().
  311. *       io_Command      NSCMD_DEVICEQUERY
  312. *       io_Data         Pointer to the NSDeviceQueryResult structure,
  313. *                       initialized as follows:
  314. *                           DevQueryFormat - Set to 0
  315. *                           SizeAvailable  - Must be cleared.
  316. *                       It is probably good manners to clear all other
  317. *                       fields as well.
  318. *       io_Length       Size of the NSDeviceQueryResult structure.
  319. *
  320. *   IO REQUEST RESULT
  321. *       io_Error        0 for success, or an error code as defined in
  322. *                       <ahi/devices.h> and <exec/errors.h>.
  323. *       io_Actual       If io_Error is 0, the value in
  324. *                       NSDeviceQueryResult.SizeAvailable.
  325. *
  326. *       The NSDeviceQueryResult structure now contains valid information.
  327. *
  328. *       The other fields, except io_Device, io_Unit and io_Command, are
  329. *       trashed.
  330. *
  331. *   EXAMPLE
  332. *
  333. *   NOTES
  334. *
  335. *   BUGS
  336. *
  337. *   SEE ALSO
  338. *       <ahi/devices.h>, <exec/errors.h>
  339. *
  340. ****************************************************************************
  341. *
  342. */
  343.  
  344. static UWORD
  345. commandlist[] =
  346. {
  347.   NSCMD_DEVICEQUERY,
  348.   CMD_RESET,
  349.   CMD_READ,
  350.   CMD_WRITE,
  351.   CMD_STOP,
  352.   CMD_START,
  353.   CMD_FLUSH,
  354.   NULL
  355. };
  356.  
  357. static void
  358. Devicequery ( struct AHIRequest *ioreq,
  359.               struct AHIBase *AHIBase )
  360. {
  361.   struct NSDeviceQueryResult *dqr;
  362.  
  363.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  364.   {
  365.     KPrintF("NSCMD_DEVICEQUERY\n");
  366.   }
  367.  
  368.   dqr = ioreq->ahir_Std.io_Data;
  369.   if(ioreq->ahir_Std.io_Length >= 16)
  370.   {
  371.     dqr->SizeAvailable = 16;
  372.     dqr->DeviceType = NSDEVTYPE_UNKNOWN;
  373.     dqr->DeviceSubType = 0;
  374.     dqr->SupportedCommands = commandlist;
  375.   }
  376.  
  377.   ioreq->ahir_Std.io_Actual = dqr->SizeAvailable;
  378.   TermIO(ioreq, AHIBase);
  379. }
  380.  
  381.  
  382. /******************************************************************************
  383. ** StopCmd ********************************************************************
  384. ******************************************************************************/
  385.  
  386. /****** ahi.device/CMD_STOP ************************************************
  387. *
  388. *   NAME
  389. *       CMD_STOP -- stop device processing (like ^S) (V4)
  390. *
  391. *   FUNCTION
  392. *       Stops all CMD_WRITE processing. All writes will be queued, and
  393. *       are not processed until CMD_START. This is useful for synchronizing
  394. *       two or more CMD_WRITE's.
  395. *
  396. *   IO REQUEST INPUT
  397. *       io_Device       Preset by the call to OpenDevice().
  398. *       io_Unit         Preset by the call to OpenDevice().
  399. *       io_Command      CMD_STOP
  400. *
  401. *   IO REQUEST RESULT
  402. *       io_Error        0 for success, or an error code as defined in
  403. *                       <ahi/devices.h> and <exec/errors.h>.
  404. *       io_Actual       If io_Error is 0, number of requests actually
  405. *                       flushed.
  406. *
  407. *       The other fields, except io_Device, io_Unit and io_Command, are
  408. *       trashed.
  409. *
  410. *   EXAMPLE
  411. *
  412. *   NOTES
  413. *       This command affects ALL writes, even those sent by other
  414. *       applications. Make sure the code between CMD_STOP and CMD_START
  415. *       runs as fast as possible!
  416. *
  417. *       Unlike most (all?) other devices, CMD_STOP and CMD_START do nest in
  418. *       ahi.device.
  419. *
  420. *   BUGS
  421. *
  422. *   SEE ALSO
  423. *       CMD_START, <ahi/devices.h>, <exec/errors.h>
  424. *
  425. ****************************************************************************
  426. *
  427. */
  428.  
  429. static void
  430. StopCmd ( struct AHIRequest *ioreq, 
  431.           struct AHIBase *AHIBase )
  432. {
  433.   struct AHIDevUnit *iounit;
  434.  
  435.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  436.  
  437.   iounit->StopCnt++;
  438.   TermIO(ioreq,AHIBase);
  439. }
  440.  
  441.  
  442. /******************************************************************************
  443. ** FlushCmd *******************************************************************
  444. ******************************************************************************/
  445.  
  446. /****** ahi.device/CMD_FLUSH ************************************************
  447. *
  448. *   NAME
  449. *       CMD_FLUSH -- Cancel all I/O requests (V4)
  450. *
  451. *   FUNCTION
  452. *       Aborts ALL current requests, both active and waiting, even
  453. *       other programs requests!
  454. *
  455. *   IO REQUEST INPUT
  456. *       io_Device       Preset by the call to OpenDevice().
  457. *       io_Unit         Preset by the call to OpenDevice().
  458. *       io_Command      CMD_FLUSH
  459. *
  460. *   IO REQUEST RESULT
  461. *       io_Error        0 for success, or an error code as defined in
  462. *                       <ahi/devices.h> and <exec/errors.h>.
  463. *       io_Actual       If io_Error is 0, number of requests actually
  464. *                       flushed.
  465. *
  466. *       The other fields, except io_Device, io_Unit and io_Command, are
  467. *       trashed.
  468. *
  469. *   EXAMPLE
  470. *
  471. *   NOTES
  472. *       This command should only be used in very rare cases, like AHI
  473. *       system utilities. Never use this command in an application.
  474. *
  475. *   BUGS
  476. *
  477. *   SEE ALSO
  478. *       CMD_RESET, <ahi/devices.h>, <exec/errors.h>
  479. *
  480. ****************************************************************************
  481. *
  482. */
  483.  
  484. static void
  485. FlushCmd ( struct AHIRequest *ioreq,
  486.            struct AHIBase *AHIBase )
  487. {
  488.   struct AHIDevUnit *iounit;
  489.   struct AHIRequest *ior;
  490.  
  491.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  492.  
  493.   ioreq->ahir_Std.io_Actual = 0;
  494.  
  495.   // Abort all current IO-requests
  496.   while((ior = (struct AHIRequest *) iounit->ReadList.mlh_Head))
  497.   {
  498.     DevAbortIO(ior, AHIBase);
  499.     ioreq->ahir_Std.io_Actual++;
  500.   }
  501.   while((ior = (struct AHIRequest *) iounit->PlayingList.mlh_Head))
  502.   {
  503.     DevAbortIO(ior, AHIBase);
  504.     ioreq->ahir_Std.io_Actual++;
  505.   }
  506.   while((ior = (struct AHIRequest *) iounit->SilentList.mlh_Head))
  507.   {
  508.     DevAbortIO(ior, AHIBase);
  509.     ioreq->ahir_Std.io_Actual++;
  510.   }
  511.   while((ior = (struct AHIRequest *) iounit->WaitingList.mlh_Head))
  512.   {
  513.     DevAbortIO(ior, AHIBase);
  514.     ioreq->ahir_Std.io_Actual++;
  515.   }
  516.   TermIO(ioreq,AHIBase);
  517. }
  518.  
  519.  
  520.  
  521. /* All the following functions are called within the unit process context */
  522.  
  523.  
  524. /******************************************************************************
  525. ** ResetCmd *******************************************************************
  526. ******************************************************************************/
  527.  
  528. /****** ahi.device/CMD_RESET ************************************************
  529. *
  530. *   NAME
  531. *       CMD_RESET -- Restore device to a known state (V4)
  532. *
  533. *   FUNCTION
  534. *       Aborts all current requests, even other programs requests
  535. *       (CMD_FLUSH), rereads the configuration file and resets the hardware
  536. *       to its initial state
  537. *       
  538. *
  539. *   IO REQUEST INPUT
  540. *       io_Device       Preset by the call to OpenDevice().
  541. *       io_Unit         Preset by the call to OpenDevice().
  542. *       io_Command      CMD_RESET
  543. *
  544. *   IO REQUEST RESULT
  545. *       io_Error        0 for success, or an error code as defined in
  546. *                       <ahi/devices.h> and <exec/errors.h>.
  547. *
  548. *       The other fields, except io_Device, io_Unit and io_Command, are
  549. *       trashed.
  550. *
  551. *   EXAMPLE
  552. *
  553. *   NOTES
  554. *       This command should only be used in very rare cases, like AHI
  555. *       system utilities. Never use this command in an application.
  556. *
  557. *   BUGS
  558. *
  559. *   SEE ALSO
  560. *       CMD_FLUSH, <ahi/devices.h>, <exec/errors.h>
  561. *
  562. ****************************************************************************
  563. *
  564. */
  565.  
  566. static void
  567. ResetCmd ( struct AHIRequest *ioreq,
  568.            struct AHIBase *AHIBase )
  569. {
  570.   struct AHIDevUnit *iounit;
  571.  
  572.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  573.  
  574.   // Remove all requests (beware, invalid IORequest to FlushCmd!)
  575.   FlushCmd(ioreq, AHIBase);
  576.  
  577.   // Reset the hardware
  578.   ReadConfig(iounit, AHIBase);
  579.   FreeHardware(iounit, AHIBase);
  580.   AllocHardware(iounit, AHIBase);
  581.   TermIO(ioreq,AHIBase);
  582. }
  583.  
  584.  
  585. /******************************************************************************
  586. ** ReadCmd ********************************************************************
  587. ******************************************************************************/
  588.  
  589. /****** ahi.device/CMD_READ *************************************************
  590. *
  591. *   NAME
  592. *       CMD_READ -- Read raw samples from audio input (V4)
  593. *
  594. *   FUNCTION
  595. *       Reads samples from the users prefered input to memory. The sample
  596. *       format and frequency will be converted on the fly. 
  597. *
  598. *   IO REQUEST INPUT
  599. *       io_Device       Preset by the call to OpenDevice().
  600. *       io_Unit         Preset by the call to OpenDevice().
  601. *       io_Command      CMD_READ
  602. *       io_Data         Pointer to the buffer where the data should be put.
  603. *       io_Length       Number of bytes to read, must be a multiple of the
  604. *                       sample frame size (see ahir_Type).
  605. *       io_Offset       Set to 0 when you use for the first time or after
  606. *                       a delay.
  607. *       ahir_Type       The desired sample format, see <ahi/devices.h>.
  608. *       ahir_Frequency  The desired sample frequency in Hertz.
  609. *
  610. *   IO REQUEST RESULT
  611. *       io_Error        0 for success, or an error code as defined in
  612. *                       <ahi/devices.h> and <exec/errors.h>.
  613. *       io_Actual       If io_Error is 0, number of bytes actually
  614. *                       transferred.
  615. *       io_Offset       Updated to be used as input next time.
  616. *
  617. *       The other fields, except io_Device, io_Unit and io_Command, are
  618. *       trashed.
  619. *
  620. *   EXAMPLE
  621. *
  622. *   NOTES
  623. *
  624. *   BUGS
  625. *
  626. *   SEE ALSO
  627. *       <ahi/devices.h>, <exec/errors.h>
  628. *
  629. ****************************************************************************
  630. *
  631. */
  632.  
  633. static void 
  634. ReadCmd ( struct AHIRequest *ioreq,
  635.           struct AHIBase *AHIBase )
  636. {
  637.   struct AHIDevUnit *iounit;
  638.   ULONG error,mixfreq = 0;
  639.  
  640.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  641.   {
  642.     KPrintF("CMD_READ\n");
  643.   }
  644.  
  645.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  646.  
  647.   /* Start recording if neccessary */
  648.   if( ! iounit->IsRecording)
  649.   {
  650.     if( (! iounit->FullDuplex) && iounit->IsPlaying)
  651.     {
  652.       error = AHIE_HALFDUPLEX;   // FIXIT!
  653.     }
  654.     else
  655.     {
  656.       error = AHI_ControlAudio(iounit->AudioCtrl,
  657.          AHIC_Record,TRUE,
  658.          TAG_DONE);
  659.     }
  660.  
  661.     if( ! error)
  662.     {
  663.       iounit->IsRecording = TRUE;
  664.     }
  665.   }
  666.  
  667.   if(iounit->IsRecording)
  668.   {
  669.     AHI_ControlAudio(iounit->AudioCtrl,
  670.         AHIC_MixFreq_Query, (ULONG) &mixfreq,
  671.         TAG_DONE);
  672.  
  673.     ioreq->ahir_Std.io_Actual = 0;
  674.  
  675.     /* Initialize ahir_Frequency for the assembler record routines */
  676.     if(ioreq->ahir_Frequency && mixfreq)
  677.       ioreq->ahir_Frequency = ((mixfreq << 15) / ioreq->ahir_Frequency) << 1;
  678.     else
  679.       ioreq->ahir_Frequency = 0x00010000;       // Fixed 1.0
  680.  
  681.     ObtainSemaphore(&iounit->ListLock);
  682.  
  683.     /* Add the request to the list of readers */
  684.     AddTail((struct List *) &iounit->ReadList,(struct Node *) ioreq);
  685.  
  686.     /* Copy the current buffer contents */
  687. #ifdef DEBUG_R
  688.     KPrintF("Copy old!\n");
  689. #endif
  690.     FillReadBuffer(ioreq, iounit, AHIBase);
  691.  
  692.     ReleaseSemaphore(&iounit->ListLock);
  693.   }
  694.   else
  695.   {
  696.     ioreq->ahir_Std.io_Error = error;
  697.     TermIO(ioreq, AHIBase);
  698.   }
  699. }
  700.  
  701.  
  702. /******************************************************************************
  703. ** WriteCmd *******************************************************************
  704. ******************************************************************************/
  705.  
  706. /****** ahi.device/CMD_WRITE ************************************************
  707. *
  708. *   NAME
  709. *       CMD_WRITE -- Write raw samples to audio output (V4)
  710. *
  711. *   FUNCTION
  712. *       Plays the samples to the users prefered audio output.
  713. *
  714. *   IO REQUEST INPUT
  715. *       io_Device       Preset by the call to OpenDevice().
  716. *       io_Unit         Preset by the call to OpenDevice().
  717. *       io_Command      CMD_WRITE
  718. *       io_Data         Pointer to the buffer of samples to be played.
  719. *       io_Length       Number of bytes to play, must be a multiple of the
  720. *                       sample frame size (see ahir_Type).
  721. *       io_Offset       Must be 0.
  722. *       ahir_Type       The desired sample format, see <ahi/devices.h>.
  723. *       ahir_Frequency  The desired sample frequency in Hertz.
  724. *       ahir_Volume     The desired volume. The range is 0 to 0x10000, where
  725. *                       0 means muted and 0x10000 (== 1.0) means full volume.
  726. *       ahir_Position   Defines the stereo balance. 0 is far left, 0x8000 is
  727. *                       center and 0x10000 is far right.
  728. *       ahir_Link       If non-zero, pointer to a previously sent AHIRequest
  729. *                       which this AHIRequest will be linked to. This
  730. *                       request will be delayed until the old one is
  731. *                       finished (used for double buffering). Must be set
  732. *                       to NULL if not used.
  733. *
  734. *   IO REQUEST RESULT
  735. *       io_Error        0 for success, or an error code as defined in
  736. *                       <ahi/devices.h> and <exec/errors.h>.
  737. *       io_Actual       If io_Error is 0, number of bytes actually
  738. *                       played.
  739. *
  740. *       The other fields, except io_Device, io_Unit and io_Command, are
  741. *       trashed.
  742. *
  743. *   EXAMPLE
  744. *
  745. *   NOTES
  746. *
  747. *   BUGS
  748. *       32 bit samples are not allowed yet.
  749. *
  750. *   SEE ALSO
  751. *       <ahi/devices.h>, <exec/errors.h>
  752. *
  753. ****************************************************************************
  754. *
  755. */
  756.  
  757. static void
  758. WriteCmd ( struct AHIRequest *ioreq,
  759.            struct AHIBase *AHIBase )
  760. {
  761.   struct AHIDevUnit *iounit;
  762.   ULONG error = 0;
  763.  
  764.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  765.   {
  766.     KPrintF("CMD_WRITE\n");
  767.   }
  768.  
  769.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  770.  
  771.   /* Start playback if neccessary */
  772.   if( ! iounit->IsPlaying)
  773.   {
  774.     if( (! iounit->FullDuplex) && iounit->IsRecording)
  775.     {
  776.       error = AHIE_HALFDUPLEX;   // FIXIT!
  777.     }
  778.     else
  779.     {
  780.       error = AHI_ControlAudio(iounit->AudioCtrl,
  781.          AHIC_Play,TRUE,
  782.          TAG_DONE);
  783.     }
  784.  
  785.     if( ! error)
  786.     {
  787.       iounit->IsPlaying = TRUE;
  788.     }
  789.   }
  790.  
  791.   ioreq->ahir_Extras = (ULONG) AllocVec(sizeof(struct Extras), MEMF_PUBLIC|MEMF_CLEAR);
  792.  
  793.   if(ioreq->ahir_Extras == NULL)
  794.   {
  795.     error = AHIE_NOMEM;
  796.   }
  797.   else
  798.   {
  799.     // Initialize the structure
  800.     GetExtras(ioreq)->Channel = NOCHANNEL;
  801.     GetExtras(ioreq)->Sound   = AHI_NOSOUND;
  802.     GetExtras(ioreq)->Count   = 2;
  803.   }
  804.  
  805.   if(iounit->IsPlaying && !error)
  806.   {
  807.     ioreq->ahir_Std.io_Actual = 0;
  808.  
  809.     // Convert length in bytes to length in samples
  810.  
  811.     ioreq->ahir_Std.io_Length /= AHI_SampleFrameSize(ioreq->ahir_Type);
  812.  
  813.     switch(ioreq->ahir_Type)
  814.     {
  815.       case AHIST_M8S:
  816.       case AHIST_S8S:
  817.       case AHIST_M16S:
  818.       case AHIST_S16S:
  819.         break;
  820.       case AHIST_M32S:
  821.       case AHIST_S32S:
  822.       default:
  823.         error = AHIE_BADSAMPLETYPE;
  824.     }
  825.  
  826.     if(! error)
  827.     {
  828.       NewWriter(ioreq, iounit, AHIBase);
  829.     }
  830.   }
  831.  
  832.   if(error)
  833.   {
  834.     ioreq->ahir_Std.io_Error = error;
  835.     TermIO(ioreq, AHIBase);
  836.   }
  837. }
  838.  
  839.  
  840. /******************************************************************************
  841. ** StartCmd *******************************************************************
  842. ******************************************************************************/
  843.  
  844. /****** ahi.device/CMD_START ************************************************
  845. *
  846. *   NAME
  847. *       CMD_START -- start device processing (like ^Q) (V4)
  848. *
  849. *   FUNCTION
  850. *       All CMD_WRITE's that has been sent to the device since CMD_STOP
  851. *       will be started at once, synchronized.
  852. *
  853. *   IO REQUEST INPUT
  854. *       io_Device       Preset by the call to OpenDevice().
  855. *       io_Unit         Preset by the call to OpenDevice().
  856. *       io_Command      CMD_START
  857. *
  858. *   IO REQUEST RESULT
  859. *       io_Error        0 for success, or an error code as defined in
  860. *                       <ahi/devices.h> and <exec/errors.h>.
  861. *       io_Actual       If io_Error is 0, number of requests actually
  862. *                       flushed.
  863. *
  864. *       The other fields, except io_Device, io_Unit and io_Command, are
  865. *       trashed.
  866. *
  867. *   EXAMPLE
  868. *
  869. *   NOTES
  870. *       Unlike most (all?) other devices, CMD_STOP and CMD_START do nest in
  871. *       ahi.device.
  872. *
  873. *   BUGS
  874. *
  875. *   SEE ALSO
  876. *       CMD_STOP, <ahi/devices.h>, <exec/errors.h>
  877. *
  878. ****************************************************************************
  879. *
  880. */
  881.  
  882. static void
  883. StartCmd ( struct AHIRequest *ioreq,
  884.            struct AHIBase *AHIBase )
  885. {
  886.   struct AHIDevUnit *iounit;
  887.   struct AHIPrivAudioCtrl *audioctrl;
  888.   struct Library *AHIsubBase;
  889.  
  890.   iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  891.   audioctrl = (struct AHIPrivAudioCtrl *) iounit->AudioCtrl;
  892.  
  893.   if(iounit->StopCnt)
  894.   {
  895.     iounit->StopCnt--;
  896.     if((AHIsubBase = audioctrl->ahiac_SubLib))
  897.     {
  898.       if(iounit->StopCnt == 0)
  899.       {
  900.         struct AHIRequest *ior;
  901.  
  902. // FIXIT! Cannot disable, since PlayRequest() doesn't exit until the sound
  903. // is actually started. Sigh. I hate this mess.
  904.  
  905. //        AHIsub_Disable((struct AHIAudioCtrlDrv *) audioctrl);
  906.  
  907.         while((ior = (struct AHIRequest *) RemHead(
  908.             (struct List *) &iounit->RequestQueue)))
  909.         {
  910.           WriteCmd(ior, AHIBase);
  911.         }
  912.  
  913. //        AHIsub_Enable((struct AHIAudioCtrlDrv *) audioctrl);
  914.       }
  915.     }
  916.   }
  917.   else
  918.   {
  919.     ioreq->ahir_Std.io_Error = AHIE_UNKNOWN;
  920.   }
  921.   TermIO(ioreq,AHIBase);
  922.  
  923. }
  924.  
  925.  
  926. /******************************************************************************
  927. ** FeedReaders ****************************************************************
  928. ******************************************************************************/
  929.  
  930. // This function is called by DevProc or ReadCmd to scan the list of waiting
  931. // readers, and fill their buffers. When a buffer is full, the IORequest is
  932. // terminated.
  933.  
  934. void
  935. FeedReaders ( struct AHIDevUnit *iounit,
  936.               struct AHIBase *AHIBase )
  937. {
  938.   struct AHIRequest *ioreq;
  939.  
  940. #ifdef DEBUG_R
  941.   KPrintF("FillReaders\n");
  942. #endif
  943.  
  944.   ObtainSemaphore(&iounit->ListLock);
  945.   for(ioreq = (struct AHIRequest *)iounit->ReadList.mlh_Head;
  946.       ioreq->ahir_Std.io_Message.mn_Node.ln_Succ;
  947.       ioreq = (struct AHIRequest *)ioreq->ahir_Std.io_Message.mn_Node.ln_Succ)
  948.   {
  949.     FillReadBuffer(ioreq, iounit, AHIBase);
  950.   }
  951.  
  952.   // Check if Reader-list is empty. If so, stop recording (after a small delay).
  953.  
  954.   if( ! iounit->ReadList.mlh_Head->mln_Succ )
  955.   {
  956. #ifdef DEBUG_R
  957.     KPrintF("Empty list\n");
  958. #endif
  959.     if(--iounit->RecordOffDelay == 0)
  960.     {
  961. #ifdef DEBUG_R
  962.       KPrintF("Removing\n");
  963. #endif
  964.       AHI_ControlAudio(iounit->AudioCtrl,
  965.           AHIC_Record,FALSE,
  966.           TAG_DONE);
  967.       iounit->IsRecording = FALSE;
  968.     }
  969.   }
  970.   else
  971.   {
  972.     iounit->RecordOffDelay = 2;
  973.   }
  974.  
  975.   ReleaseSemaphore(&iounit->ListLock);
  976. }
  977.  
  978.  
  979. /******************************************************************************
  980. ** FillReadBuffer *************************************************************
  981. ******************************************************************************/
  982.  
  983. // Handles a read request. Note that the request MUST be in a list, and the
  984. // list must be semaphore locked!
  985.  
  986. static void 
  987. FillReadBuffer ( struct AHIRequest *ioreq,
  988.                  struct AHIDevUnit *iounit,
  989.                  struct AHIBase *AHIBase )
  990. {
  991.   ULONG length,length2;
  992.   APTR  oldaddress;
  993.   BOOL  remove;
  994.  
  995. #ifdef DEBUG_R
  996.   KPrintF("FillReadBuffer\n");
  997. #endif
  998.   if(iounit->ValidRecord) // Make sure we have a valid source buffer
  999.   {
  1000.     oldaddress = ioreq->ahir_Std.io_Data;
  1001.  
  1002.     length = (ioreq->ahir_Std.io_Length - ioreq->ahir_Std.io_Actual)
  1003.              / AHI_SampleFrameSize(ioreq->ahir_Type);
  1004.  
  1005.     length2 = (iounit->RecordSize - ioreq->ahir_Std.io_Offset)
  1006.               / AHI_SampleFrameSize(AHIST_S16S);
  1007. #ifdef DEBUG_R
  1008.     KPrintF("Samples left in buffer: %ld\n", length2);
  1009. #endif
  1010.     length2 = MultFixed(length2, (Fixed) ioreq->ahir_Frequency);
  1011.  
  1012. #ifdef DEBUG_R
  1013.     KPrintF("Left to store: %ld  Left to read: %ld\n",length, length2);
  1014. #endif
  1015.  
  1016.  
  1017.     if(length <= length2)
  1018.     {
  1019.       remove=TRUE;
  1020.     }
  1021.     else
  1022.     {
  1023.       length = length2;
  1024.       remove = FALSE;
  1025.     }
  1026.  
  1027. #ifdef DEBUG_R
  1028.     KPrintF("Copying %ld bytes from 0x%08lx + 0x%08lx to 0x%08lx, add 0x%08lx\n",
  1029.       length, iounit->RecordBuffer, ioreq->ahir_Std.io_Offset,
  1030.       ioreq->ahir_Std.io_Data, ioreq->ahir_Frequency);
  1031. #endif
  1032.  
  1033.     switch (ioreq->ahir_Type)
  1034.     {
  1035.       case AHIST_M8S:
  1036.         RecM8S(length,ioreq->ahir_Frequency,
  1037.             iounit->RecordBuffer,
  1038.             &ioreq->ahir_Std.io_Offset,
  1039.             &ioreq->ahir_Std.io_Data);
  1040.         break;
  1041.       case AHIST_S8S:
  1042.         RecS8S(length,ioreq->ahir_Frequency,
  1043.             iounit->RecordBuffer,
  1044.             &ioreq->ahir_Std.io_Offset,
  1045.             &ioreq->ahir_Std.io_Data);
  1046.         break;
  1047.       case AHIST_M16S:
  1048.         RecM16S(length,ioreq->ahir_Frequency,
  1049.             iounit->RecordBuffer,
  1050.             &ioreq->ahir_Std.io_Offset,
  1051.             &ioreq->ahir_Std.io_Data);
  1052.         break;
  1053.       case AHIST_S16S:
  1054.         RecS16S(length,ioreq->ahir_Frequency,
  1055.             iounit->RecordBuffer,
  1056.             &ioreq->ahir_Std.io_Offset,
  1057.             &ioreq->ahir_Std.io_Data);
  1058.         break;
  1059.       case AHIST_M32S:
  1060.         RecM32S(length,ioreq->ahir_Frequency,
  1061.             iounit->RecordBuffer,
  1062.             &ioreq->ahir_Std.io_Offset,
  1063.             &ioreq->ahir_Std.io_Data);
  1064.         break;
  1065.       case AHIST_S32S:
  1066.         RecS32S(length,ioreq->ahir_Frequency,
  1067.             iounit->RecordBuffer,
  1068.             &ioreq->ahir_Std.io_Offset,
  1069.             &ioreq->ahir_Std.io_Data);
  1070.         break;
  1071.       default:
  1072.         ioreq->ahir_Std.io_Error = AHIE_BADSAMPLETYPE;
  1073.         remove = TRUE;
  1074.         break;
  1075.     }
  1076.     
  1077.     ioreq->ahir_Std.io_Actual += ((ULONG) ioreq->ahir_Std.io_Data - (ULONG) oldaddress);
  1078.  
  1079.     if(remove)
  1080.     {
  1081.       Remove((struct Node *) ioreq);
  1082.       TermIO(ioreq, AHIBase);
  1083. #ifdef DEBUG_R
  1084.       KPrintF("Finished.\n");
  1085. #endif
  1086.     }
  1087.     else
  1088.     {
  1089.       ioreq->ahir_Std.io_Offset = 0;
  1090.     }
  1091.   }
  1092.   else
  1093.   {
  1094.     ioreq->ahir_Std.io_Offset = 0;
  1095.   }
  1096. }
  1097.  
  1098.  
  1099. /******************************************************************************
  1100. ** NewWriter ******************************************************************
  1101. ******************************************************************************/
  1102.  
  1103. // This function is called by WriteCmd when a new write request comes.
  1104.  
  1105. static void
  1106. NewWriter ( struct AHIRequest *ioreq,
  1107.             struct AHIDevUnit *iounit,
  1108.             struct AHIBase *AHIBase )
  1109. {
  1110.   int channel, sound;
  1111.   BOOL delay = FALSE;
  1112.   struct AHISampleInfo si;
  1113.   struct Library *AHIsubBase;
  1114.  
  1115. #ifdef DEBUG
  1116.   KPrintF("New writer (0x%08lx)\n", ioreq);
  1117. #endif
  1118.  
  1119.   AHIsubBase = ((struct AHIPrivAudioCtrl *) iounit->AudioCtrl)->ahiac_SubLib;
  1120.  
  1121.   si.ahisi_Type    = ioreq->ahir_Type;
  1122.   si.ahisi_Address = ioreq->ahir_Std.io_Data;
  1123.   si.ahisi_Length  = ioreq->ahir_Std.io_Length;
  1124.  
  1125.   // Load the sound
  1126.   
  1127.   for(sound = 0; sound < MAXSOUNDS; sound++)
  1128.   {
  1129.     if(iounit->Sounds[sound] == SOUND_FREE)
  1130.     {
  1131.       iounit->Sounds[sound] = SOUND_IN_USE;
  1132.       break;
  1133.     }
  1134.   }
  1135.  
  1136.   if((sound < MAXSOUNDS) &&
  1137.      (AHI_LoadSound(sound, AHIST_DYNAMICSAMPLE, &si, iounit->AudioCtrl)
  1138.       == AHIE_OK)) {
  1139.  
  1140.     GetExtras(ioreq)->Sound = sound;
  1141.  
  1142.     ObtainSemaphore(&iounit->ListLock);
  1143.   
  1144.     if(ioreq->ahir_Link)
  1145.     {
  1146.   
  1147. #ifdef DEBUG
  1148.       KPrintF("Linked (0x%08lx)\n",ioreq);
  1149. #endif
  1150.   
  1151.       // See if the linked request is playing, silent or waiting...
  1152.   
  1153.       if(FindNode((struct List *) &iounit->PlayingList,
  1154.           (struct Node *) ioreq->ahir_Link))
  1155.       {
  1156.         delay = TRUE;
  1157.       }
  1158.       else if(FindNode((struct List *) &iounit->SilentList,
  1159.           (struct Node *) ioreq->ahir_Link))
  1160.       {
  1161.         delay = TRUE;
  1162.       }
  1163.       else if(FindNode((struct List *) &iounit->WaitingList,
  1164.           (struct Node *) ioreq->ahir_Link))
  1165.       {
  1166.         delay = TRUE;
  1167.       }
  1168.     }
  1169.  
  1170.   // NOTE: ahir_Link changes direction here. When the user set's it, she makes a new
  1171.   // request point to an old. We let the old point to the next (that's more natural,
  1172.   // anyway...) It the user tries to link more than one request to another, we fail.
  1173.   
  1174.     if(delay)
  1175.     {
  1176.   
  1177. #ifdef DEBUG
  1178.       KPrintF("Delayed (0x%08lx)\n",ioreq);
  1179. #endif
  1180.   
  1181.       if( ! ioreq->ahir_Link->ahir_Link)
  1182.       {
  1183.         struct AHIRequest *otherioreq = ioreq->ahir_Link;
  1184.       
  1185.         channel = GetExtras(ioreq->ahir_Link)->Channel;
  1186.         GetExtras(ioreq)->Channel = NOCHANNEL;
  1187.   
  1188.         otherioreq->ahir_Link = ioreq;
  1189.         ioreq->ahir_Link = NULL;
  1190.         Enqueue((struct List *) &iounit->WaitingList,(struct Node *) ioreq);
  1191.   
  1192.         if(channel != NOCHANNEL)
  1193.         {
  1194.           // Attach the request to the currently playing one
  1195.   
  1196.           AHIsub_Disable((struct AHIAudioCtrlDrv *) iounit->AudioCtrl);
  1197.  
  1198.           // Make SURE the current sound isn't already finished!
  1199.           
  1200.           if(otherioreq->ahir_Std.io_Command == AHICMD_WRITTEN)
  1201.           {
  1202.             AHIsub_Enable((struct AHIAudioCtrlDrv *) iounit->AudioCtrl);
  1203.  
  1204.             // OOPS! It's finished! Undo...
  1205.             Remove((struct Node *) ioreq);
  1206.             
  1207.             // Start sound as if it wasn't delayed (see below);
  1208.             AddWriter(ioreq, iounit, AHIBase);
  1209.           }
  1210.           else
  1211.           {
  1212.             iounit->Voices[channel].QueuedRequest = ioreq;
  1213.             iounit->Voices[channel].NextOffset  = PLAY;
  1214.             iounit->Voices[channel].NextRequest = NULL;
  1215.             AHI_Play(iounit->AudioCtrl,
  1216.                 AHIP_BeginChannel,  channel,
  1217.                 AHIP_LoopFreq,      ioreq->ahir_Frequency,
  1218.                 AHIP_LoopVol,       ioreq->ahir_Volume,
  1219.                 AHIP_LoopPan,       ioreq->ahir_Position,
  1220.                 AHIP_LoopSound,     GetExtras(ioreq)->Sound,
  1221.                 AHIP_LoopOffset,    ioreq->ahir_Std.io_Actual,
  1222.                 AHIP_LoopLength,    ioreq->ahir_Std.io_Length - ioreq->ahir_Std.io_Actual,
  1223.                 AHIP_EndChannel,    NULL,
  1224.                 TAG_DONE);
  1225.             AHIsub_Enable((struct AHIAudioCtrlDrv *) iounit->AudioCtrl);
  1226.           }
  1227.  
  1228.         }
  1229.       }
  1230.       else // She tried to add more than one request to another one
  1231.       { 
  1232.         ioreq->ahir_Std.io_Error = AHIE_UNKNOWN;
  1233.         TermIO(ioreq, AHIBase);
  1234.       }
  1235.     }
  1236.     else // Sound is not delayed
  1237.     {
  1238.       ioreq->ahir_Link=NULL;
  1239.       AddWriter(ioreq, iounit, AHIBase);
  1240.     }
  1241.  
  1242.     ReleaseSemaphore(&iounit->ListLock);
  1243.   }
  1244.   else // No free sound found, or sound failed to load
  1245.   {
  1246.     ioreq->ahir_Std.io_Error = AHIE_UNKNOWN;
  1247.     TermIO(ioreq, AHIBase);
  1248.   }
  1249. }
  1250.  
  1251.  
  1252. /******************************************************************************
  1253. ** AddWriter ******************************************************************
  1254. ******************************************************************************/
  1255.  
  1256. // This function is called by NewWriter and RethinkPlayers. It adds an
  1257. // initialized request to either the playing or waiting list, and starts
  1258. // the sound it if possible
  1259.  
  1260. static void
  1261. AddWriter ( struct AHIRequest *ioreq,
  1262.             struct AHIDevUnit *iounit,
  1263.             struct AHIBase *AHIBase )
  1264. {
  1265.   int channel;
  1266.  
  1267. #ifdef DEBUG
  1268.   KPrintF("Addwriter (0x%08lx)\n",ioreq);
  1269. #endif
  1270.  
  1271.   // Search for a free channel, and use if found
  1272.  
  1273.   for(channel = 0; channel < iounit->Channels; channel++)
  1274.   {
  1275.     if(iounit->Voices[channel].NextOffset == (ULONG) FREE)
  1276.     {
  1277.       Enqueue((struct List *) &iounit->PlayingList,(struct Node *) ioreq);
  1278.       PlayRequest(channel, ioreq, iounit, AHIBase);
  1279.       break;
  1280.     }
  1281.   }
  1282.  
  1283.  
  1284.   if(channel == iounit->Channels)
  1285.   {
  1286.     struct AHIRequest *ioreq2;
  1287.  
  1288.     // No free channel found. Check if we can kick the last one out...
  1289.     // There is at least on node in the list, and the last one has lowest priority.
  1290.  
  1291. #ifdef DEBUG
  1292.     KPrintF("No free channel (0x%08lx)\n",ioreq);
  1293. #endif
  1294.  
  1295.     ioreq2 = (struct AHIRequest *) iounit->PlayingList.mlh_TailPred; 
  1296.     if(ioreq->ahir_Std.io_Message.mn_Node.ln_Pri
  1297.         > ioreq2->ahir_Std.io_Message.mn_Node.ln_Pri)
  1298.     {
  1299.       // Let's steal his place!
  1300.       RemTail((struct List *) &iounit->PlayingList);
  1301.       channel = GetExtras(ioreq2)->Channel;
  1302.       GetExtras(ioreq2)->Channel = NOCHANNEL;
  1303.       Enqueue((struct List *) &iounit->SilentList,(struct Node *) ioreq2);
  1304.  
  1305. #ifdef DEBUG
  1306.       KPrintF("Stealing %ld (my: %ld, her: %ld) (0x%08lx)\n",channel,
  1307.         ioreq->ahir_Std.io_Message.mn_Node.ln_Pri,
  1308.         ioreq2->ahir_Std.io_Message.mn_Node.ln_Pri, ioreq);
  1309. #endif
  1310.       Enqueue((struct List *) &iounit->PlayingList,(struct Node *) ioreq);
  1311.       PlayRequest(channel, ioreq, iounit, AHIBase);
  1312.     }
  1313.     else
  1314.     {
  1315.       // Let's be quiet for a while.
  1316.  
  1317. #ifdef DEBUG
  1318.       KPrintF("Being quiet for a while.. (0x%08lx)\n",ioreq);
  1319. #endif
  1320.       GetExtras(ioreq)->Channel = NOCHANNEL;
  1321.       Enqueue((struct List *) &iounit->SilentList,(struct Node *) ioreq);
  1322.     }
  1323.   }
  1324. }
  1325.  
  1326.  
  1327. /******************************************************************************
  1328. ** PlayRequest ****************************************************************
  1329. ******************************************************************************/
  1330.  
  1331. // This begins to play an AHIRequest (starting at sample io_Actual).
  1332.  
  1333. static void
  1334. PlayRequest ( int channel,
  1335.               struct AHIRequest *ioreq,
  1336.               struct AHIDevUnit *iounit,
  1337.               struct AHIBase *AHIBase )
  1338. {
  1339.   struct Library *AHIsubBase;
  1340.  
  1341.   AHIsubBase = ((struct AHIPrivAudioCtrl *) iounit->AudioCtrl)->ahiac_SubLib;
  1342.  
  1343. #ifdef DEBUG
  1344.   KPrintF("PlayRequest(%ld, 0x%08lx)\n", channel, ioreq);
  1345. #endif
  1346.  
  1347.   // Start the sound
  1348.  
  1349.   GetExtras(ioreq)->Channel = channel;
  1350.  
  1351.   if(ioreq->ahir_Link)
  1352.   {
  1353.     struct Voice        *v = &iounit->Voices[channel];
  1354.     struct AHIRequest   *r = ioreq->ahir_Link;
  1355.  
  1356. #ifdef DEBUG
  1357.     KPrintF("It has a link! 0x%08lx\n", ioreq->ahir_Link);
  1358. #endif
  1359.  
  1360.     v->NextSound     = GetExtras(r)->Sound;
  1361.     v->NextVolume    = r->ahir_Volume;
  1362.     v->NextPan       = r->ahir_Position;
  1363.     v->NextFrequency = r->ahir_Frequency;
  1364.     v->NextOffset    = r->ahir_Std.io_Actual;
  1365.     v->NextLength    = r->ahir_Std.io_Length
  1366.                      - r->ahir_Std.io_Actual;
  1367.     v->NextRequest   = r;
  1368.   }
  1369.   else
  1370.   {
  1371.     iounit->Voices[channel].NextOffset  = PLAY;
  1372.     iounit->Voices[channel].NextRequest = NULL;
  1373.   }
  1374.  
  1375. #ifdef DEBUG
  1376.   KPrintF("Starting it (0x%08lx)\n",ioreq);
  1377. #endif
  1378.  
  1379.   AHIsub_Disable((struct AHIAudioCtrlDrv *) iounit->AudioCtrl);
  1380.  
  1381.   iounit->Voices[channel].PlayingRequest = NULL;
  1382.   iounit->Voices[channel].QueuedRequest = ioreq;
  1383.   iounit->Voices[channel].Flags &= ~VF_STARTED;
  1384.  
  1385.   AHI_Play(iounit->AudioCtrl,
  1386.       AHIP_BeginChannel,  channel,
  1387.       AHIP_Freq,          ioreq->ahir_Frequency,
  1388.       AHIP_Vol,           ioreq->ahir_Volume,
  1389.       AHIP_Pan,           ioreq->ahir_Position,
  1390.       AHIP_Sound,         GetExtras(ioreq)->Sound,
  1391.       AHIP_Offset,        ioreq->ahir_Std.io_Actual,
  1392.       AHIP_Length,        ioreq->ahir_Std.io_Length-ioreq->ahir_Std.io_Actual,
  1393.       AHIP_EndChannel,    NULL,
  1394.       TAG_DONE);
  1395.  
  1396.   AHIsub_Enable((struct AHIAudioCtrlDrv *) iounit->AudioCtrl);
  1397.  
  1398.   // This is a workaround for a race condition.
  1399.   // The problem can occur if a delayed request follows immediately after
  1400.   // this one, before the sample interrupt routine has been called, and
  1401.   // overwrites QueuedRequest. The result is that this sound is never
  1402.   // marked as finished, and the application will wait forever on the
  1403.   // IO Request. Quite ugly, no?
  1404.  
  1405.   Wait(1L << iounit->SampleSignal);
  1406.  
  1407.   // Set signal again...
  1408.   Signal((struct Task *) iounit->Master, (1L << iounit->SampleSignal));
  1409.   
  1410. //  while(((volatile UBYTE) (iounit->Voices[channel].Flags) & VF_STARTED) == 0);
  1411. #ifdef DEBUG
  1412.   KPrintF("Exiting PlayRequest()\n");
  1413. #endif
  1414. }
  1415.  
  1416.  
  1417. /******************************************************************************
  1418. ** RethinkPlayers *************************************************************
  1419. ******************************************************************************/
  1420.  
  1421. // When a playing sample has reached it's end, this function is called.
  1422. // It finds and terminates all finished requests, and moves their 'childs'
  1423. // from the waiting list.
  1424. // Then it tries to restart all silent sounds.
  1425.  
  1426. void
  1427. RethinkPlayers ( struct AHIDevUnit *iounit,
  1428.                  struct AHIBase *AHIBase )
  1429. {
  1430.   struct MinList templist;
  1431.   struct AHIRequest *ioreq;
  1432.  
  1433. #ifdef DEBUG
  1434.   KPrintF("RethinkPlayers\n");
  1435. #endif
  1436.  
  1437.   NewList((struct List *) &templist);
  1438.  
  1439.   ObtainSemaphore(&iounit->ListLock);
  1440.  
  1441.   RemPlayers((struct List *) &iounit->PlayingList, iounit, AHIBase);
  1442.   RemPlayers((struct List *) &iounit->SilentList, iounit, AHIBase);
  1443.  
  1444.   // Move all silent requests to our temporary list
  1445.  
  1446.   while((ioreq = (struct AHIRequest *) RemHead((struct List *) &iounit->SilentList)))
  1447.   {
  1448.     AddTail((struct List *) &templist, (struct Node *) ioreq);
  1449.   }
  1450.  
  1451.   // And add them back...
  1452.   while((ioreq = (struct AHIRequest *) RemHead((struct List *) &templist)))
  1453.   {
  1454.     AddWriter(ioreq, iounit, AHIBase);
  1455.   }
  1456.  
  1457.   ReleaseSemaphore(&iounit->ListLock);
  1458. }
  1459.  
  1460.  
  1461. /******************************************************************************
  1462. ** RemPlayers *****************************************************************
  1463. ******************************************************************************/
  1464.  
  1465. // Removes all finished play requests from a list. The lists must be locked!
  1466.  
  1467. static void
  1468. RemPlayers ( struct List *list,
  1469.              struct AHIDevUnit *iounit,
  1470.              struct AHIBase *AHIBase )
  1471. {
  1472.   struct AHIRequest *ioreq, *node;
  1473.  
  1474. #ifdef DEBUG
  1475.   KPrintF("RemPlayers\n");
  1476. #endif
  1477.  
  1478.   node = (struct AHIRequest *) list->lh_Head;
  1479.   while(node->ahir_Std.io_Message.mn_Node.ln_Succ)
  1480.   {
  1481.     ioreq = node;
  1482.     node = (struct AHIRequest *) node->ahir_Std.io_Message.mn_Node.ln_Succ;
  1483.  
  1484.     if(ioreq->ahir_Std.io_Command == AHICMD_WRITTEN)
  1485.     {
  1486.  
  1487. #ifdef DEBUG
  1488.       KPrintF("Removing 0x%08lx\n", ioreq);
  1489. #endif
  1490.  
  1491.       Remove((struct Node *) ioreq);
  1492.  
  1493.       if(ioreq->ahir_Link)
  1494.       {
  1495.         // Move the attached one to the list
  1496.         Remove((struct Node *) ioreq->ahir_Link);
  1497.         GetExtras(ioreq->ahir_Link)->Channel = GetExtras(ioreq)->Channel;
  1498.         Enqueue(list, (struct Node *) ioreq->ahir_Link);
  1499.         // We have to go through the whole procedure again, in case
  1500.         // the child is finished, too.
  1501.         node = (struct AHIRequest *) list->lh_Head;
  1502.       }
  1503.  
  1504.       ioreq->ahir_Std.io_Error = AHIE_OK;
  1505.       ioreq->ahir_Std.io_Command = CMD_WRITE;
  1506.       ioreq->ahir_Std.io_Actual = ioreq->ahir_Std.io_Length
  1507.                                 * AHI_SampleFrameSize(ioreq->ahir_Type);
  1508.       TermIO(ioreq, AHIBase);
  1509.     }
  1510.   }
  1511. }
  1512.  
  1513.  
  1514. /******************************************************************************
  1515. ** UpdateSilentPlayers ********************************************************
  1516. ******************************************************************************/
  1517.  
  1518. // Updates the io_Actual field of all silent requests. The lists must be locked.
  1519. // This function is either called from the interrupt or DevProc.
  1520.  
  1521. void 
  1522. UpdateSilentPlayers ( struct AHIDevUnit *iounit,
  1523.                       struct AHIBase *AHIBase )
  1524. {
  1525.   struct AHIRequest *ioreq;
  1526.  
  1527.   for(ioreq = (struct AHIRequest *)iounit->SilentList.mlh_Head;
  1528.       ioreq->ahir_Std.io_Message.mn_Node.ln_Succ;
  1529.       ioreq = (struct AHIRequest *)ioreq->ahir_Std.io_Message.mn_Node.ln_Succ)
  1530.  
  1531.   {
  1532.     // Update io_Actual
  1533.     ioreq->ahir_Std.io_Actual += ((ioreq->ahir_Frequency << 14) / PLAYERFREQ) >> 14;
  1534.  
  1535.     // Check if the whole sample has been "played"
  1536.     if(ioreq->ahir_Std.io_Actual >= ioreq->ahir_Std.io_Length)
  1537.     {
  1538.       // Mark request as finished
  1539.       ioreq->ahir_Std.io_Command = AHICMD_WRITTEN;
  1540.  
  1541.       // Make us call Rethinkplayers later
  1542.       Signal((struct Task *) iounit->Master, (1L << iounit->SampleSignal));
  1543.     }
  1544.   }
  1545. }
  1546.