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

  1. /* $Id: device.c,v 4.25 1999/08/29 23:53:06 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 <exec/alerts.h>
  30. #include <exec/errors.h>
  31. #include <exec/io.h>
  32. #include <exec/devices.h>
  33. #include <exec/memory.h>
  34. #include <dos/dos.h>
  35. #include <dos/dostags.h>
  36. #include <libraries/iffparse.h>
  37. #include <prefs/prefhdr.h>
  38. #include <proto/exec.h>
  39. #include <proto/dos.h>
  40. #include <proto/iffparse.h>
  41. #include <clib/ahi_protos.h>
  42. #include <pragmas/ahi_pragmas.h>
  43. #include <proto/ahi_sub.h>
  44. #include <stddef.h>
  45.  
  46. #include "ahi_def.h"
  47. #include "device.h"
  48. #include "devcommands.h"
  49. #include "header.h"
  50. #include "misc.h"
  51.  
  52. /*
  53. ** Message passed to the Unit Process at
  54. ** startup time.
  55. */
  56.  
  57. struct StartupMessage
  58. {
  59.         struct Message           Msg;
  60.         struct AHIDevUnit       *Unit;
  61. };
  62.  
  63.  
  64. static struct
  65. AHIDevUnit *InitUnit( ULONG , struct AHIBase * );
  66.  
  67. static void
  68. ExpungeUnit( struct AHIDevUnit *, struct AHIBase * );
  69.  
  70. static void
  71. DevProc( void );
  72.  
  73.  
  74. static void ASMCALL INTERRUPT
  75. PlayerFunc ( REG(a0, struct Hook *hook),
  76.              REG(a2, struct AHIAudioCtrl *actrl),
  77.              REG(a1, APTR null) );
  78.  
  79. static ULONG ASMCALL INTERRUPT
  80. RecordFunc ( REG(a0, struct Hook *hook),
  81.              REG(a2, struct AHIAudioCtrl *actrl),
  82.              REG(a1, struct AHIRecordMessage *recmsg) );
  83.  
  84. static void ASMCALL INTERRUPT
  85. SoundFunc ( REG(a0, struct Hook *hook),
  86.             REG(a2, struct AHIAudioCtrl *actrl),
  87.             REG(a1, struct AHISoundMessage *sndmsg) );
  88.  
  89. static void ASMCALL INTERRUPT
  90. ChannelInfoFunc ( REG(a0, struct Hook *hook),
  91.                   REG(a2, struct AHIAudioCtrl *actrl),
  92.                   REG(a1, struct AHIEffChannelInfo *cimsg) );
  93.  
  94. BPTR ASMCALL
  95. DevExpunge( REG( a6, struct AHIBase* device ) );
  96.  
  97.  
  98. /***** ahi.device/--background-- *******************************************
  99. *
  100. *   PURPOSE
  101. *
  102. *       The 'ahi.device' was first created because the lack of standards
  103. *       when it comes to sound cards on the Amiga. Another reason was to
  104. *       make it easier to write multi-channel music programs.
  105. *
  106. *       This device is by no means the final and perfect solution. But
  107. *       hopefully, it can evolve into something useful until AT brings you
  108. *       The Real Thing (TM).
  109. *
  110. *   OVERVIEW
  111. *
  112. *       Please see the document "AHI Developer's Guide" for more
  113. *       information.
  114. *
  115. *
  116. *       * Driver based
  117. *
  118. *       Each supported sound card is controlled by a library-based audio
  119. *       driver. For a 'dumb' sound card, a new driver could be written in
  120. *       a few hours. For a 'smart' sound card, it is possible to utilize an
  121. *       on-board DSP, for example, to maximize performance and sound quality.
  122. *       For sound cards with own DSP but little or no memory, it is possible
  123. *       to use the main CPU to mix channels and do the post-processing
  124. *       with the DSP. Drivers are available for most popular sound cards,
  125. *       as well as an 8SVX (mono) and AIFF/AIFC (mono & stereo) sample render
  126. *       driver.
  127. *  
  128. *       * Fast, powerful mixing routines (yeah, right... haha)
  129. *  
  130. *       The device's mixing routines mix 8- or 16-bit signed samples, both
  131. *       mono and stereo, located in Fast-RAM and outputs 16-bit mono or stereo
  132. *       (with stereo panning if desired) data, using any number of channels
  133. *       (as long as 'any' means less than 128).  Tables can be used speed
  134. *       the mixing up (especially when using 8-bit samples).  The samples can
  135. *       have any length (including odd) and can have any number of loops.
  136. *       There are also so-called HiFi mixing routines that can be used, that
  137. *       use linear interpolation and gives 32 bit output.
  138. *       
  139. *       * Support for non-realtime mixing
  140. *  
  141. *       By providing a timing feature, it is possible to create high-
  142. *       quality output even if the processing power is lacking, by saving
  143. *       the output to disk, for example as an IFF AIFF or 8SXV file.
  144. *  
  145. *       * Audio database
  146. *  
  147. *       Uses ID codes, much like Screenmode IDs, to select the many
  148. *       parameters that can be set. The functions to access the audio
  149. *       database are not too different from those in 'graphics.library'.
  150. *       The device also features a requester to get an ID code from the
  151. *       user.
  152. *  
  153. *       * Both high- and low-level protocol
  154. *  
  155. *       By acting both like a device and a library, AHI gives the programmer
  156. *       a choice between full control and simplicity. The device API allows
  157. *       several programs to use the audio hardware at the same time, and
  158. *       the AUDIO: dos-device driver makes playing and recording sound very
  159. *       simple for both the programmer and user.
  160. *  
  161. *       * Future Compatible
  162. *  
  163. *       When AmigaOS gets device-independent audio worth it's name, it should
  164. *       not be too difficult to write a driver for AHI, allowing applications
  165. *       using 'ahi.device' to automatically use the new OS interface. At
  166. *       least I hope it wont.
  167. *
  168. *
  169. ****************************************************************************
  170. *
  171. */
  172.  
  173.  
  174. /******************************************************************************
  175. ** DevOpen ********************************************************************
  176. ******************************************************************************/
  177.  
  178. /****** ahi.device/OpenDevice **********************************************
  179. *
  180. *   NAME
  181. *       OpenDevice -- Open the device
  182. *
  183. *   SYNOPSIS
  184. *       error = OpenDevice(AHINAME, unit, ioRequest, flags)
  185. *       D0                 A0       D0    A1         D1
  186. *
  187. *       BYTE OpenDevice(STRPTR, ULONG, struct AHIRequest *, ULONG);
  188. *
  189. *   FUNCTION
  190. *       This is an exec call.  Exec will search for the ahi.device, and
  191. *       if found, will pass this call on to the device.
  192. *
  193. *   INPUTS
  194. *       AHINAME - pointer to the string "ahi.device".
  195. *       unit - Either AHI_DEFAULT_UNIT (0), AHI_NO_UNIT (255) or any other
  196. *           unit the user has requested, for example with a UNIT tooltype.
  197. *           AHI_NO_UNIT should be used when you're using the low-level
  198. *           API.
  199. *       ioRequest - a pointer to a struct AHIRequest, initialized by
  200. *           exec.library/CreateIORequest(). ahir_Version *must* be preset
  201. *           to the version you need!
  202. *       flags - There is only one flag defined, AHIDF_NOMODESCAN, which
  203. *           asks ahi.device not to build the audio mode database if not
  204. *           already initialized. It should not be used by applications
  205. *           without good reasons (AddAudioModes uses this flag).
  206. *
  207. *   RESULT
  208. *       error - Same as io_Error.
  209. *       io_Error - If the call succeeded, io_Error will be 0, else
  210. *           an error code as defined in <exec/errors.h> and
  211. *           <devices/ahi.h>.
  212. *       io_Device - A pointer to the device base, which can be used
  213. *           to call the functions the device provides.
  214. *
  215. *   EXAMPLE
  216. *
  217. *   NOTES
  218. *
  219. *   BUGS
  220. *
  221. *   SEE ALSO
  222. *      CloseDevice(), exec.library/OpenDevice(), <exec/errors.h>,
  223. *      <devices/ahi.h>.
  224. *
  225. ****************************************************************************
  226. *
  227. */
  228.  
  229. // This function is called by the system each time a unit is opened with
  230. // exec.library/OpenDevice().
  231.  
  232. ULONG ASMCALL
  233. DevOpen ( REG(d0, ULONG unit),
  234.           REG(d1, ULONG flags),
  235.           REG(a1, struct AHIRequest *ioreq),
  236.           REG(a6, struct AHIBase *AHIBase) )
  237. {
  238.   ULONG rc = 0;
  239.   BOOL  error = FALSE;
  240.   struct AHIDevUnit *iounit=NULL;
  241.  
  242.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  243.   {
  244.     KPrintF("OpenDevice(%ld, 0x%08lx, %ld)", unit, ioreq, flags);
  245.   }
  246.  
  247. // Check if size includes the ahir_Version field
  248.  
  249.   if(ioreq->ahir_Std.io_Message.mn_Length < (sizeof(struct IOStdReq) + 2))
  250.   {
  251.     Req( "Bad parameters to OpenDevice()." );
  252.     ioreq->ahir_Std.io_Error=IOERR_OPENFAIL;
  253.     return IOERR_OPENFAIL;
  254.   }
  255.  
  256. // One more check...
  257.  
  258.   if((unit != AHI_NO_UNIT) && (ioreq->ahir_Version >= Version))
  259.   {
  260.     if(ioreq->ahir_Std.io_Message.mn_Length < sizeof(struct AHIRequest))
  261.     {
  262.       Req( "Bad parameters to OpenDevice()." );
  263.       ioreq->ahir_Std.io_Error=IOERR_OPENFAIL;
  264.       return IOERR_OPENFAIL;
  265.     }
  266.   }
  267.  
  268.   AHIBase->ahib_Library.lib_OpenCnt++;
  269.   ObtainSemaphore(&AHIBase->ahib_Lock);
  270.  
  271.   if( ! (flags & AHIDF_NOMODESCAN))
  272.   {
  273.     // Load database if not already loaded
  274.  
  275.     if(AHI_NextAudioID(AHI_INVALID_ID) == AHI_INVALID_ID)
  276.     {
  277.       AHI_LoadModeFile("DEVS:AudioModes");
  278.     }
  279.   }
  280.  
  281.   if( ioreq->ahir_Version > Version)
  282.     error=TRUE;
  283.   else
  284.   {
  285.     if(unit < AHI_UNITS)
  286.     {
  287.       iounit=InitUnit(unit,AHIBase);
  288.       if(!iounit) 
  289.         error=TRUE;
  290.     }
  291.     else if(unit == AHI_NO_UNIT)
  292.       InitUnit(unit,AHIBase);
  293.   }
  294.  
  295.   if(!error)
  296.   {
  297.     ioreq->ahir_Std.io_Unit=(struct Unit *) iounit;
  298.     if(iounit)    // Is NULL for AHI_NO_UNIT
  299.       iounit->Unit.unit_OpenCnt++;
  300.     AHIBase->ahib_Library.lib_OpenCnt++;
  301.     AHIBase->ahib_Library.lib_Flags &=~LIBF_DELEXP;
  302.   }
  303.   else
  304.   {
  305.     rc=IOERR_OPENFAIL;
  306.     ioreq->ahir_Std.io_Error=IOERR_OPENFAIL;
  307.     ioreq->ahir_Std.io_Device=(struct Device *) -1;
  308.     ioreq->ahir_Std.io_Unit=(struct Unit *) -1;
  309.   }
  310.   ReleaseSemaphore(&AHIBase->ahib_Lock);
  311.   AHIBase->ahib_Library.lib_OpenCnt--;
  312.  
  313.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  314.   {
  315.     KPrintF("=>%ld\n",rc);
  316.   }
  317.  
  318.   return rc;
  319. }
  320.  
  321.  
  322. /******************************************************************************
  323. ** DevClose *******************************************************************
  324. ******************************************************************************/
  325.  
  326. /****** ahi.device/CloseDevice *********************************************
  327. *
  328. *   NAME
  329. *       CloseDevice -- Close the device
  330. *
  331. *   SYNOPSIS
  332. *       CloseDevice(ioRequest)
  333. *                   A1
  334. *
  335. *       void CloseDevice(struct IORequest *);
  336. *
  337. *   FUNCTION
  338. *       This is an exec call that closes the device. Every OpenDevice()
  339. *       must be matched with a call to CloseDevice().
  340. *
  341. *       The user must ensure that all outstanding IO Requests have been
  342. *       returned before closing the device.
  343. *
  344. *   INPUTS
  345. *       ioRequest - a pointer to the same struct AHIRequest that was used
  346. *           to open the device.
  347. *
  348. *   RESULT
  349. *
  350. *   EXAMPLE
  351. *
  352. *   NOTES
  353. *
  354. *   BUGS
  355. *
  356. *   SEE ALSO
  357. *      OpenDevice(), exec.library/CloseDevice()
  358. *
  359. ****************************************************************************
  360. *
  361. */
  362.  
  363. // This function is called by the system each time a unit is closed with
  364. // exec.library/CloseDevice().
  365.  
  366. BPTR ASMCALL
  367. DevClose ( REG(a1, struct AHIRequest *ioreq),
  368.            REG(a6, struct AHIBase *AHIBase) )
  369. {
  370.   struct AHIDevUnit *iounit;
  371.   BPTR  seglist=0;
  372.  
  373.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
  374.   {
  375.     KPrintF("CloseDevice(0x%08lx)\n", ioreq);
  376.   }
  377.  
  378.   ObtainSemaphore(&AHIBase->ahib_Lock);
  379.  
  380.   iounit= (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit;
  381.   ioreq->ahir_Std.io_Device = (struct Device *) -1;
  382.   ioreq->ahir_Std.io_Unit = (struct Unit *) -1;
  383.  
  384.   if(iounit)
  385.   {
  386.     iounit->Unit.unit_OpenCnt--;
  387.     if(!iounit->Unit.unit_OpenCnt)
  388.       ExpungeUnit(iounit,AHIBase);
  389.   }
  390.  
  391.   AHIBase->ahib_Library.lib_OpenCnt--;
  392.  
  393.   ReleaseSemaphore(&AHIBase->ahib_Lock);
  394.  
  395.   if(!AHIBase->ahib_Library.lib_OpenCnt)
  396.   {
  397.     if(AHIBase->ahib_Library.lib_Flags & LIBF_DELEXP)
  398.       seglist=DevExpunge(AHIBase);
  399.   }
  400.   return seglist;
  401. }
  402.  
  403.  
  404. /******************************************************************************
  405. ** InitUnit *******************************************************************
  406. ******************************************************************************/
  407.  
  408. // This function is called by DevOpen() to initialize a unit
  409.  
  410. static struct AHIDevUnit *
  411. InitUnit ( ULONG unit, 
  412.            struct AHIBase *AHIBase )
  413. {
  414.   struct AHIDevUnit *iounit;
  415.  
  416.   if( unit == AHI_NO_UNIT )
  417.   {
  418.     ReadConfig(NULL,AHIBase);
  419.     return NULL;
  420.   }
  421.   else if(!AHIBase->ahib_DevUnits[unit])
  422.   {
  423.     if((iounit = AllocVec(sizeof(struct AHIDevUnit), MEMF_CLEAR|MEMF_PUBLIC)))
  424.     {
  425.       NewList(&iounit->Unit.unit_MsgPort.mp_MsgList);
  426.  
  427.       iounit->Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
  428.       iounit->Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
  429.       iounit->Unit.unit_MsgPort.mp_Node.ln_Name = (STRPTR) DevName;
  430.       iounit->UnitNum = unit;
  431.       InitSemaphore(&iounit->ListLock);
  432.       NewList((struct List *)&iounit->ReadList);
  433.       NewList((struct List *)&iounit->PlayingList);
  434.       NewList((struct List *)&iounit->SilentList);
  435.       NewList((struct List *)&iounit->WaitingList);
  436.       NewList((struct List *)&iounit->RequestQueue);
  437.       if(ReadConfig(iounit,AHIBase))
  438.       {
  439.         if((iounit->Voices = AllocVec(
  440.             sizeof(struct Voice)*iounit->Channels,MEMF_PUBLIC|MEMF_CLEAR)))
  441.         {
  442.           int i;
  443.           struct Voice   *v = iounit->Voices;
  444.           struct MsgPort *replyport;
  445.           
  446.           // Mark all channels as free
  447.           for(i = 0 ; i < iounit->Channels; i++)
  448.           {
  449.             v->NextOffset = FREE;
  450.             v++;
  451.           }
  452.           
  453.           replyport = CreateMsgPort();
  454.  
  455.           if( replyport != NULL )
  456.           {
  457.             struct StartupMessage sm =
  458.             {
  459.               {
  460.                 { NULL, NULL, NT_UNKNOWN, 0, NULL },
  461.                 replyport, sizeof(struct StartupMessage),
  462.               },
  463.               iounit
  464.             };
  465.  
  466.             iounit->Process = CreateNewProcTags( NP_Entry,    (ULONG) &DevProc,
  467.                                                  NP_Name,     (ULONG) DevName,
  468.                                                  NP_Priority, AHI_PRI,
  469.                                                  TAG_DONE );
  470.  
  471.             if( iounit->Process != NULL )
  472.             {
  473.   
  474.                 PutMsg( &iounit->Process->pr_MsgPort,
  475.                         &sm.Msg );
  476.  
  477.                 WaitPort(replyport);
  478.                 GetMsg(replyport);
  479.             }
  480.             DeleteMsgPort(replyport);
  481.           }
  482.         }
  483.       }
  484.  
  485.       if(!iounit->Process)
  486.         FreeVec(iounit);
  487.       else
  488.         AHIBase->ahib_DevUnits[unit] = iounit;
  489.  
  490.     }
  491.   }
  492.   return AHIBase->ahib_DevUnits[unit];
  493. }
  494.  
  495.  
  496. /******************************************************************************
  497. ** ExpungeUnit ****************************************************************
  498. ******************************************************************************/
  499.  
  500. // This function is called by DevClose() to remove a unit.
  501.  
  502. static void 
  503. ExpungeUnit ( struct AHIDevUnit *iounit,
  504.               struct AHIBase *AHIBase )
  505. {
  506.   struct Task *unittask;
  507.  
  508.   unittask = (struct Task *) iounit->Process;
  509.   iounit->Process = (struct Process *) FindTask(NULL);
  510.   Signal(unittask,SIGBREAKF_CTRL_F);
  511.   Wait(SIGBREAKF_CTRL_F);
  512.   AHIBase->ahib_DevUnits[iounit->UnitNum]=NULL;
  513.   FreeVec(iounit->Voices);
  514.   FreeVec(iounit);
  515. }
  516.  
  517.  
  518. /******************************************************************************
  519. ** ReadConfig *****************************************************************
  520. ******************************************************************************/
  521.  
  522. // This functions loads the users settings for AHI.
  523.  
  524. BOOL
  525. ReadConfig ( struct AHIDevUnit *iounit,
  526.              struct AHIBase *AHIBase )
  527. {
  528.   struct IFFHandle *iff;
  529.   struct StoredProperty *prhd,*ahig;
  530.   struct CollectionItem *ci;
  531.  
  532.   if(iounit)
  533.   {
  534.     /* Internal defaults for device unit */
  535.     iounit->AudioMode       = AHI_INVALID_ID;   // See at the end of the function!
  536.     iounit->Frequency       = 10000;
  537.     iounit->Channels        = 4;
  538.     iounit->MonitorVolume   = ~0;
  539.     iounit->InputGain       = ~0;
  540.     iounit->OutputVolume    = ~0;
  541.     iounit->Input           = ~0;
  542.     iounit->Output          = ~0;
  543.   }
  544.   else
  545.   {
  546.     /* Internal defaults for low-level mode */
  547.     AHIBase->ahib_AudioMode       = AHI_INVALID_ID;
  548.     AHIBase->ahib_Frequency       = 10000;
  549.     AHIBase->ahib_MonitorVolume   = 0x00000;
  550.     AHIBase->ahib_InputGain       = 0x10000;
  551.     AHIBase->ahib_OutputVolume    = 0x10000;
  552.     AHIBase->ahib_Input           = 0;
  553.     AHIBase->ahib_Output          = 0;
  554.   }
  555.  
  556.   if((iff=AllocIFF()))
  557.   {
  558.     iff->iff_Stream=Open("ENV:Sys/ahi.prefs", MODE_OLDFILE);
  559.     if(iff->iff_Stream)
  560.     {
  561.       InitIFFasDOS(iff);
  562.       if(!OpenIFF(iff,IFFF_READ))
  563.       {
  564.         if(!(PropChunk(iff,ID_PREF,ID_PRHD)
  565.           || PropChunk(iff,ID_PREF,ID_AHIG)
  566.           || CollectionChunk(iff,ID_PREF,ID_AHIU)
  567.           || StopOnExit(iff,ID_PREF,ID_FORM)))
  568.         {
  569.           if(ParseIFF(iff,IFFPARSE_SCAN) == IFFERR_EOC)
  570.           {
  571.             prhd=FindProp(iff,ID_PREF,ID_PRHD);
  572.             ahig=FindProp(iff,ID_PREF,ID_AHIG);
  573.             
  574.             if(ahig)
  575.             {
  576.               struct AHIGlobalPrefs *globalprefs;
  577.               
  578.               globalprefs = (struct AHIGlobalPrefs *)ahig->sp_Data;
  579.  
  580.               AHIBase->ahib_DebugLevel = globalprefs->ahigp_DebugLevel;
  581.  
  582.               AHIBase->ahib_Flags = 0;
  583.  
  584.               if(globalprefs->ahigp_DisableSurround)
  585.                 AHIBase->ahib_Flags |= AHIBF_NOSURROUND;
  586.  
  587.               if(globalprefs->ahigp_DisableEcho)
  588.                 AHIBase->ahib_Flags |= AHIBF_NOECHO;
  589.  
  590.               if(globalprefs->ahigp_FastEcho)
  591.                 AHIBase->ahib_Flags |= AHIBF_FASTECHO;
  592.                 
  593.               if( (ULONG) ahig->sp_Size > offsetof( struct AHIGlobalPrefs,
  594.                                                     ahigp_MaxCPU) )
  595.               {
  596.                 AHIBase->ahib_MaxCPU = globalprefs->ahigp_MaxCPU;
  597.               }
  598.               else
  599.               {
  600.                 AHIBase->ahib_MaxCPU = 0x10000 * 90 / 100;
  601.               }
  602.  
  603.               if( (ULONG) ahig->sp_Size > offsetof( struct AHIGlobalPrefs, 
  604.                                                     ahigp_ClipMasterVolume) )
  605.               {
  606.                 if(globalprefs->ahigp_ClipMasterVolume)
  607.                   AHIBase->ahib_Flags |= AHIBF_CLIPPING;
  608.               }
  609.  
  610.               if( (ULONG) ahig->sp_Size > offsetof( struct AHIGlobalPrefs, 
  611.                                                     ahigp_AntiClickTime ) )
  612.               {
  613.                 AHIBase->ahib_AntiClickTime = globalprefs->ahigp_AntiClickTime;
  614.               }
  615.               else
  616.               {
  617.                 AHIBase->ahib_AntiClickTime = 0;
  618.               }
  619.  
  620.             }
  621.             ci=FindCollection(iff,ID_PREF,ID_AHIU);
  622.             while(ci)
  623.             {
  624.               struct AHIUnitPrefs *unitprefs;
  625.  
  626.               unitprefs = (struct AHIUnitPrefs *)ci->ci_Data;
  627.  
  628.               if(iounit)
  629.               {
  630.                 if(unitprefs->ahiup_Unit == iounit->UnitNum)
  631.                 {
  632.                   iounit->AudioMode       = unitprefs->ahiup_AudioMode;
  633.                   iounit->Frequency       = unitprefs->ahiup_Frequency;
  634.                   iounit->Channels        = unitprefs->ahiup_Channels;
  635.                   iounit->MonitorVolume   = unitprefs->ahiup_MonitorVolume;
  636.                   iounit->InputGain       = unitprefs->ahiup_InputGain;
  637.                   iounit->OutputVolume    = unitprefs->ahiup_OutputVolume;
  638.                   iounit->Input           = unitprefs->ahiup_Input;
  639.                   iounit->Output          = unitprefs->ahiup_Output;
  640.                 }
  641.               }
  642.               else
  643.               {
  644.                 if(unitprefs->ahiup_Unit == AHI_NO_UNIT)
  645.                 {
  646.                   AHIBase->ahib_AudioMode       = unitprefs->ahiup_AudioMode;
  647.                   AHIBase->ahib_Frequency       = unitprefs->ahiup_Frequency;
  648.                   AHIBase->ahib_MonitorVolume   = unitprefs->ahiup_MonitorVolume;
  649.                   AHIBase->ahib_InputGain       = unitprefs->ahiup_InputGain;
  650.                   AHIBase->ahib_OutputVolume    = unitprefs->ahiup_OutputVolume;
  651.                   AHIBase->ahib_Input           = unitprefs->ahiup_Input;
  652.                   AHIBase->ahib_Output          = unitprefs->ahiup_Output;
  653.                 }
  654.               }
  655.  
  656.               ci=ci->ci_Next;
  657.             }
  658.           }
  659.         }
  660.         CloseIFF(iff);
  661.       }
  662.       Close(iff->iff_Stream);
  663.     }
  664.     FreeIFF(iff);
  665.   }
  666.  
  667.   // Avoids calling AHI_BestAudioID if not neccessary (faster startup time,
  668.   // since doesn't open all sub libraries.
  669.  
  670.   if(iounit)
  671.   {
  672.     if(iounit->AudioMode == AHI_INVALID_ID)
  673.     {
  674.       iounit->AudioMode = AHI_BestAudioID(AHIDB_Realtime, TRUE, TAG_DONE);
  675.     }
  676.   }
  677.   else
  678.   {
  679.     if(AHIBase->ahib_AudioMode == AHI_INVALID_ID)
  680.     {
  681.       AHIBase->ahib_AudioMode = AHI_BestAudioID( AHIDB_Realtime, TRUE, TAG_DONE);
  682.     }
  683.   }
  684.  
  685.   return TRUE;
  686. }
  687.  
  688.  
  689. /******************************************************************************
  690. ** AllocHardware **************************************************************
  691. ******************************************************************************/
  692.  
  693. // Allocates the audio hardware
  694.  
  695. BOOL
  696. AllocHardware ( struct AHIDevUnit *iounit,
  697.                 struct AHIBase *AHIBase )
  698. {
  699.   BOOL rc = FALSE;
  700.   ULONG fullduplex=FALSE;
  701.  
  702.   /* Allocate the hardware */
  703.   iounit->AudioCtrl = AHI_AllocAudio(
  704.       AHIA_AudioID,       iounit->AudioMode,
  705.       AHIA_MixFreq,       iounit->Frequency,
  706.       AHIA_Channels,      iounit->Channels,
  707.       AHIA_Sounds,        MAXSOUNDS,
  708.       AHIA_PlayerFunc,    (ULONG) &iounit->PlayerHook,
  709.       AHIA_RecordFunc,    (ULONG) &iounit->RecordHook,
  710.       AHIA_SoundFunc,     (ULONG) &iounit->SoundHook,
  711.       TAG_DONE);
  712.  
  713.   if(iounit->AudioCtrl != NULL)
  714.   {
  715.     /* Full duplex? */
  716.     AHI_GetAudioAttrs(AHI_INVALID_ID,iounit->AudioCtrl,
  717.       AHIDB_FullDuplex, (ULONG) &fullduplex,
  718.       TAG_DONE);
  719.     iounit->FullDuplex = fullduplex;
  720.  
  721.     /* Set hardware properties */
  722.     AHI_ControlAudio(iounit->AudioCtrl,
  723.         (iounit->MonitorVolume == ~0 ? TAG_IGNORE : AHIC_MonitorVolume),
  724.         iounit->MonitorVolume,
  725.  
  726.         (iounit->InputGain == ~0 ? TAG_IGNORE : AHIC_InputGain),
  727.         iounit->InputGain,
  728.  
  729.         (iounit->OutputVolume == ~0 ? TAG_IGNORE : AHIC_OutputVolume),
  730.         iounit->OutputVolume,
  731.  
  732.         (iounit->Input == ~0U ? TAG_IGNORE : AHIC_Input),
  733.         iounit->Input,
  734.  
  735.         (iounit->Output == ~0U ? TAG_IGNORE : AHIC_Output),
  736.         iounit->Output,
  737.  
  738.         TAG_DONE);
  739.  
  740.     iounit->ChannelInfoStruct->ahie_Effect = AHIET_CHANNELINFO;
  741.     iounit->ChannelInfoStruct->ahieci_Func = &iounit->ChannelInfoHook;
  742.     iounit->ChannelInfoStruct->ahieci_Channels = iounit->Channels;
  743.     if(!AHI_SetEffect(iounit->ChannelInfoStruct, iounit->AudioCtrl))
  744.     {
  745.       rc = TRUE;
  746.     }
  747.   }
  748.   return rc;
  749. }
  750.  
  751.  
  752. /******************************************************************************
  753. ** FreeHardware ***************************************************************
  754. ******************************************************************************/
  755.  
  756. // Take a wild guess!
  757.  
  758. void
  759. FreeHardware ( struct AHIDevUnit *iounit,
  760.                struct AHIBase *AHIBase )
  761. {
  762.   if(iounit->AudioCtrl)
  763.   {
  764.     if(iounit->ChannelInfoStruct)
  765.     {
  766.       iounit->ChannelInfoStruct->ahie_Effect = (AHIET_CANCEL | AHIET_CHANNELINFO);
  767.       AHI_SetEffect(iounit->ChannelInfoStruct, iounit->AudioCtrl);
  768.     }
  769.     AHI_FreeAudio(iounit->AudioCtrl);
  770.     iounit->AudioCtrl = NULL;
  771.     iounit->IsRecording = FALSE;
  772.     iounit->IsPlaying = FALSE;
  773.     iounit->ValidRecord = FALSE;
  774.   }
  775. }
  776.  
  777.  
  778. /******************************************************************************
  779. ** DevProc ********************************************************************
  780. ******************************************************************************/
  781.  
  782. static void
  783. DevProc( void )
  784. {
  785.   struct Process *proc;
  786.   struct StartupMessage *sm;
  787.   struct AHIDevUnit *iounit;
  788.   BYTE  signalbit;
  789.  
  790.   proc = (struct Process *)FindTask(NULL);
  791.   WaitPort(&proc->pr_MsgPort);
  792.   sm = (struct StartupMessage *)GetMsg(&proc->pr_MsgPort);
  793.   iounit = sm->Unit;
  794.  
  795.   iounit->Process = NULL;
  796.  
  797.   iounit->PlayerHook.h_Entry=(HOOKFUNC)PlayerFunc;
  798.   iounit->PlayerHook.h_Data=iounit;
  799.  
  800.   iounit->RecordHook.h_Entry=(HOOKFUNC)RecordFunc;
  801.   iounit->RecordHook.h_Data=iounit;
  802.  
  803.   iounit->SoundHook.h_Entry=(HOOKFUNC)SoundFunc;
  804.   iounit->SoundHook.h_Data=iounit;
  805.  
  806.   iounit->ChannelInfoHook.h_Entry=(HOOKFUNC)ChannelInfoFunc;
  807.   iounit->ChannelInfoHook.h_Data=iounit;
  808.  
  809.   iounit->ChannelInfoStruct = AllocVec(
  810.       sizeof(struct AHIEffChannelInfo) + (iounit->Channels * sizeof(ULONG)),
  811.       MEMF_PUBLIC | MEMF_CLEAR);
  812.  
  813.   iounit->Master=proc;
  814.  
  815.   signalbit = AllocSignal(-1);
  816.   iounit->PlaySignal = AllocSignal(-1);
  817.   iounit->RecordSignal = AllocSignal(-1);
  818.   iounit->SampleSignal = AllocSignal(-1);
  819.  
  820.   if((signalbit != -1)
  821.   && (iounit->PlaySignal != -1)
  822.   && (iounit->RecordSignal != -1)
  823.   && (iounit->SampleSignal != -1)
  824.   && (iounit->ChannelInfoStruct != NULL)
  825.   )
  826.   {
  827.     /* Set up our Unit's MsgPort. */
  828.     iounit->Unit.unit_MsgPort.mp_SigBit = signalbit;
  829.     iounit->Unit.unit_MsgPort.mp_SigTask = (struct Task *)proc;
  830.     iounit->Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
  831.  
  832.     /* Allocate the hardware */
  833.     if(AllocHardware(iounit, AHIBase))
  834.     {
  835.  
  836.       /* Set iounit->Process to pointer to our unit process.
  837.          This will let the Unit init code know that were
  838.          are okay. */
  839.       iounit->Process = proc;
  840.     }
  841.   }
  842.  
  843.   /* Reply to our startup message */
  844.   ReplyMsg(&sm->Msg);
  845.  
  846.   if(iounit->Process)
  847.   {
  848.     ULONG  waitmask,signals;
  849.  
  850.     waitmask = (1L << signalbit)
  851.              | SIGBREAKF_CTRL_E    // Dummy signal to wake up task
  852.              | SIGBREAKF_CTRL_F    // Quit signal
  853.              | (1L << iounit->PlaySignal)
  854.              | (1L << iounit->RecordSignal)
  855.              | (1L << iounit->SampleSignal);
  856.  
  857.     while(TRUE)
  858.     {
  859.       signals = Wait(waitmask);
  860.  
  861.       /* Have we been signaled to shut down? */
  862.       if(signals & SIGBREAKF_CTRL_F)
  863.         break;
  864.  
  865.       if(signals & (1L << iounit->SampleSignal))
  866.       {
  867.         RethinkPlayers(iounit,AHIBase);
  868.       }
  869.  
  870.       if(signals & (1L << signalbit))
  871.       {
  872.         struct AHIRequest *ioreq;
  873.  
  874.         while((ioreq = (struct AHIRequest *) GetMsg(&iounit->Unit.unit_MsgPort)))
  875.         {
  876.           PerformIO(ioreq,AHIBase);
  877.         }
  878.       }
  879.       
  880.       if(signals & (1L << iounit->PlaySignal))
  881.       {
  882.         ObtainSemaphore(&iounit->ListLock);
  883.         UpdateSilentPlayers(iounit,AHIBase);
  884.         ReleaseSemaphore(&iounit->ListLock);
  885.       }
  886.  
  887.       if(signals & (1L << iounit->RecordSignal))
  888.       {
  889.         iounit->ValidRecord = TRUE;
  890.         FeedReaders(iounit,AHIBase);
  891.       }
  892.     }
  893.   }
  894.  
  895.   FreeHardware(iounit, AHIBase);
  896.   FreeSignal(iounit->SampleSignal);
  897.   iounit->SampleSignal = -1;
  898.   FreeSignal(iounit->RecordSignal);
  899.   iounit->RecordSignal = -1;
  900.   FreeSignal(iounit->PlaySignal);
  901.   iounit->PlaySignal = -1;
  902.   FreeVec(iounit->ChannelInfoStruct);
  903.  
  904.   if(iounit->Process)
  905.   {
  906.     Forbid();
  907.     Signal((struct Task *) iounit->Process, SIGBREAKF_CTRL_F);
  908.   }
  909.   FreeSignal(signalbit);
  910. }
  911.  
  912.  
  913. /******************************************************************************
  914. ** PlayerFunc *****************************************************************
  915. ******************************************************************************/
  916.  
  917. static void ASMCALL INTERRUPT
  918. PlayerFunc ( REG(a0, struct Hook *hook),
  919.              REG(a2, struct AHIAudioCtrl *actrl),
  920.              REG(a1, APTR null) )
  921. {
  922.   struct AHIDevUnit *iounit = (struct AHIDevUnit *) hook->h_Data;
  923.  
  924.   if(AttemptSemaphore(&iounit->ListLock))
  925.   {
  926.     UpdateSilentPlayers(iounit,AHIBase);
  927.     ReleaseSemaphore(&iounit->ListLock);
  928.   }
  929.   else
  930.   { // Do it later instead
  931.     Signal((struct Task *) iounit->Master, (1L << iounit->PlaySignal));
  932.   }
  933.   return;
  934. }
  935.  
  936.  
  937. /******************************************************************************
  938. ** RecordFunc *****************************************************************
  939. ******************************************************************************/
  940.  
  941. static ULONG ASMCALL INTERRUPT
  942. RecordFunc ( REG(a0, struct Hook *hook),
  943.              REG(a2, struct AHIAudioCtrl *actrl),
  944.              REG(a1, struct AHIRecordMessage *recmsg) )
  945. {
  946.   struct AHIDevUnit *iounit;
  947.   
  948.   if(recmsg->ahirm_Type == AHIST_S16S)
  949.   {
  950.     iounit = (struct AHIDevUnit *) hook->h_Data;
  951.     iounit->RecordBuffer = recmsg->ahirm_Buffer;
  952.     iounit->RecordSize = recmsg->ahirm_Length<<2;
  953. #ifdef DEBUG_R
  954.     KPrintF("Buffer Filled again...\n");
  955. #endif
  956.     Signal((struct Task *) iounit->Master, (1L << iounit->RecordSignal));
  957.   }
  958.   return 0;
  959. }
  960.  
  961.  
  962. /******************************************************************************
  963. ** SoundFunc ******************************************************************
  964. ******************************************************************************/
  965.  
  966. static void ASMCALL INTERRUPT
  967. SoundFunc ( REG(a0, struct Hook *hook),
  968.             REG(a2, struct AHIAudioCtrl *actrl),
  969.             REG(a1, struct AHISoundMessage *sndmsg) )
  970. {
  971.   struct AHIDevUnit *iounit;
  972.   struct Voice *voice;  
  973.  
  974.   iounit = (struct AHIDevUnit *) hook->h_Data;
  975.   voice = &iounit->Voices[(WORD)sndmsg->ahism_Channel];
  976.  
  977. #ifdef DEBUG
  978.   KPrintF("Playing on channel %ld: 0x%08lx\n", sndmsg->ahism_Channel, voice->PlayingRequest);
  979. #endif
  980.  
  981.   if(voice->PlayingRequest)
  982.   {
  983.     voice->PlayingRequest->ahir_Std.io_Command = AHICMD_WRITTEN;
  984. #ifdef DEBUG
  985.     KPrintF("Marked 0x%08lx as written\n", voice->PlayingRequest);
  986. #endif
  987.   }
  988.   voice->PlayingRequest = voice->QueuedRequest;
  989.   voice->Flags |= VF_STARTED;
  990. #ifdef DEBUG
  991.   KPrintF("New player: 0x%08lx\n", voice->PlayingRequest);
  992. #endif
  993.   voice->QueuedRequest  = NULL;
  994.  
  995.   switch(voice->NextOffset)
  996.   {
  997.     case FREE:
  998. #ifdef DEBUG
  999.       KPrintF("Ch %ld FREE\n",sndmsg->ahism_Channel);
  1000. #endif
  1001.       break;
  1002.     case MUTE:
  1003. #ifdef DEBUG
  1004.       KPrintF("Ch %ld MUTE->FREE\n",sndmsg->ahism_Channel);
  1005. #endif
  1006.       /* A AHI_NOSOUND is done, channel is silent */
  1007.       voice->NextOffset = FREE;
  1008.       break;
  1009.     case PLAY:
  1010. #ifdef DEBUG
  1011.       KPrintF("Ch %ld PLAY->MUTE\n",sndmsg->ahism_Channel);
  1012. #endif
  1013.       /* A normal sound is done and playing, no other sound is queued */
  1014.       AHI_SetSound(sndmsg->ahism_Channel,AHI_NOSOUND,0,0,actrl,AHISF_NONE);
  1015.       voice->NextOffset = MUTE;
  1016.       break;
  1017.     default:
  1018. #ifdef DEBUG
  1019.       KPrintF("Ch %ld 0x%08lx->PLAY\n",sndmsg->ahism_Channel,voice->NextOffset);
  1020. #endif
  1021.       /* A normal sound is done, and another is waiting */
  1022.       AHI_SetSound(sndmsg->ahism_Channel,
  1023.           voice->NextSound,
  1024.           voice->NextOffset,
  1025.           voice->NextLength,
  1026.           actrl,AHISF_NONE);
  1027.       AHI_SetFreq(sndmsg->ahism_Channel,
  1028.           voice->NextFrequency,
  1029.           actrl,AHISF_NONE);
  1030.       AHI_SetVol(sndmsg->ahism_Channel,
  1031.           voice->NextVolume,
  1032.           voice->NextPan,
  1033.           actrl,AHISF_NONE);
  1034.       voice->QueuedRequest = voice->NextRequest;
  1035.       voice->NextRequest = NULL;
  1036.       voice->NextOffset = PLAY;
  1037.       break;
  1038.   }
  1039.  
  1040.   Signal((struct Task *) iounit->Master, (1L << iounit->SampleSignal));
  1041. }
  1042.  
  1043.  
  1044. /******************************************************************************
  1045. ** ChannelInfoFunc ************************************************************
  1046. ******************************************************************************/
  1047.  
  1048. // This hook keeps updating the io_Actual field of each playing requests
  1049.  
  1050. static void ASMCALL INTERRUPT
  1051. ChannelInfoFunc ( REG(a0, struct Hook *hook),
  1052.                   REG(a2, struct AHIAudioCtrl *actrl),
  1053.                   REG(a1, struct AHIEffChannelInfo *cimsg) )
  1054. {
  1055.   struct AHIDevUnit *iounit = (struct AHIDevUnit *) hook->h_Data;
  1056.   struct Voice      *voice;
  1057.   ULONG             *offsets = (ULONG *) &cimsg->ahieci_Offset;
  1058.   int i;
  1059.  
  1060.   Disable();    // Not needed?
  1061.   voice = iounit->Voices;
  1062.   for(i = 0; i < iounit->Channels; i++)
  1063.   {
  1064.     if(voice->PlayingRequest)
  1065.     {
  1066.       voice->PlayingRequest->ahir_Std.io_Actual = *offsets;
  1067.     }
  1068.     voice++;
  1069.     offsets++;
  1070.   }
  1071.   Enable();
  1072.   return;
  1073. }
  1074.