home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / ahisrc / device / mixer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-11  |  45.9 KB  |  1,638 lines

  1. /* $Id: mixer.c,v 4.45 1999/10/11 21:48:04 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. #include <config.h>
  24. #include <CompilerSpecific.h>
  25.  
  26. #include <exec/interrupts.h>
  27. #include <hardware/intbits.h>
  28.  
  29. #if !defined( VERSIONPPC )
  30. # include <string.h>
  31. # include <stddef.h>
  32.  
  33. # include <exec/memory.h>
  34. # include <exec/execbase.h>
  35. # include <powerup/ppclib/memory.h>
  36. # include <powerup/ppclib/interface.h>
  37. # include <powerup/ppclib/object.h>
  38. # include <powerpc/powerpc.h>
  39.  
  40. # include <proto/exec.h>
  41. # include <proto/utility.h>
  42. # include <proto/ppc.h> 
  43. # include <proto/powerpc.h> 
  44. # include <clib/ahi_protos.h>
  45. # include <inline/ahi.h>
  46. #endif
  47.  
  48. #include "ahi_def.h"
  49. #include "dsp.h"
  50. #include "mixer.h"
  51. #include "addroutines.h"
  52. #include "misc.h"
  53. #include "header.h"
  54. #include "ppcheader.h"
  55.  
  56. #define GetSymbol( name ) AHIGetELFSymbol( #name, (void*) &name ## Ptr )
  57.  
  58. /******************************************************************************
  59. ** Prototypes *****************************************************************
  60. ******************************************************************************/
  61.  
  62. static void
  63. DoMasterVolume ( void *buffer,
  64.                  struct AHIPrivAudioCtrl *audioctrl );
  65.  
  66. #if !defined( VERSIONPPC )
  67.  
  68. static void
  69. DoOutputBuffer ( void *buffer,
  70.                  struct AHIPrivAudioCtrl *audioctrl );
  71.  
  72. static void
  73. DoChannelInfo ( struct AHIPrivAudioCtrl *audioctrl );
  74.  
  75. #endif /* !defined( VERSIONPPC ) */
  76.  
  77. ADDFUNC* AddByteMonoPtr     = NULL;
  78. ADDFUNC* AddByteStereoPtr   = NULL;
  79. ADDFUNC* AddBytesMonoPtr    = NULL;
  80. ADDFUNC* AddBytesStereoPtr  = NULL;
  81. ADDFUNC* AddWordMonoPtr     = NULL;
  82. ADDFUNC* AddWordStereoPtr   = NULL;
  83. ADDFUNC* AddWordsMonoPtr    = NULL;
  84. ADDFUNC* AddWordsStereoPtr  = NULL;
  85. ADDFUNC* AddByteMonoBPtr    = NULL;
  86. ADDFUNC* AddByteStereoBPtr  = NULL;
  87. ADDFUNC* AddBytesMonoBPtr   = NULL;
  88. ADDFUNC* AddBytesStereoBPtr = NULL;
  89. ADDFUNC* AddWordMonoBPtr    = NULL;
  90. ADDFUNC* AddWordStereoBPtr  = NULL;
  91. ADDFUNC* AddWordsMonoBPtr   = NULL;
  92. ADDFUNC* AddWordsStereoBPtr = NULL;
  93.  
  94. ADDFUNC* AddLofiByteMonoPtr     = NULL;
  95. ADDFUNC* AddLofiByteStereoPtr   = NULL;
  96. ADDFUNC* AddLofiBytesMonoPtr    = NULL;
  97. ADDFUNC* AddLofiBytesStereoPtr  = NULL;
  98. ADDFUNC* AddLofiWordMonoPtr     = NULL;
  99. ADDFUNC* AddLofiWordStereoPtr   = NULL;
  100. ADDFUNC* AddLofiWordsMonoPtr    = NULL;
  101. ADDFUNC* AddLofiWordsStereoPtr  = NULL;
  102. ADDFUNC* AddLofiByteMonoBPtr    = NULL;
  103. ADDFUNC* AddLofiByteStereoBPtr  = NULL;
  104. ADDFUNC* AddLofiBytesMonoBPtr   = NULL;
  105. ADDFUNC* AddLofiBytesStereoBPtr = NULL;
  106. ADDFUNC* AddLofiWordMonoBPtr    = NULL;
  107. ADDFUNC* AddLofiWordStereoBPtr  = NULL;
  108. ADDFUNC* AddLofiWordsMonoBPtr   = NULL;
  109. ADDFUNC* AddLofiWordsStereoBPtr = NULL;
  110.  
  111.  
  112. static const UBYTE type2bytes[]=
  113. {
  114.   1,    // AHIST_M8S  (0)
  115.   2,    // AHIST_M16S (1)
  116.   2,    // AHIST_S8S  (2)
  117.   4,    // AHIST_S16S (3)
  118.   1,    // AHIST_M8U  (4)
  119.   0,
  120.   0,
  121.   0,
  122.   4,    // AHIST_M32S (8)
  123.   0,
  124.   8     // AHIST_S32S (10)
  125. };
  126.  
  127. inline ULONG
  128. InternalSampleFrameSize( ULONG sampletype )
  129. {
  130.   return type2bytes[sampletype];
  131. }
  132.  
  133. /******************************************************************************
  134. ** PowerUp Support code *******************************************************
  135. ******************************************************************************/
  136.  
  137. #if defined( VERSIONPPC )
  138.  
  139. /* PPC code ******************************************************************/
  140.  
  141. static inline void
  142. CallSoundHook( struct AHIPrivAudioCtrl *audioctrl,
  143.                void* arg )
  144. {
  145.   audioctrl->ahiac_PPCCommand  = AHIAC_COM_SOUNDFUNC;
  146.   audioctrl->ahiac_PPCArgument = arg;
  147.   *((WORD*) 0xdff09C)  = INTF_SETCLR | INTF_PORTS;
  148.   while( audioctrl->ahiac_PPCCommand != AHIAC_COM_ACK );
  149. }
  150.  
  151. static inline void
  152. CallDebug( struct AHIPrivAudioCtrl *audioctrl, long value )
  153. {
  154.   audioctrl->ahiac_PPCCommand  = AHIAC_COM_DEBUG;
  155.   audioctrl->ahiac_PPCArgument = (void*) value;
  156.   *((WORD*) 0xdff09C)  = INTF_SETCLR | INTF_PORTS;
  157.   while( audioctrl->ahiac_PPCCommand != AHIAC_COM_ACK );
  158. }
  159.  
  160. static void*
  161. memset( void* s, int c, unsigned int n )
  162. {
  163.   char* dst = s;
  164.  
  165.   while( n > 0 )
  166.   {
  167.     *dst++ = c;
  168.     n--;
  169.   }
  170.  
  171.   return s;
  172. }
  173.  
  174. #else
  175.  
  176. /* M68k code *****************************************************************/
  177.  
  178. static inline void
  179. CallSoundHook( struct AHIPrivAudioCtrl *audioctrl,
  180.                void* arg )
  181. {
  182. //kprintf("CallSoundHook\n");
  183.   CallHookPkt( audioctrl->ac.ahiac_SoundFunc,
  184.                audioctrl,
  185.                arg );
  186. }
  187.  
  188. static void
  189. CallDebug( struct AHIPrivAudioCtrl *audioctrl, long value )
  190. {
  191.   kprintf( "%lx ", value );
  192. }
  193.  
  194.  
  195. INTERRUPT SAVEDS int
  196. Interrupt( struct AHIPrivAudioCtrl *audioctrl __asm( "a1" ) )
  197. {
  198.  
  199.   if( audioctrl->ahiac_PPCCommand != AHIAC_COM_INIT )
  200.   {
  201.     /* Not for us, continue */
  202.     return 0;
  203.   }
  204.   else
  205.   {
  206.     BOOL running = TRUE;
  207. //kprintf("I");
  208.     while( running )
  209.     {
  210. //kprintf("0");
  211.       switch( audioctrl->ahiac_PPCCommand )
  212.       {
  213.         case AHIAC_COM_INIT:
  214. //kprintf("1");
  215.           // Keep looping
  216.           audioctrl->ahiac_PPCCommand = AHIAC_COM_ACK;
  217.           break;
  218.  
  219.         case AHIAC_COM_ACK:
  220. //kprintf("2");
  221.           // Keep looping, try not to waste to much memory bandwidth...
  222.           asm( "stop #(1<<13) | (2<<8)" : );
  223.           break;
  224.  
  225.         case AHIAC_COM_SOUNDFUNC:
  226. //kprintf("3");
  227.           CallSoundHook( audioctrl, (void*) audioctrl->ahiac_PPCArgument );
  228.           audioctrl->ahiac_PPCCommand = AHIAC_COM_ACK;
  229.           break;
  230.  
  231.         case AHIAC_COM_DEBUG:
  232. //kprintf("4");
  233.           CallDebug( audioctrl, (ULONG) audioctrl->ahiac_PPCArgument );
  234.           audioctrl->ahiac_PPCCommand = AHIAC_COM_ACK;
  235.           break;
  236.  
  237.         case AHIAC_COM_QUIT:
  238. //kprintf("5");
  239.           running = FALSE;
  240.           audioctrl->ahiac_PPCCommand = AHIAC_COM_ACK;
  241.           break;
  242.         
  243.         case AHIAC_COM_NONE:
  244.         default:
  245. //kprintf("6");
  246.           // Error
  247.           running  = FALSE;
  248.           audioctrl->ahiac_PPCCommand = AHIAC_COM_ACK;
  249.           break;
  250.       }
  251.     }
  252. //kprintf("i");
  253.  
  254.     /* End chain! */
  255.     return 1;
  256.   }
  257. };
  258.  
  259. void ASMCALL
  260. MixPowerUp( REG(a0, struct Hook *Hook), 
  261.             REG(a1, void *dst), 
  262.             REG(a2, struct AHIPrivAudioCtrl *audioctrl) )
  263. {
  264.   struct AHISoundData *sd;
  265.   int                  i;
  266.   BOOL                 flushed = FALSE;
  267.  
  268. //kprintf("M");
  269.   // Flush all DYNAMICSAMPLE's
  270.  
  271.   sd = audioctrl->ahiac_SoundDatas;
  272.  
  273.   for( i = 0; i < audioctrl->ac.ahiac_Sounds; i++)
  274.   {
  275.     if( sd->sd_Type == AHIST_DYNAMICSAMPLE )
  276.     {
  277.       if( sd->sd_Addr == NULL )
  278.       {
  279. //kprintf("a");
  280.         // Flush all and exit
  281.         CacheClearU();
  282.         flushed = TRUE;
  283.         break;
  284.       }
  285.       else
  286.       {
  287. //kprintf("b");
  288.         switch( MixBackend )
  289.         {
  290.           case MB_POWERUP:
  291.             PPCCacheClearE( sd->sd_Addr,
  292.                             sd->sd_Length * InternalSampleFrameSize( sd->sd_Type ),
  293.                             CACRF_ClearD );
  294.             break;
  295.  
  296.           case MB_WARPUP:
  297.             CacheClearE( sd->sd_Addr,
  298.                          sd->sd_Length * InternalSampleFrameSize( sd->sd_Type ),
  299.                          CACRF_ClearD );
  300. //            SetCache68K( CACHE_DCACHEFLUSH,
  301. //                         sd->sd_Addr,
  302. //                         sd->sd_Length * InternalSampleFrameSize( sd->sd_Type ) );
  303.             break;
  304.  
  305.           case MB_NATIVE:
  306.             // Ugh!
  307.             break;
  308.         }
  309.       }
  310. //kprintf("c");
  311.     }
  312.     sd++;
  313.   }
  314.  
  315. //kprintf("d");
  316. #ifdef WARPUP_INVALIDATE_CACHE
  317.   if( ! flushed && MixBackend == MB_WARPUP )
  318.   {
  319. //kprintf( "0x%08lx, 0x%08lx, %ld\n", audioctrl, audioctrl->ahiac_PPCMixBuffer, audioctrl->ahiac_BuffSizeNow );
  320.     /* Since the PPC mix buffer is m68k cacheable in WarpUp, we have to
  321.        flush, or better, *invalidate* the cache before mixing starts. */
  322.  
  323.       CacheClearE( audioctrl->ahiac_PPCMixBuffer,
  324.                    audioctrl->ahiac_BuffSizeNow,
  325.                    CACRF_ClearD );
  326.  
  327. //    SetCache68K( CACHE_DCACHEFLUSH,
  328. //                 audioctrl->ahiac_PPCMixBuffer,
  329. //                 audioctrl->ahiac_BuffSizeNow );
  330.   }
  331. #endif
  332. //kprintf("e");
  333.  
  334.   audioctrl->ahiac_PPCCommand = AHIAC_COM_NONE;
  335.  
  336.   switch( MixBackend )
  337.   {
  338.     case MB_POWERUP:
  339.     {
  340.       struct ModuleArgs mod =
  341.       {
  342.         IF_CACHEFLUSHNO, 0, 0,
  343.         IF_CACHEFLUSHNO | IF_ASYNC, 0, 0,
  344.  
  345.         0xC0DECAFE,
  346.         (ULONG) Hook,
  347.         (ULONG) audioctrl->ahiac_PPCMixBuffer,
  348.         (ULONG) audioctrl,
  349.         TRUE,                                  // Flush buffer afterwards!
  350.         0, 0, 0,
  351.         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  352.       };
  353.  
  354.       //kprintf("K");
  355.       PPCRunKernelObject( PPCObject, &mod );
  356.       //kprintf("k");
  357.  
  358.       audioctrl->ahiac_PPCCommand = AHIAC_COM_START; // I like it better after
  359.       break;
  360.     }
  361.  
  362.     case MB_WARPUP:
  363.       audioctrl->ahiac_PPCWarpUpContext->AudioCtrl    = (struct AudioCtrl*) audioctrl;
  364.       audioctrl->ahiac_PPCWarpUpContext->Hook         = Hook;
  365.       audioctrl->ahiac_PPCWarpUpContext->Dst          = audioctrl->ahiac_PPCMixBuffer;
  366. #ifndef WARPUP_INVALIDATE_CACHE
  367.       audioctrl->ahiac_PPCWarpUpContext->MixLongWords = ( audioctrl->ahiac_BuffSizeNow + 3 ) / 4;
  368. #endif
  369.       audioctrl->ahiac_PPCWarpUpContext->Active       = TRUE;
  370.  
  371.       audioctrl->ahiac_PPCCommand = AHIAC_COM_START; // Must be before
  372.       //kprintf("C");
  373.       CausePPCInterrupt();
  374.       //kprintf("c");
  375.       break;
  376.  
  377.     case MB_NATIVE:
  378.       // Ugh!
  379.       break;
  380.   }
  381.  
  382. //kprintf("f");
  383.   while( audioctrl->ahiac_PPCCommand != AHIAC_COM_FINISHED );
  384. //kprintf("g");
  385.  
  386.   // The PPC mix buffer is either not m68k-cachable or cleared;
  387.   // just read from it.
  388.  
  389.   memcpy( dst, audioctrl->ahiac_PPCMixBuffer, audioctrl->ahiac_BuffSizeNow );
  390.  
  391.   /*** AHIET_OUTPUTBUFFER ***/
  392.  
  393.   DoOutputBuffer(dst, audioctrl);
  394.  
  395.   /*** AHIET_CHANNELINFO ***/
  396.  
  397.   DoChannelInfo(audioctrl);
  398. //kprintf("m");
  399.  
  400.   return;
  401. }
  402.  
  403. #endif /* defined( VERSIONPPC ) */
  404.  
  405.  
  406. #if !defined( VERSIONPPC )
  407.  
  408. /******************************************************************************
  409. ** InitMixroutine *************************************************************
  410. ******************************************************************************/
  411.  
  412. // This function is used to initialize the mixer routine (called from 
  413. // AHI_AllocAudio()).
  414.  
  415. BOOL
  416. InitMixroutine ( struct AHIPrivAudioCtrl *audioctrl )
  417. {
  418.   BOOL rc = FALSE;
  419.  
  420.   // Allocate and initialize the AHIChannelData structures
  421.   // This structure could be accessed from from interrupts!
  422.  
  423.   audioctrl->ahiac_ChannelDatas = AHIAllocVec(
  424.       audioctrl->ac.ahiac_Channels * sizeof( struct AHIChannelData ),
  425.       MEMF_PUBLIC | MEMF_CLEAR | MEMF_NOCACHESYNCPPC | MEMF_NOCACHESYNCM68K );
  426.  
  427.   // Allocate and initialize the AHISoundData structures
  428.   // This structure could be accessed from from interrupts!
  429.  
  430.   audioctrl->ahiac_SoundDatas = AHIAllocVec(
  431.       audioctrl->ac.ahiac_Sounds * sizeof( struct AHISoundData ),
  432.       MEMF_PUBLIC | MEMF_CLEAR | MEMF_NOCACHESYNCPPC | MEMF_NOCACHESYNCM68K );
  433.  
  434.   // Allocate structures specific to the PPC version
  435.  
  436.   if( PPCObject != NULL )
  437.   {
  438.     switch( MixBackend )
  439.     {
  440.       case MB_NATIVE:
  441.         Req( "Internal error: Illegal MixBackend in InitMixroutine()" );
  442.         break;
  443.  
  444.       case MB_POWERUP:
  445.         audioctrl->ahiac_PPCMixBuffer = AHIAllocVec(
  446.             audioctrl->ac.ahiac_BuffSize,
  447.             MEMF_PUBLIC | MEMF_NOCACHEM68K );
  448.         break;
  449.  
  450.       case MB_WARPUP:
  451.         audioctrl->ahiac_PPCMixBuffer = AHIAllocVec(
  452.             audioctrl->ac.ahiac_BuffSize,
  453. #ifdef WARPUP_INVALIDATE_CACHE
  454.             MEMF_PUBLIC
  455. #else
  456.             MEMF_PUBLIC | MEMF_NOCACHEPPC | MEMF_NOCACHEM68K
  457. #endif
  458.             );
  459.         break;
  460.     }
  461. //kprintf( "PPCMixBuffer: 0x%08lx (%ld)\n", audioctrl->ahiac_PPCMixBuffer, audioctrl->ac.ahiac_BuffSize );
  462.     audioctrl->ahiac_PPCMixInterrupt = AllocVec(
  463.         sizeof( struct Interrupt ),
  464.         MEMF_PUBLIC | MEMF_CLEAR );
  465.   }
  466.  
  467.   // Now link the list and fill in the channel number for each structure.
  468.  
  469.   if( audioctrl->ahiac_ChannelDatas != NULL &&
  470.       audioctrl->ahiac_SoundDatas != NULL &&
  471.       ( PPCObject == NULL || audioctrl->ahiac_PPCMixBuffer != NULL ) &&
  472.       ( PPCObject == NULL || audioctrl->ahiac_PPCMixInterrupt != NULL ) )
  473.   {
  474.     struct AHIChannelData *cd;
  475.     struct AHISoundData   *sd;
  476.     int                    i;
  477.  
  478.     cd = audioctrl->ahiac_ChannelDatas;
  479.  
  480.     audioctrl->ahiac_WetList = cd;
  481.     audioctrl->ahiac_DryList = NULL;
  482.  
  483.     for(i = 0; i < audioctrl->ac.ahiac_Channels - 1; i++)
  484.     {
  485.       // Set Channel No
  486.       cd->cd_ChannelNo = i;
  487.  
  488.       // Set link to next channel
  489.       cd->cd_Succ = cd + 1;
  490.       cd++;
  491.     }
  492.  
  493.     // Set the last No
  494.     cd->cd_ChannelNo = i;
  495.  
  496.     // Clear the last link;
  497.     cd->cd_Succ = NULL;
  498.  
  499.  
  500.     sd = audioctrl->ahiac_SoundDatas;
  501.  
  502.     for( i = 0; i < audioctrl->ac.ahiac_Sounds; i++)
  503.     {
  504.       sd->sd_Type = AHIST_NOTYPE;
  505.       sd++;
  506.     }
  507.  
  508.     if( PPCObject != NULL )
  509.     {
  510.       int r = ~0;
  511.  
  512.       r &= GetSymbol( AddByteMono     );
  513.       r &= GetSymbol( AddByteStereo   );
  514.       r &= GetSymbol( AddBytesMono    );
  515.       r &= GetSymbol( AddBytesStereo  );
  516.       r &= GetSymbol( AddWordMono     );
  517.       r &= GetSymbol( AddWordStereo   );
  518.       r &= GetSymbol( AddWordsMono    );
  519.       r &= GetSymbol( AddWordsStereo  );
  520.       r &= GetSymbol( AddByteMonoB    );
  521.       r &= GetSymbol( AddByteStereoB  );
  522.       r &= GetSymbol( AddBytesMonoB   );
  523.       r &= GetSymbol( AddBytesStereoB );
  524.       r &= GetSymbol( AddWordMonoB    );
  525.       r &= GetSymbol( AddWordStereoB  );
  526.       r &= GetSymbol( AddWordsMonoB   );
  527.       r &= GetSymbol( AddWordsStereoB );
  528.  
  529.       r &= GetSymbol( AddLofiByteMono     );
  530.       r &= GetSymbol( AddLofiByteStereo   );
  531.       r &= GetSymbol( AddLofiBytesMono    );
  532.       r &= GetSymbol( AddLofiBytesStereo  );
  533.       r &= GetSymbol( AddLofiWordMono     );
  534.       r &= GetSymbol( AddLofiWordStereo   );
  535.       r &= GetSymbol( AddLofiWordsMono    );
  536.       r &= GetSymbol( AddLofiWordsStereo  );
  537.       r &= GetSymbol( AddLofiByteMonoB    );
  538.       r &= GetSymbol( AddLofiByteStereoB  );
  539.       r &= GetSymbol( AddLofiBytesMonoB   );
  540.       r &= GetSymbol( AddLofiBytesStereoB );
  541.       r &= GetSymbol( AddLofiWordMonoB    );
  542.       r &= GetSymbol( AddLofiWordStereoB  );
  543.       r &= GetSymbol( AddLofiWordsMonoB   );
  544.       r &= GetSymbol( AddLofiWordsStereoB );
  545.  
  546.       // Sucess?
  547.  
  548.       if( r != 0 )
  549.       {
  550.         switch( MixBackend )
  551.         {
  552.           case MB_NATIVE:
  553.             Req( "Internal error: Illegal MixBackend in InitMixroutine()" );
  554.             break;
  555.  
  556.           case MB_POWERUP:
  557.             rc = TRUE;
  558.             break;
  559.  
  560.           case MB_WARPUP:
  561.           {
  562.             // Initialize the WarpUp side
  563.         
  564.             struct PPCArgs args = 
  565.             {
  566.               NULL,
  567.               0,
  568.               0,
  569.               NULL,
  570.               0,
  571.               { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  572.               { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }
  573.             };
  574.  
  575.             audioctrl->ahiac_PPCWarpUpContext = AHIAllocVec(
  576.                 sizeof( struct WarpUpContext ), 
  577.                 MEMF_PUBLIC | MEMF_CLEAR | MEMF_NOCACHEPPC | MEMF_NOCACHEM68K );
  578.  
  579.             if( audioctrl->ahiac_PPCWarpUpContext != NULL )
  580.             {
  581. #ifndef WARPUP_INVALIDATE_CACHE
  582.               audioctrl->ahiac_PPCWarpUpContext->MixBuffer = 
  583.                 AHIAllocVec( audioctrl->ac.ahiac_BuffSize,
  584.                              MEMF_PUBLIC );
  585.  
  586.               // Set a default value, just in case...
  587.  
  588.               audioctrl->ahiac_PPCWarpUpContext->MixLongWords = 
  589.                   ( audioctrl->ac.ahiac_BuffSize + 3 ) / 4;
  590.  
  591.               if( audioctrl->ahiac_PPCWarpUpContext->MixBuffer != NULL )
  592.               {
  593. #endif
  594.                 audioctrl->ahiac_PPCWarpUpContext->PowerPCBase = PowerPCBase;
  595.  
  596.                 args.PP_Regs[ 0 ] = (ULONG) audioctrl->ahiac_PPCWarpUpContext;
  597.  
  598.                 if( AHIGetELFSymbol( "InitWarpUp", &args.PP_Code ) )
  599.                 {
  600.                   if( RunPPC( &args ) == PPERR_SUCCESS )
  601.                   {
  602.                     rc = TRUE;
  603.                   }
  604.                   else
  605.                   {
  606.                     Req( "Call to InitWarpUp() failed." );
  607.                   }
  608.                 }
  609.                 else
  610.                 {
  611.                   Req( "Unable to fetch symbol 'InitWarpUp'." );
  612.                 }
  613. #ifndef WARPUP_INVALIDATE_CACHE
  614.               }
  615.               else
  616.               {
  617.                 Req( "Out of memory in InitMixroutine()." );
  618.               }
  619. #endif
  620.             }
  621.             else
  622.             {
  623.               Req( "Out of memory in InitMixroutine()." );
  624.             }
  625.  
  626.             break;
  627.           }
  628.         }
  629.  
  630.         if( rc )
  631.         {
  632.           audioctrl->ahiac_PPCMixInterrupt->is_Node.ln_Type = NT_INTERRUPT;
  633.           audioctrl->ahiac_PPCMixInterrupt->is_Node.ln_Pri  = 127;
  634.           audioctrl->ahiac_PPCMixInterrupt->is_Node.ln_Name = (STRPTR) DevName;
  635.           audioctrl->ahiac_PPCMixInterrupt->is_Data         = audioctrl;
  636.           audioctrl->ahiac_PPCMixInterrupt->is_Code         = (void(*)(void)) Interrupt;
  637.  
  638.           AddIntServer( INTB_PORTS, audioctrl->ahiac_PPCMixInterrupt );
  639.         }
  640.       }
  641.       else
  642.       {
  643.         Req( "Unable to fetch all symbols from ELF object." );
  644.       }
  645.     }
  646.     else // PPCObject
  647.     {
  648.       AddByteMonoPtr         = AddByteMono;
  649.       AddByteStereoPtr       = AddByteStereo;
  650.       AddBytesMonoPtr        = AddBytesMono;
  651.       AddBytesStereoPtr      = AddBytesStereo;
  652.       AddWordMonoPtr         = AddWordMono;
  653.       AddWordStereoPtr       = AddWordStereo;
  654.       AddWordsMonoPtr        = AddWordsMono;
  655.       AddWordsStereoPtr      = AddWordsStereo;
  656.       AddByteMonoBPtr        = AddByteMonoB;
  657.       AddByteStereoBPtr      = AddByteStereoB;
  658.       AddBytesMonoBPtr       = AddBytesMonoB;
  659.       AddBytesStereoBPtr     = AddBytesStereoB;
  660.       AddWordMonoBPtr        = AddWordMonoB;
  661.       AddWordStereoBPtr      = AddWordStereoB;
  662.       AddWordsMonoBPtr       = AddWordsMonoB;
  663.       AddWordsStereoBPtr     = AddWordsStereoB;
  664.  
  665.       AddLofiByteMonoPtr     = AddLofiByteMono;
  666.       AddLofiByteStereoPtr   = AddLofiByteStereo;
  667.       AddLofiBytesMonoPtr    = AddLofiBytesMono;
  668.       AddLofiBytesStereoPtr  = AddLofiBytesStereo;
  669.       AddLofiWordMonoPtr     = AddLofiWordMono;
  670.       AddLofiWordStereoPtr   = AddLofiWordStereo;
  671.       AddLofiWordsMonoPtr    = AddLofiWordsMono;
  672.       AddLofiWordsStereoPtr  = AddLofiWordsStereo;
  673.       AddLofiByteMonoBPtr    = AddLofiByteMonoB;
  674.       AddLofiByteStereoBPtr  = AddLofiByteStereoB;
  675.       AddLofiBytesMonoBPtr   = AddLofiBytesMonoB;
  676.       AddLofiBytesStereoBPtr = AddLofiBytesStereoB;
  677.       AddLofiWordMonoBPtr    = AddLofiWordMonoB;
  678.       AddLofiWordStereoBPtr  = AddLofiWordStereoB;
  679.       AddLofiWordsMonoBPtr   = AddLofiWordsMonoB;
  680.       AddLofiWordsStereoBPtr = AddLofiWordsStereoB;
  681.  
  682.       // Sucess!
  683.     
  684.       rc = TRUE;
  685.     }
  686.   }
  687.  
  688.   return rc;
  689. }
  690.  
  691. /******************************************************************************
  692. ** CleanUpMixroutine **********************************************************
  693. ******************************************************************************/
  694.  
  695. // This function is used to clean up after the mixer routine (called from 
  696. // AHI_FreeAudio()).
  697.  
  698. void
  699. CleanUpMixroutine( struct AHIPrivAudioCtrl *audioctrl )
  700. {
  701.   if( audioctrl->ahiac_PPCMixInterrupt != NULL )
  702.   {
  703.     RemIntServer( INTB_PORTS, audioctrl->ahiac_PPCMixInterrupt );
  704.   }
  705.  
  706.   switch( MixBackend )
  707.   {
  708.     case MB_NATIVE:
  709.     case MB_POWERUP:
  710.       break;
  711.  
  712.     case MB_WARPUP:
  713.     {
  714.       // Clean up the WarpUp side
  715.       
  716.       struct PPCArgs args = 
  717.       {
  718.         NULL,
  719.         0,
  720.         0,
  721.         NULL,
  722.         0,
  723.         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  724.         { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }
  725.       };
  726.  
  727.       if( audioctrl->ahiac_PPCWarpUpContext != NULL )
  728.       {
  729.         args.PP_Regs[ 0 ] = (ULONG) audioctrl->ahiac_PPCWarpUpContext;
  730.         
  731.         if( AHIGetELFSymbol( "CleanUpWarpUp", &args.PP_Code ) )
  732.         {
  733.           RunPPC( &args );
  734.         }
  735.         else
  736.         {
  737.           Req( "Unable to fetch symbol 'CleanUpWarpUp'." );
  738.         }
  739. #ifndef WARPUP_INVALIDATE_CACHE
  740.         AHIFreeVec( audioctrl->ahiac_PPCWarpUpContext->MixBuffer );
  741. #endif
  742.         AHIFreeVec( audioctrl->ahiac_PPCWarpUpContext );
  743.         audioctrl->ahiac_PPCWarpUpContext = NULL;
  744.       }
  745.  
  746.       break;
  747.     }
  748.   }
  749.  
  750.   FreeVec( audioctrl->ahiac_PPCMixInterrupt );
  751.   audioctrl->ahiac_PPCMixInterrupt = NULL;
  752.  
  753.   AHIFreeVec( audioctrl->ahiac_PPCMixBuffer );
  754.   audioctrl->ahiac_PPCMixBuffer = NULL;
  755.  
  756.   AHIFreeVec( audioctrl->ahiac_SoundDatas );
  757.   audioctrl->ahiac_SoundDatas = NULL;
  758.  
  759.   AHIFreeVec( audioctrl->ahiac_ChannelDatas );
  760.   audioctrl->ahiac_ChannelDatas = NULL;
  761. }
  762.  
  763. /******************************************************************************
  764. ** calcMasterVolumeTable ******************************************************
  765. ******************************************************************************/
  766.  
  767. // This function is called each time the master volume changes.
  768.  
  769. void
  770. calcMasterVolumeTable ( struct AHIPrivAudioCtrl *audioctrl )
  771. {
  772.   // Do nothing, no tables are used!
  773. }
  774.  
  775.  
  776. /******************************************************************************
  777. ** initSignedTable ************************************************************
  778. ******************************************************************************/
  779.  
  780. // This function sets up the multiplication tables used when mixing signed
  781. // samples.
  782.  
  783. BOOL
  784. initSignedTable ( struct AHIPrivAudioCtrl *audioctrl )
  785. {
  786.   // No tables are used, return success.
  787.   return TRUE;
  788. }
  789.  
  790.  
  791. /******************************************************************************
  792. ** calcSignedTable ************************************************************
  793. ******************************************************************************/
  794.  
  795. // This function is called each time the master volume changes
  796.  
  797. void
  798. calcSignedTable ( struct AHIPrivAudioCtrl *audioctrl )
  799. {
  800.   // Do nothing, no tables are used!
  801. }
  802.  
  803.  
  804. /******************************************************************************
  805. ** initUnsignedTable **********************************************************
  806. ******************************************************************************/
  807.  
  808. // This function sets up the multiplication tables used when mixing unsigned
  809. // samples (obsolete since V4, but kept for backward compability with
  810. // Delitracker II).
  811.  
  812. BOOL
  813. initUnsignedTable ( struct AHIPrivAudioCtrl *audioctrl )
  814. {
  815.   // No tables are used, return success.
  816.   return TRUE;
  817. }
  818.  
  819.  
  820. /******************************************************************************
  821. ** calcUnsignedTable **********************************************************
  822. ******************************************************************************/
  823.  
  824. // This function is called each time the master volume changes
  825.  
  826. void
  827. calcUnsignedTable ( struct AHIPrivAudioCtrl *audioctrl )
  828. {
  829.   // Do nothing, no tables are used!
  830. }
  831.  
  832.  
  833. /******************************************************************************
  834. ** SelectAddRoutine ***********************************************************
  835. ******************************************************************************/
  836.  
  837. // This routine gets called each time there is reason to believe that a new
  838. // add-routine should be used (new sound selected, volume changed,
  839. // mastervolume changed)
  840.  
  841. // Based on VolumeLeft, VolumeRight and SampleType, fill in ScaleLeft,
  842. // ScaleRight and AddRoutine.
  843.  
  844. void
  845. SelectAddRoutine ( Fixed     VolumeLeft,
  846.                    Fixed     VolumeRight,
  847.                    ULONG     SampleType,
  848.                    struct    AHIPrivAudioCtrl *audioctrl,
  849.                    LONG     *ScaleLeft,
  850.                    LONG     *ScaleRight,
  851.                    ADDFUNC **AddRoutine )
  852.  
  853. {
  854.   // This version only cares about the sample format and does not use any
  855.   // optimized add-routines.
  856.  
  857.   // Scale the volume
  858.  
  859.   VolumeLeft  = VolumeLeft  * (audioctrl->ahiac_MasterVolume >> 8) / 
  860.                               (audioctrl->ahiac_Channels2 << 8);
  861.  
  862.   VolumeRight = VolumeRight * (audioctrl->ahiac_MasterVolume >> 8) / 
  863.                               (audioctrl->ahiac_Channels2 << 8);
  864.  
  865.   // First, select HiFi or LoFi...
  866.  
  867.   if( audioctrl->ac.ahiac_Flags & AHIACF_HIFI )
  868.   {
  869.  
  870.     // Then, check the output format...
  871.  
  872.     switch(audioctrl->ac.ahiac_BuffType)
  873.     {
  874.  
  875.       case AHIST_M32S:
  876.  
  877.         // ...and then the source format.
  878.  
  879.         switch(SampleType)
  880.         {
  881.           case AHIST_M8S:
  882.           case AHIST_BW|AHIST_M8S:
  883.             *ScaleLeft  = VolumeLeft + VolumeRight;
  884.             *ScaleRight = 0;
  885.             if(SampleType & AHIST_BW)
  886.               *AddRoutine = AddByteMonoBPtr;
  887.             else
  888.               *AddRoutine = AddByteMonoPtr;
  889.             break;
  890.  
  891.           case AHIST_S8S:
  892.           case AHIST_BW|AHIST_S8S:
  893.             *ScaleLeft  = VolumeLeft;
  894.             *ScaleRight = VolumeRight;
  895.             if(SampleType & AHIST_BW)
  896.               *AddRoutine = AddBytesMonoBPtr;
  897.             else
  898.               *AddRoutine = AddBytesMonoPtr;
  899.             break;
  900.  
  901.           case AHIST_M16S:
  902.           case AHIST_BW|AHIST_M16S:
  903.             *ScaleLeft  = VolumeLeft + VolumeRight;
  904.             *ScaleRight = 0;
  905.             if(SampleType & AHIST_BW)
  906.               *AddRoutine = AddWordMonoBPtr;
  907.             else
  908.               *AddRoutine = AddWordMonoPtr;
  909.             break;
  910.  
  911.           case AHIST_S16S:
  912.           case AHIST_BW|AHIST_S16S:
  913.             *ScaleLeft  = VolumeLeft;
  914.             *ScaleRight = VolumeRight;
  915.             if(SampleType & AHIST_BW)
  916.               *AddRoutine = AddWordsMonoBPtr;
  917.             else
  918.               *AddRoutine = AddWordsMonoPtr;
  919.             break;
  920.  
  921.           default:
  922.             *ScaleLeft  = 0;
  923.             *ScaleRight = 0;
  924.             *AddRoutine = NULL;
  925.             break;
  926.         }
  927.         break;
  928.  
  929.       case AHIST_S32S:
  930.  
  931.         // ...and then the source format.
  932.  
  933.         switch(SampleType)
  934.         {
  935.           case AHIST_M8S:
  936.           case AHIST_BW|AHIST_M8S:
  937.             *ScaleLeft  = VolumeLeft;
  938.             *ScaleRight = VolumeRight;
  939.             if(SampleType & AHIST_BW)
  940.               *AddRoutine = AddByteStereoBPtr;
  941.             else
  942.               *AddRoutine = AddByteStereoPtr;
  943.             break;
  944.  
  945.           case AHIST_S8S:
  946.           case AHIST_BW|AHIST_S8S:
  947.             *ScaleLeft  = VolumeLeft;
  948.             *ScaleRight = VolumeRight;
  949.             if(SampleType & AHIST_BW)
  950.               *AddRoutine = AddBytesStereoBPtr;
  951.             else
  952.               *AddRoutine = AddBytesStereoPtr;
  953.             break;
  954.  
  955.           case AHIST_M16S:
  956.           case AHIST_BW|AHIST_M16S:
  957.             *ScaleLeft  = VolumeLeft;
  958.             *ScaleRight = VolumeRight;
  959.             if(SampleType & AHIST_BW)
  960.               *AddRoutine = AddWordStereoBPtr;
  961.             else
  962.               *AddRoutine = AddWordStereoPtr;
  963.             break;
  964.  
  965.           case AHIST_S16S:
  966.           case AHIST_BW|AHIST_S16S:
  967.             *ScaleLeft  = VolumeLeft;
  968.             *ScaleRight = VolumeRight;
  969.             if(SampleType & AHIST_BW)
  970.               *AddRoutine = AddWordsStereoBPtr;
  971.             else
  972.               *AddRoutine = AddWordsStereoPtr;
  973.             break;
  974.  
  975.           default:
  976.             *ScaleLeft  = 0;
  977.             *ScaleRight = 0;
  978.             *AddRoutine = NULL;
  979.             break;
  980.         }
  981.         break;
  982.  
  983.       default:
  984.         *ScaleLeft  = 0;
  985.         *ScaleRight = 0;
  986.         *AddRoutine = NULL;
  987.         break;
  988.     }
  989.   }
  990.   else
  991.   {
  992.  
  993.     // Then, check the output format...
  994.  
  995.     switch(audioctrl->ac.ahiac_BuffType)
  996.     {
  997.  
  998.       case AHIST_M16S:
  999.  
  1000.         // ...and then the source format.
  1001.  
  1002.         switch(SampleType)
  1003.         {
  1004.           case AHIST_M8S:
  1005.           case AHIST_BW|AHIST_M8S:
  1006.             *ScaleLeft  = VolumeLeft + VolumeRight;
  1007.             *ScaleRight = 0;
  1008.             if(SampleType & AHIST_BW)
  1009.               *AddRoutine = AddLofiByteMonoBPtr;
  1010.             else
  1011.               *AddRoutine = AddLofiByteMonoPtr;
  1012.             break;
  1013.  
  1014.           case AHIST_S8S:
  1015.           case AHIST_BW|AHIST_S8S:
  1016.             *ScaleLeft  = VolumeLeft;
  1017.             *ScaleRight = VolumeRight;
  1018.             if(SampleType & AHIST_BW)
  1019.               *AddRoutine = AddLofiBytesMonoBPtr;
  1020.             else
  1021.               *AddRoutine = AddLofiBytesMonoPtr;
  1022.             break;
  1023.  
  1024.           case AHIST_M16S:
  1025.           case AHIST_BW|AHIST_M16S:
  1026.             *ScaleLeft  = VolumeLeft + VolumeRight;
  1027.             *ScaleRight = 0;
  1028.             if(SampleType & AHIST_BW)
  1029.               *AddRoutine = AddLofiWordMonoBPtr;
  1030.             else
  1031.               *AddRoutine = AddLofiWordMonoPtr;
  1032.             break;
  1033.  
  1034.           case AHIST_S16S:
  1035.           case AHIST_BW|AHIST_S16S:
  1036.             *ScaleLeft  = VolumeLeft;
  1037.             *ScaleRight = VolumeRight;
  1038.             if(SampleType & AHIST_BW)
  1039.               *AddRoutine = AddLofiWordsMonoBPtr;
  1040.             else
  1041.               *AddRoutine = AddLofiWordsMonoPtr;
  1042.             break;
  1043.  
  1044.           default:
  1045.             *ScaleLeft  = 0;
  1046.             *ScaleRight = 0;
  1047.             *AddRoutine = NULL;
  1048.             break;
  1049.         }
  1050.         break;
  1051.  
  1052.       case AHIST_S16S:
  1053.  
  1054.         // ...and then the source format.
  1055.  
  1056.         switch(SampleType)
  1057.         {
  1058.           case AHIST_M8S:
  1059.           case AHIST_BW|AHIST_M8S:
  1060.             *ScaleLeft  = VolumeLeft;
  1061.             *ScaleRight = VolumeRight;
  1062.             if(SampleType & AHIST_BW)
  1063.               *AddRoutine = AddLofiByteStereoBPtr;
  1064.             else
  1065.               *AddRoutine = AddLofiByteStereoPtr;
  1066.             break;
  1067.  
  1068.           case AHIST_S8S:
  1069.           case AHIST_BW|AHIST_S8S:
  1070.             *ScaleLeft  = VolumeLeft;
  1071.             *ScaleRight = VolumeRight;
  1072.             if(SampleType & AHIST_BW)
  1073.               *AddRoutine = AddLofiBytesStereoBPtr;
  1074.             else
  1075.               *AddRoutine = AddLofiBytesStereoPtr;
  1076.             break;
  1077.  
  1078.           case AHIST_M16S:
  1079.           case AHIST_BW|AHIST_M16S:
  1080.             *ScaleLeft  = VolumeLeft;
  1081.             *ScaleRight = VolumeRight;
  1082.             if(SampleType & AHIST_BW)
  1083.               *AddRoutine = AddLofiWordStereoBPtr;
  1084.             else
  1085.               *AddRoutine = AddLofiWordStereoPtr;
  1086.             break;
  1087.  
  1088.           case AHIST_S16S:
  1089.           case AHIST_BW|AHIST_S16S:
  1090.             *ScaleLeft  = VolumeLeft;
  1091.             *ScaleRight = VolumeRight;
  1092.             if(SampleType & AHIST_BW)
  1093.               *AddRoutine = AddLofiWordsStereoBPtr;
  1094.             else
  1095.               *AddRoutine = AddLofiWordsStereoPtr;
  1096.             break;
  1097.  
  1098.           default:
  1099.             *ScaleLeft  = 0;
  1100.             *ScaleRight = 0;
  1101.             *AddRoutine = NULL;
  1102.             break;
  1103.         }
  1104.         break;
  1105.  
  1106.       default:
  1107.         *ScaleLeft  = 0;
  1108.         *ScaleRight = 0;
  1109.         *AddRoutine = NULL;
  1110.         break;
  1111.     }
  1112.   }
  1113. }
  1114.  
  1115. #endif /* !defined( VERSIONPPC ) */
  1116.  
  1117.  
  1118. /******************************************************************************
  1119. ** Mix ************************************************************************
  1120. ******************************************************************************/
  1121.  
  1122. // This is the function that the driver calls each time it want more data
  1123. // to play. 
  1124.  
  1125. // There is a stub function in asmfuncs.s called Mix() that saves d0-d1/a0-a1
  1126. // and calls MixGeneric. This stub is only assembled if VERSIONGEN is set.
  1127.  
  1128. #if !defined( VERSIONPPC )
  1129. void ASMCALL
  1130. MixGeneric ( REG(a0, struct Hook *Hook), 
  1131.              REG(a1, void *dst), 
  1132.              REG(a2, struct AHIPrivAudioCtrl *audioctrl) )
  1133. #else
  1134. void
  1135. MixGeneric ( struct Hook*             unused_Hook, 
  1136.              void*                    dst, 
  1137.              struct AHIPrivAudioCtrl* audioctrl )
  1138. #endif
  1139. {
  1140.   struct AHIChannelData    *cd;
  1141.   void                  *dstptr;
  1142.   LONG                   samplesleft;
  1143.  
  1144.   /* Clear the buffer */
  1145.  
  1146.   memset( dst, 0, audioctrl->ahiac_BuffSizeNow );
  1147.  
  1148.   /* Mix the samples */
  1149.  
  1150.   audioctrl->ahiac_WetOrDry = AHIEDM_WET;
  1151.  
  1152.   cd = audioctrl->ahiac_WetList;
  1153.  
  1154.   while(TRUE)
  1155.   {
  1156.     while(cd != NULL) // .nextchannel
  1157.     {
  1158.       samplesleft = audioctrl->ac.ahiac_BuffSamples;
  1159.       dstptr      = dst;
  1160.  
  1161.       while(TRUE) // .contchannel
  1162.       {
  1163.         LONG samples;
  1164.         LONG processed;
  1165.  
  1166.         /* Call Sound Hook */
  1167.  
  1168.         if(cd->cd_EOS)
  1169.         {
  1170.           cd->cd_EOS = FALSE;
  1171.           if(audioctrl->ac.ahiac_SoundFunc != NULL)
  1172.           {
  1173.             CallSoundHook( audioctrl, &cd->cd_ChannelNo );
  1174.           }
  1175.         }
  1176.  
  1177.         processed = 0;
  1178.  
  1179.         if( cd->cd_AntiClickCount > 0 && cd->cd_FreqOK && cd->cd_SoundOK )
  1180.         {
  1181.           // Sound is ok and we're looking for a zero-crossing.
  1182.  
  1183.           LONG try_samples;
  1184.  
  1185.           samples     = min( samplesleft, cd->cd_Samples );
  1186.           try_samples = min( samples, cd->cd_AntiClickCount );
  1187.  
  1188.           if( try_samples > 0 )
  1189.           {
  1190.             cd->cd_TempStartPointL = cd->cd_StartPointL;
  1191.             cd->cd_TempStartPointR = cd->cd_StartPointR;
  1192.  
  1193.             processed = ((ADDFUNC *) cd->cd_AddRoutine)( try_samples,
  1194.                                                          cd->cd_ScaleLeft,
  1195.                                                          cd->cd_ScaleRight,
  1196.                                                         &cd->cd_TempStartPointL,
  1197.                                                         &cd->cd_TempStartPointR,
  1198.                                                          cd->cd_DataStart,
  1199.                                                         &dstptr,
  1200.                                                          cd->cd_FirstOffsetI,
  1201.                                                          cd->cd_Add,
  1202.                                                         &cd->cd_Offset, 
  1203.                                                          TRUE );
  1204.             cd->cd_Samples -= processed;
  1205.             samplesleft    -= processed;
  1206.           }
  1207.           else
  1208.           {
  1209.             processed = 0;
  1210.           }
  1211.  
  1212.           if( try_samples == cd->cd_AntiClickCount ||
  1213.               processed != samples )
  1214.           {
  1215.             // We either found a zero-crossing or looked as far as
  1216.             // we were allowed to.
  1217.             
  1218.             // Note that the sample end was NOT reached! If it was,
  1219.             // cd_Samples will be zero and the second cd_AddRoutine
  1220.             // call below will have no effect, and the cd_Next#?
  1221.             // variables will be copied instead.
  1222.  
  1223.             // Now start the delayed sound.
  1224.  
  1225.             if( cd->cd_VolDelayed )
  1226.             {
  1227.               cd->cd_VolDelayed = FALSE;
  1228.               cd->cd_VolumeLeft  = cd->cd_DelayedVolumeLeft;
  1229.               cd->cd_VolumeRight = cd->cd_DelayedVolumeRight;
  1230.               cd->cd_ScaleLeft   = cd->cd_DelayedScaleLeft;
  1231.               cd->cd_ScaleRight  = cd->cd_DelayedScaleRight;
  1232.               cd->cd_AddRoutine  = cd->cd_DelayedAddRoutine;
  1233.             }
  1234.  
  1235.             if( cd->cd_FreqDelayed )
  1236.             {
  1237.               cd->cd_FreqDelayed = FALSE;
  1238.               cd->cd_FreqOK      = cd->cd_DelayedFreqOK;
  1239.               cd->cd_Add         = cd->cd_DelayedAdd;
  1240.               
  1241.               // Since we have advanced, cd_Samples must be recalculated!
  1242.               cd->cd_Samples     = CalcSamples( cd->cd_Add,
  1243.                                                 cd->cd_Type,
  1244.                                                 cd->cd_LastOffset,
  1245.                                                 cd->cd_Offset );
  1246.             }
  1247.  
  1248.             if( cd->cd_SoundDelayed )
  1249.             {
  1250.               cd->cd_SoundDelayed = FALSE;
  1251.  
  1252.               cd->cd_SoundOK       = cd->cd_DelayedSoundOK;
  1253.  
  1254.               cd->cd_Offset        = cd->cd_DelayedOffset;
  1255.               cd->cd_FirstOffsetI  = cd->cd_DelayedFirstOffsetI;
  1256.               cd->cd_LastOffset    = cd->cd_DelayedLastOffset;
  1257.               cd->cd_DataStart     = cd->cd_DelayedDataStart;
  1258.  
  1259.               cd->cd_Type          = cd->cd_DelayedType;
  1260.               cd->cd_AddRoutine    = cd->cd_DelayedAddRoutine;
  1261.  
  1262.               cd->cd_Samples       = cd->cd_DelayedSamples;
  1263.  
  1264.               cd->cd_ScaleLeft     = cd->cd_DelayedScaleLeft;
  1265.               cd->cd_ScaleRight    = cd->cd_DelayedScaleRight;
  1266.               cd->cd_AddRoutine    = cd->cd_DelayedAddRoutine;
  1267.             }
  1268.           }
  1269.  
  1270.           if( cd->cd_VolDelayed || cd->cd_FreqDelayed || cd->cd_SoundDelayed )
  1271.           {
  1272.             cd->cd_AntiClickCount -= processed;
  1273.           }
  1274.           else
  1275.           {
  1276.             cd->cd_AntiClickCount = 0;
  1277.           }
  1278.         }
  1279.  
  1280.         if( cd->cd_FreqOK && cd->cd_SoundOK )
  1281.         {
  1282.           // Sound is still ok, let's rock'n roll.
  1283.  
  1284.           samples = min( samplesleft, cd->cd_Samples );
  1285.  
  1286.           if( samples > 0 )
  1287.           {
  1288.             cd->cd_TempStartPointL = cd->cd_StartPointL;
  1289.             cd->cd_TempStartPointR = cd->cd_StartPointR;
  1290.  
  1291.             processed = ((ADDFUNC *) cd->cd_AddRoutine)( samples,
  1292.                                                          cd->cd_ScaleLeft,
  1293.                                                          cd->cd_ScaleRight,
  1294.                                                         &cd->cd_TempStartPointL,
  1295.                                                         &cd->cd_TempStartPointR,
  1296.                                                          cd->cd_DataStart,
  1297.                                                         &dstptr,
  1298.                                                          cd->cd_FirstOffsetI,
  1299.                                                          cd->cd_Add,
  1300.                                                         &cd->cd_Offset,
  1301.                                                          FALSE );
  1302.             cd->cd_Samples -= processed;
  1303.             samplesleft    -= processed;
  1304.           }
  1305.  
  1306.           if( cd->cd_Samples == 0 )
  1307.           {
  1308.             /* Linear interpol. stuff */
  1309.  
  1310.             cd->cd_StartPointL = cd->cd_TempStartPointL;
  1311.             cd->cd_StartPointR = cd->cd_TempStartPointR;
  1312.  
  1313.             /*
  1314.             ** Offset always points OUTSIDE the sample after this
  1315.             ** call.  Ie, if we read a sample at offset (Offset.I)
  1316.             ** now, it does not belong to the sample just played.
  1317.             ** This is true for both backward and forward mixing.
  1318.             */
  1319.  
  1320.  
  1321.             /* What we do now is to calculate how much futher we have
  1322.                advanced. */
  1323.  
  1324.               cd->cd_Offset -= cd->cd_LastOffset;
  1325.  
  1326.             /*
  1327.             ** Offset should now be added to the NEXT Offset. Offset
  1328.             ** is positive of the sample was mixed forwards, and
  1329.             ** negative if the sample was mixed backwards.  There is
  1330.             ** one catch, however.  If the direction is about to
  1331.             ** change now, Offset should instead be SUBTRACTED.
  1332.             ** Let's check:
  1333.             */
  1334.  
  1335.             if( (cd->cd_Type ^ cd->cd_NextType) & AHIST_BW )
  1336.             {
  1337.               cd->cd_Offset = -cd->cd_Offset;
  1338.             }
  1339.  
  1340.             cd->cd_Offset += cd->cd_NextOffset;
  1341.  
  1342.             cd->cd_FirstOffsetI = cd->cd_Offset >> 32;
  1343.  
  1344.             /*
  1345.             ** But what if the next sample is so short that we just
  1346.             ** passed it!?  Here is the nice part.  CalcSamples
  1347.             ** checks this, and sets cd_Samples to 0 in that case.
  1348.             ** And the add routines doesn't do anything when asked to
  1349.             ** mix 0 samples.  Assume we have passed a sample with 4
  1350.             ** samples, and the next one is only 3.  CalcSamples
  1351.             ** returns 0.  The (ADDFUNC) call above does not do
  1352.             ** anything at all, OffsetI is still 4.  Now we subtract
  1353.             ** LastOffsetI, which is 3.  Result:  We have passed the
  1354.             ** sample with 1.  And guess what?  That's in range.
  1355.             */
  1356.  
  1357.             /* Now, let's copy the rest of the cd_Next#? stuff... */
  1358.  
  1359.             cd->cd_FreqOK        = cd->cd_NextFreqOK;
  1360.             cd->cd_SoundOK       = cd->cd_NextSoundOK;
  1361.             cd->cd_Add           = cd->cd_NextAdd;
  1362.             cd->cd_DataStart     = cd->cd_NextDataStart;
  1363.             cd->cd_LastOffset    = cd->cd_NextLastOffset;
  1364.             cd->cd_ScaleLeft     = cd->cd_NextScaleLeft;
  1365.             cd->cd_ScaleRight    = cd->cd_NextScaleRight;
  1366.             cd->cd_AddRoutine    = cd->cd_NextAddRoutine;
  1367.             cd->cd_VolumeLeft    = cd->cd_NextVolumeLeft;
  1368.             cd->cd_VolumeRight   = cd->cd_NextVolumeRight;
  1369.             cd->cd_Type          = cd->cd_NextType;
  1370.  
  1371.             cd->cd_Samples = CalcSamples( cd->cd_Add,
  1372.                                           cd->cd_Type,
  1373.                                           cd->cd_LastOffset,
  1374.                                           cd->cd_Offset );
  1375.  
  1376.             /* Also update all cd_Delayed#? stuff */
  1377.  
  1378.             if( !cd->cd_VolDelayed )
  1379.             {
  1380.               cd->cd_DelayedVolumeLeft    = cd->cd_NextVolumeLeft;
  1381.               cd->cd_DelayedVolumeRight   = cd->cd_NextVolumeRight;
  1382.             }
  1383.  
  1384.             if( !cd->cd_FreqDelayed )
  1385.             {
  1386.               cd->cd_DelayedFreqOK        = cd->cd_NextFreqOK;
  1387.               cd->cd_DelayedAdd           = cd->cd_NextAdd;
  1388.             }
  1389.  
  1390.             if( !cd->cd_SoundDelayed )
  1391.             {
  1392.               cd->cd_DelayedSoundOK       = cd->cd_NextSoundOK;
  1393.               cd->cd_DelayedOffset        = cd->cd_NextOffset;
  1394.               cd->cd_DelayedFirstOffsetI  = cd->cd_FirstOffsetI;  // See above
  1395.               cd->cd_DelayedLastOffset    = cd->cd_NextLastOffset;
  1396.               cd->cd_DelayedType          = cd->cd_NextType;
  1397.               cd->cd_DelayedDataStart     = cd->cd_NextDataStart;
  1398.             }
  1399.  
  1400.             if( !cd->cd_VolDelayed && !cd->cd_SoundDelayed )
  1401.             {
  1402.               cd->cd_DelayedScaleLeft     = cd->cd_NextScaleLeft;
  1403.               cd->cd_DelayedScaleRight    = cd->cd_NextScaleRight;
  1404.               cd->cd_DelayedAddRoutine    = cd->cd_NextAddRoutine;
  1405.             }
  1406.  
  1407.             if( !cd->cd_FreqDelayed && !cd->cd_SoundDelayed )
  1408.             {
  1409.               cd->cd_DelayedSamples       = cd->cd_Samples;
  1410.             }
  1411.  
  1412.             cd->cd_EOS = TRUE;      // signal End-Of-Sample
  1413.             continue;               // .contchannel (same channel, new sound)
  1414.           }
  1415.         } // FreqOK && SoundOK
  1416.         break; // .contchannel
  1417.  
  1418.       } // while(TRUE)
  1419.  
  1420.       cd = cd->cd_Succ;
  1421.     } // while(cd)
  1422.  
  1423.     if(audioctrl->ahiac_WetOrDry == AHIEDM_WET)
  1424.     {
  1425.       audioctrl->ahiac_WetOrDry = AHIEDM_DRY;
  1426.  
  1427.       /*** AHIET_DSPECHO ***/
  1428.       if(audioctrl->ahiac_EffDSPEchoStruct != NULL)
  1429.       {
  1430.         audioctrl->ahiac_EffDSPEchoStruct->ahiecho_Code(
  1431.             audioctrl->ahiac_EffDSPEchoStruct, dst, audioctrl);
  1432.       }
  1433.  
  1434.       cd = audioctrl->ahiac_DryList;
  1435.  
  1436.       if(audioctrl->ac.ahiac_Flags & AHIACF_POSTPROC)
  1437.       {
  1438.         /*** AHIET_MASTERVOLUME ***/
  1439.  
  1440.         DoMasterVolume(dst, audioctrl);
  1441.  
  1442.         /*
  1443.         ** When AHIACB_POSTPROC is set, the dry data shall be placed
  1444.         ** immediate after the wet data. This is done by modifying the
  1445.         ** dst pointer
  1446.         */
  1447.  
  1448.         dst = (char *) dst + audioctrl->ac.ahiac_BuffSamples * 
  1449.                              InternalSampleFrameSize(audioctrl->ac.ahiac_BuffType);
  1450.       }
  1451.  
  1452.       continue; /* while(TRUE) */
  1453.     }
  1454.     else
  1455.     {
  1456.       break; /* while(TRUE) */
  1457.     }
  1458.   } // while(TRUE)
  1459.  
  1460.   /*** AHIET_MASTERVOLUME ***/
  1461.  
  1462.   DoMasterVolume(dst, audioctrl);
  1463.  
  1464. #if !defined( VERSIONPPC )
  1465.  
  1466.   // This is handled in m68k code, in order to minimize cache flushes.
  1467.  
  1468.   /*** AHIET_OUTPUTBUFFER ***/
  1469.  
  1470.   DoOutputBuffer(dst, audioctrl);
  1471.  
  1472.   /*** AHIET_CHANNELINFO ***/
  1473.  
  1474.   DoChannelInfo(audioctrl);
  1475.  
  1476. #endif /* !defined( VERSIONPPC ) */
  1477.  
  1478.   return;
  1479. }
  1480.  
  1481. /*
  1482. ** This function would be better if it was written in assembler,
  1483. ** since overflow could then be detected. Instead we reduce the
  1484. ** number of bits to 20 and then scale and compare.
  1485. */
  1486.  
  1487. static void
  1488. DoMasterVolume ( void *buffer,
  1489.                  struct AHIPrivAudioCtrl *audioctrl )
  1490. {
  1491.   int   cnt;
  1492.   LONG  vol;
  1493.   LONG  sample;
  1494.  
  1495.   cnt = audioctrl->ac.ahiac_BuffSamples;
  1496.  
  1497.   switch(audioctrl->ac.ahiac_BuffType)
  1498.   {
  1499.  
  1500.     case AHIST_M16S:
  1501.     case AHIST_M32S:
  1502.       break;
  1503.  
  1504.     case AHIST_S16S:
  1505.     case AHIST_S32S:
  1506.       cnt *= 2;
  1507.       break;
  1508.  
  1509.     default:
  1510.       return; // Panic
  1511.   }
  1512.  
  1513.   if( audioctrl->ac.ahiac_BuffType == AHIST_M32S
  1514.       || audioctrl->ac.ahiac_BuffType == AHIST_S32S )
  1515.   {
  1516.     LONG *dst = buffer;
  1517.  
  1518.     vol = audioctrl->ahiac_SetMasterVolume >> 8;
  1519.  
  1520.     while(cnt > 0)
  1521.     {
  1522.       cnt--;
  1523.     
  1524.       sample = (*dst >> 12) * vol;
  1525.  
  1526.       if(sample > (LONG) 0x07ffffff)
  1527.         sample = 0x07ffffff;
  1528.       else if(sample < (LONG) 0xf8000000)
  1529.         sample = 0xf8000000;
  1530.  
  1531.       *dst++ = sample << 4;
  1532.     }
  1533.   }
  1534.   else
  1535.   {
  1536.     WORD *dst = buffer;
  1537.  
  1538.     vol = audioctrl->ahiac_SetMasterVolume >> 4;
  1539.  
  1540.     while(cnt > 0)
  1541.     {
  1542.       cnt--;
  1543.     
  1544.       sample = *dst * vol;
  1545.  
  1546.       if(sample > (LONG) 0x07ffffff)
  1547.         sample = 0x07ffffff;
  1548.       else if(sample < (LONG) 0xf8000000)
  1549.         sample = 0xf8000000;
  1550.  
  1551.       *dst++ = sample >> 12;
  1552.     }
  1553.   
  1554.   }
  1555. }
  1556.  
  1557.  
  1558. #if !defined( VERSIONPPC )
  1559.  
  1560. static void
  1561. DoOutputBuffer ( void *buffer,
  1562.                  struct AHIPrivAudioCtrl *audioctrl )
  1563. {
  1564.   struct AHIEffOutputBuffer *ob;
  1565.  
  1566.   ob = audioctrl->ahiac_EffOutputBufferStruct;
  1567.  
  1568.   if(ob != NULL)
  1569.   {
  1570.     ob->ahieob_Buffer = buffer;
  1571.     ob->ahieob_Length = audioctrl->ac.ahiac_BuffSamples;
  1572.     ob->ahieob_Type   = audioctrl->ac.ahiac_BuffType;
  1573.  
  1574.     CallHookPkt( ob->ahieob_Func,
  1575.                  audioctrl,
  1576.                  ob);
  1577.   }
  1578. }
  1579.  
  1580. static void
  1581. DoChannelInfo ( struct AHIPrivAudioCtrl *audioctrl )
  1582. {
  1583.   struct AHIEffChannelInfo *ci;
  1584.   struct AHIChannelData    *cd;
  1585.   ULONG                    *offsets;
  1586.  
  1587.   ci = audioctrl->ahiac_EffChannelInfoStruct;
  1588.  
  1589.   if(ci != NULL)
  1590.   {
  1591.     int i;
  1592.     
  1593.     cd      = audioctrl->ahiac_ChannelDatas;
  1594.     offsets = ci->ahieci_Offset;
  1595.  
  1596.     for(i = ci->ahieci_Channels; i > 0; i--)
  1597.     {
  1598.       *offsets++ = cd->cd_Offset >> 32;
  1599.       cd++;
  1600.     }
  1601.     
  1602.     CallHookPkt( ci->ahieci_Func,
  1603.                  audioctrl,
  1604.                  ci );
  1605.   }
  1606. }
  1607.  
  1608. #endif /* !defined( VERSIONPPC ) */
  1609.  
  1610.  
  1611. /******************************************************************************
  1612. ** CalcSamples ****************************************************************
  1613. ******************************************************************************/
  1614.  
  1615. LONG
  1616. CalcSamples ( Fixed64 Add,
  1617.               ULONG   Type,
  1618.               Fixed64 LastOffset,
  1619.               Fixed64 Offset )
  1620.  
  1621. {
  1622.   Fixed64 len;
  1623.  
  1624.   if( Type & AHIST_BW )
  1625.   {
  1626.     len = Offset - LastOffset; 
  1627.   }
  1628.   else
  1629.   {
  1630.     len = LastOffset - Offset;
  1631.   }
  1632.  
  1633.   if(len < 0 || Add == 0) return 0; // Error!
  1634.  
  1635.   return (LONG) ( len / Add ) + 1;
  1636. }
  1637.  
  1638.