home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / bbs / termv4.6 / extras / source / term-source.lha / Sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  23.2 KB  |  1,174 lines

  1. /*
  2. **    Sound.c
  3. **
  4. **    Sound support routines
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #ifndef _GLOBAL_H
  11. #include "Global.h"
  12. #endif
  13.  
  14.     /* Double buffering chunk size. */
  15.  
  16. #define BUFFER_SIZE    32768
  17.  
  18.     /* Maximum replay volume. */
  19.  
  20. #define MAX_VOLUME    64
  21.  
  22.     /* Stereo/channel sample type. */
  23.  
  24. typedef LONG        SampleType;
  25.  
  26.     /* Channel definitions. */
  27.  
  28. #define SAMPLE_LEFT    2
  29. #define SAMPLE_RIGHT    4
  30. #define SAMPLE_STEREO    6
  31.  
  32.     /* A fixed-point value, 16 bits to the left of
  33.      * the point and 16 to the right. A Fixed is a
  34.      * number of 2**16ths, i.e. 65536ths.
  35.      */
  36.  
  37. typedef LONG        Fixed;
  38.  
  39.     /* Unity = Fixed 1.0 = maximum volume */
  40.  
  41. #define Unity        0x10000L
  42.  
  43.     /* Sample compression modes. */
  44.  
  45. #define sCmpNone    0
  46. #define sCmpFibDelta    1
  47.  
  48.     /* The voice header. */
  49.  
  50. typedef struct
  51. {
  52.     ULONG    oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  53.         repeatHiSamples,    /* # samples in the high octave repeat part */
  54.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  55.     UWORD    samplesPerSec;        /* data sampling rate */
  56.     UBYTE    ctOctave,        /* # of octaves of waveforms */
  57.         sCompression;        /* data compression technique used */
  58.     Fixed    volume;            /* playback nominal volume from 0 to Unity
  59.                      * (full volume). Map this value into
  60.                      * the output hardware's dynamic range.
  61.                      */
  62. } Voice8Header;
  63.  
  64.     /* Double-buffering information. */
  65.  
  66. struct BufferInfo
  67. {
  68.     LONG    Size;
  69.     UBYTE    Buffer[BUFFER_SIZE];
  70. };
  71.  
  72.     /* Sound replay information. */
  73.  
  74. struct SoundInfo
  75. {
  76.     UBYTE         Name[MAX_FILENAME_LENGTH];
  77.  
  78.     ULONG         Rate,
  79.              Length,
  80.              Volume;
  81.  
  82.     APTR         SoundData;
  83.  
  84.     APTR         LeftData,
  85.              RightData;
  86.  
  87.     Object        *SoundObject;
  88.     struct timeval     SoundTime;
  89. };
  90.  
  91.     /* Local data. */
  92.  
  93. STATIC BOOL             SoundInitialized;
  94. STATIC struct SignalSemaphore     SoundSemaphore;
  95. STATIC struct SoundInfo        *SoundSlot[SOUND_COUNT];
  96.  
  97.     /* DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst):
  98.      *
  99.      *    Unpack Fibonacci-delta-encoded data.
  100.      */
  101.  
  102. STATIC VOID
  103. DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst)
  104. {
  105.     STATIC BYTE CodeToDelta[16] = { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };
  106.  
  107.     BYTE    Value = (BYTE)Src[1];
  108.     UBYTE    Code;
  109.  
  110.         /* Skip the header information. */
  111.  
  112.     Src    += 2;
  113.     Size    -= 2;
  114.  
  115.         /* Run down the chunk... */
  116.  
  117.     while(Size--)
  118.     {
  119.         Code = *Src++;
  120.  
  121.             /* Add the top nibble delta. */
  122.  
  123.         Value += CodeToDelta[Code >> 4];
  124.  
  125.         *Dst++ = Value;
  126.  
  127.             /* Add the bottom nibble delta. */
  128.  
  129.         Value += CodeToDelta[Code & 0xF];
  130.  
  131.         *Dst++ = Value;
  132.     }
  133. }
  134.  
  135.     /* FreeSound(struct SoundInfo *SoundInfo):
  136.      *
  137.      *    Free sound handle and associated data.
  138.      */
  139.  
  140. VOID
  141. FreeSound(struct SoundInfo *SoundInfo)
  142. {
  143.     if(SoundInfo->SoundObject)
  144.         DisposeDTObject(SoundInfo->SoundObject);
  145.     else
  146.         FreeVecPooled(SoundInfo->SoundData);
  147.  
  148.     FreeVecPooled(SoundInfo);
  149. }
  150.  
  151.     /* LoadSound(STRPTR Name):
  152.      *
  153.      *    Load a sound file from disk.
  154.      */
  155.  
  156. struct SoundInfo *
  157. LoadSound(STRPTR Name,BOOL Warn)
  158. {
  159.     struct SoundInfo    *SoundInfo = NULL;
  160.     struct IFFHandle    *Handle;
  161.  
  162.         /* Allocate IFF handle for reading. */
  163.  
  164.     if(Handle = AllocIFF())
  165.     {
  166.             /* Open a standard DOS stream. */
  167.  
  168.         if(Handle->iff_Stream = Open(Name,MODE_OLDFILE))
  169.         {
  170.                 /* Say it's a DOS stream. */
  171.  
  172.             InitIFFasDOS(Handle);
  173.  
  174.                 /* Open the file for reading. */
  175.  
  176.             if(!OpenIFF(Handle,IFFF_READ))
  177.             {
  178.                 LONG SoundStops[3 * 2] =
  179.                 {
  180.                     ID_8SVX,ID_VHDR,
  181.                     ID_8SVX,ID_CHAN,
  182.                     ID_8SVX,ID_BODY
  183.                 };
  184.  
  185.                     /* Mark the chunks to stop at. */
  186.  
  187.                 if(!StopChunks(Handle,SoundStops,3))
  188.                 {
  189.                     struct ContextNode    *Chunk;
  190.                     Voice8Header         Header;
  191.                     UBYTE             Compression;
  192.                     SampleType         Channel    = SAMPLE_STEREO;
  193.                     BOOL             SingleChannel    = TRUE;
  194.  
  195.                         /* Clear the voice header. */
  196.  
  197.                     memset(&Header,0,sizeof(Voice8Header));
  198.  
  199.                         /* Scan for data... */
  200.  
  201.                     while(!ParseIFF(Handle,IFFPARSE_SCAN))
  202.                     {
  203.                         Chunk = CurrentChunk(Handle);
  204.  
  205.                             /* What did we find? */
  206.  
  207.                         switch(Chunk->cn_ID)
  208.                         {
  209.                                 /* Looks like the basic voice header. */
  210.  
  211.                             case ID_VHDR:
  212.  
  213.                                     /* Read the header. */
  214.  
  215.                                 if(ReadChunkRecords(Handle,&Header,MIN(Chunk->cn_Size,sizeof(Voice8Header)),1) == 1)
  216.                                 {
  217.                                         /* Compression type supported? */
  218.  
  219.                                     if(Header.sCompression == sCmpNone || Header.sCompression == sCmpFibDelta)
  220.                                     {
  221.                                             /* Allocate the sound handle. */
  222.  
  223.                                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  224.                                         {
  225.                                                 /* Install the rate, volume and length. */
  226.  
  227.                                             SoundInfo->Rate        = SysBase->ex_EClockFrequency * 5 / Header.samplesPerSec;
  228.                                             SoundInfo->Length    = Header.oneShotHiSamples ? Header.oneShotHiSamples : (Header.repeatHiSamples ? Header.repeatHiSamples : Header.samplesPerHiCycle);
  229.                                             SoundInfo->Volume    = (SoundConfig.Volume * ((Header.volume * MAX_VOLUME) / Unity)) / 100;
  230.  
  231.                                                 /* Remember compression mode. */
  232.  
  233.                                             Compression        = Header.sCompression;
  234.                                         }
  235.                                     }
  236.                                 }
  237.  
  238.                                 break;
  239.  
  240.                                 /* Looks like sound channel information. */
  241.  
  242.                             case ID_CHAN:
  243.  
  244.                                     /* Do we have a handle to manage it? */
  245.  
  246.                                 if(SoundInfo)
  247.                                 {
  248.                                         /* Read the channel information. */
  249.  
  250.                                     if(ReadChunkRecords(Handle,&Channel,MIN(Chunk->cn_Size,sizeof(SampleType)),1) == 1)
  251.                                     {
  252.                                             /* Stereo sound file? */
  253.  
  254.                                         if(Channel == SAMPLE_STEREO)
  255.                                             SingleChannel = FALSE;
  256.                                     }
  257.                                     else
  258.                                     {
  259.                                         FreeVecPooled(SoundInfo);
  260.  
  261.                                         SoundInfo = NULL;
  262.                                     }
  263.                                 }
  264.  
  265.                                 break;
  266.  
  267.                                 /* Looks like the sound body data. */
  268.  
  269.                             case ID_BODY:
  270.  
  271.                                     /* Do we have sound handle to manage it? */
  272.  
  273.                                 if(SoundInfo)
  274.                                 {
  275.                                     BOOL Success = FALSE;
  276.  
  277.                                     if(!SoundInfo->Length)
  278.                                         SoundInfo->Length = Chunk->cn_Size;
  279.  
  280.                                         /* Uncompressed raw data? */
  281.  
  282.                                     if(Compression == sCmpNone)
  283.                                     {
  284.                                         ULONG Wanted;
  285.  
  286.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  287.                                         {
  288.                                             Wanted = SoundInfo->Length * 2;
  289.  
  290.                                             if(Wanted > Chunk->cn_Size)
  291.                                             {
  292.                                                 SoundInfo->Length /= 2;
  293.  
  294.                                                 Wanted = SoundInfo->Length * 2;
  295.                                             }
  296.                                         }
  297.                                         else
  298.                                             Wanted = SoundInfo->Length;
  299.  
  300.                                         if(Chunk->cn_Size >= Wanted)
  301.                                         {
  302.                                                 /* Allocate a buffer. */
  303.  
  304.                                             if(SoundInfo->SoundData = AllocVecPooled(Wanted,MEMF_ANY))
  305.                                             {
  306.                                                     /* Read the data. */
  307.  
  308.                                                 if(ReadChunkRecords(Handle,SoundInfo->SoundData,Wanted,1) == 1)
  309.                                                     Success = TRUE;
  310.                                                 else
  311.                                                     FreeVecPooled(SoundInfo->SoundData);
  312.                                             }
  313.                                         }
  314.                                     }
  315.                                     else
  316.                                     {
  317.                                         ULONG Wanted;
  318.  
  319.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  320.                                         {
  321.                                             Wanted = SoundInfo->Length + 4;
  322.  
  323.                                             if(Wanted > Chunk->cn_Size)
  324.                                             {
  325.                                                 SoundInfo->Length /= 2;
  326.  
  327.                                                 Wanted = SoundInfo->Length * 2 + 4;
  328.  
  329.                                                 SingleChannel = TRUE;
  330.                                             }
  331.                                         }
  332.                                         else
  333.                                             Wanted = SoundInfo->Length / 2 + 2;
  334.  
  335.                                         if(Chunk->cn_Size >= Wanted)
  336.                                         {
  337.                                             UBYTE    *TempBuffer;
  338.  
  339.                                                 /* Allocate a temporary decompression buffer. */
  340.  
  341.                                             if(TempBuffer = (UBYTE *)AllocVecPooled(Chunk->cn_Size,MEMF_ANY))
  342.                                             {
  343.                                                     /* Read the compressed data. */
  344.  
  345.                                                 if(ReadChunkRecords(Handle,TempBuffer,Chunk->cn_Size,1) == 1)
  346.                                                 {
  347.                                                     ULONG Length = SoundInfo->Length;
  348.  
  349.                                                         /* Allocate space for the uncompressed data. */
  350.  
  351.                                                     if(SoundInfo->SoundData = AllocVecPooled(Length * 2,MEMF_ANY))
  352.                                                     {
  353.                                                             /* Stereo sound file? */
  354.  
  355.                                                         if(!SingleChannel && Channel == SAMPLE_STEREO)
  356.                                                         {
  357.                                                             UBYTE *Data = SoundInfo->SoundData;
  358.  
  359.                                                                 /* Unpack the stereo sound. */
  360.  
  361.                                                             DeltaUnpack(TempBuffer,                 Length / 2 + 2,Data);
  362.                                                             DeltaUnpack(TempBuffer + Length / 2 + 2,Length / 2 + 2,Data + Length);
  363.                                                         }
  364.                                                         else
  365.                                                         {
  366.                                                                 /* Unpack the mono sound. */
  367.  
  368.                                                             DeltaUnpack(TempBuffer,Length / 2 + 2,SoundInfo->SoundData);
  369.                                                         }
  370.  
  371.                                                         Success = TRUE;
  372.                                                     }
  373.                                                 }
  374.  
  375.                                                 FreeVecPooled(TempBuffer);
  376.                                             }
  377.                                         }
  378.                                     }
  379.  
  380.                                     if(!Success)
  381.                                     {
  382.                                         FreeVecPooled(SoundInfo);
  383.  
  384.                                         SoundInfo = NULL;
  385.                                     }
  386.                                 }
  387.  
  388.                                 break;
  389.                         }
  390.                     }
  391.  
  392.                         /* Did we get what we wanted? */
  393.  
  394.                     if(SoundInfo)
  395.                     {
  396.                             /* Any sound data allocated? */
  397.  
  398.                         if(SoundInfo->SoundData)
  399.                         {
  400.                             UBYTE *Data = SoundInfo->SoundData;
  401.  
  402.                                 /* Which kind of sound file did
  403.                                  * we read?
  404.                                  */
  405.  
  406.                             switch(Channel)
  407.                             {
  408.                                     /* Left channel only. */
  409.  
  410.                                 case SAMPLE_LEFT:
  411.  
  412.                                     SoundInfo->LeftData = Data;
  413.                                     break;
  414.  
  415.                                     /* Right channel only. */
  416.  
  417.                                 case SAMPLE_RIGHT:
  418.  
  419.                                     SoundInfo->RightData = Data;
  420.                                     break;
  421.  
  422.                                     /* Two stereo channels. */
  423.  
  424.                                 case SAMPLE_STEREO:
  425.  
  426.                                         /* One sound mapped to two voices. */
  427.  
  428.                                     if(SingleChannel)
  429.                                         SoundInfo->LeftData = SoundInfo->RightData = Data;
  430.                                     else
  431.                                     {
  432.                                             /* Split the voice data. */
  433.  
  434.                                         SoundInfo->LeftData    = Data;
  435.                                         SoundInfo->RightData    = Data + SoundInfo->Length;
  436.                                     }
  437.  
  438.                                     break;
  439.                             }
  440.                         }
  441.                         else
  442.                         {
  443.                             FreeVecPooled(SoundInfo);
  444.  
  445.                             SoundInfo = NULL;
  446.                         }
  447.                     }
  448.                 }
  449.  
  450.                 CloseIFF(Handle);
  451.             }
  452.  
  453.             Close(Handle->iff_Stream);
  454.         }
  455.  
  456.         FreeIFF(Handle);
  457.     }
  458.  
  459.         /* Successful? */
  460.  
  461.     if(SoundInfo)
  462.         strcpy(SoundInfo->Name,Name);
  463.     else
  464.     {
  465.         if(DataTypesBase)
  466.         {
  467.             Object *Sound;
  468.  
  469.             if(Sound = NewDTObject(Name,
  470.                 DTA_SourceType,    DTST_FILE,
  471.                 DTA_GroupID,    GID_SOUND,
  472.                 SDTA_Volume,    (SoundConfig.Volume * MAX_VOLUME) / 100,
  473.                 SDTA_Cycles,    1,
  474.             TAG_DONE))
  475.             {
  476.                 ULONG             SampleLength    = 0;
  477.                 struct VoiceHeader    *Header        = NULL;
  478.  
  479.                 if(GetDTAttrs(Sound,
  480.                     SDTA_SampleLength,    &SampleLength,
  481.                     SDTA_VoiceHeader,    &Header,
  482.                 TAG_DONE) == 2)
  483.                 {
  484.                     if(SampleLength && Header)
  485.                     {
  486.                         ULONG Secs,Micro,Period;
  487.  
  488.                         Period    = Header->vh_SamplesPerSec;
  489.  
  490.                         Secs    = SampleLength / Period;
  491.                         Micro    = (1000000 / Period) * (SampleLength % Period);
  492.  
  493.                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  494.                         {
  495.                             strcpy(SoundInfo->Name,Name);
  496.  
  497.                             SoundInfo->SoundObject        = Sound;
  498.                             SoundInfo->SoundTime.tv_secs    = Secs;
  499.                             SoundInfo->SoundTime.tv_micro    = Micro;
  500.  
  501.                             return(SoundInfo);
  502.                         }
  503.                     }
  504.                 }
  505.  
  506.                 DisposeDTObject(Sound);
  507.             }
  508.         }
  509.  
  510.         if(Warn)
  511.             ShowRequest(Window,LocaleString(MSG_TERMSOUND_COULD_NOT_LOAD_SOUND_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);
  512.     }
  513.  
  514.     return(SoundInfo);
  515. }
  516.  
  517.     /* ReplaySound():
  518.      *
  519.      *    Replay sound with given information (doubly-buffered).
  520.      */
  521.  
  522. STATIC VOID
  523. ReplaySound(struct SoundInfo *SoundInfo,struct IOAudio *SoundControlRequest,struct IOAudio *SoundRequestLeft,struct IOAudio *SoundRequestRight,struct BufferInfo *BufferInfo)
  524. {
  525.     UBYTE    *Left    = SoundInfo->LeftData,
  526.         *Right    = SoundInfo->RightData;
  527.     ULONG     Size    = SoundInfo->Length,Length;
  528.     LONG     Base    = 0;
  529.  
  530.     Length = MIN(BUFFER_SIZE,Size);
  531.  
  532.     Size -= Length;
  533.  
  534.         /* Left channel available? */
  535.  
  536.     if(!(((ULONG)SoundRequestLeft->ioa_Request.io_Unit) & (LEFT0F | LEFT1F)))
  537.         Left = NULL;
  538.  
  539.         /* Right channel available? */
  540.  
  541.     if(!(((ULONG)SoundRequestRight->ioa_Request.io_Unit) & (RIGHT0F | RIGHT1F)))
  542.         Right = NULL;
  543.  
  544.         /* Fill up left buffer. */
  545.  
  546.     if(Left)
  547.     {
  548.         CopyMem(Left,BufferInfo[Base].Buffer,Length);
  549.  
  550.         BufferInfo[Base].Size = Length;
  551.  
  552.         Left += Length;
  553.     }
  554.  
  555.         /* Fill up right buffer. */
  556.  
  557.     if(Right)
  558.     {
  559.         CopyMem(Right,BufferInfo[Base + 2].Buffer,Length);
  560.  
  561.         BufferInfo[Base + 2].Size = Length;
  562.  
  563.         Right += Length;
  564.     }
  565.  
  566.         /* Process sound data. */
  567.  
  568.     do
  569.     {
  570.             /* Block both channels. */
  571.  
  572.         SoundControlRequest->ioa_Request.io_Command = CMD_STOP;
  573.  
  574.         SendIO(SoundControlRequest);
  575.         WaitIO(SoundControlRequest);
  576.  
  577.             /* Any data for the left channel? */
  578.  
  579.         if(Left)
  580.         {
  581.             SoundRequestLeft->ioa_Request.io_Command    = CMD_WRITE;
  582.             SoundRequestLeft->ioa_Request.io_Flags        = ADIOF_PERVOL;
  583.             SoundRequestLeft->ioa_Period            = SoundInfo->Rate;
  584.             SoundRequestLeft->ioa_Volume            = SoundInfo->Volume;
  585.             SoundRequestLeft->ioa_Cycles            = 1;
  586.             SoundRequestLeft->ioa_Data            = BufferInfo[Base].Buffer;
  587.             SoundRequestLeft->ioa_Length            = BufferInfo[Base].Size;
  588.  
  589.                 /* Get the left channel going. */
  590.  
  591.             BeginIO(SoundRequestLeft);
  592.         }
  593.  
  594.             /* Any data for the right channel? */
  595.  
  596.         if(Right)
  597.         {
  598.             SoundRequestRight->ioa_Request.io_Command    = CMD_WRITE;
  599.             SoundRequestRight->ioa_Request.io_Flags        = ADIOF_PERVOL;
  600.             SoundRequestRight->ioa_Period            = SoundInfo->Rate;
  601.             SoundRequestRight->ioa_Volume            = SoundInfo->Volume;
  602.             SoundRequestRight->ioa_Cycles            = 1;
  603.             SoundRequestRight->ioa_Data            = BufferInfo[Base + 2].Buffer;
  604.             SoundRequestRight->ioa_Length            = BufferInfo[Base + 2].Size;
  605.  
  606.                 /* Get the right channel going. */
  607.  
  608.             BeginIO(SoundRequestRight);
  609.         }
  610.  
  611.             /* Start up both channels synchronously... */
  612.  
  613.         SoundControlRequest->ioa_Request.io_Command = CMD_START;
  614.  
  615.         SendIO(SoundControlRequest);
  616.         WaitIO(SoundControlRequest);
  617.  
  618.             /* Grab the other buffers. */
  619.  
  620.         Base ^= 1;
  621.  
  622.             /* Still any data left? */
  623.  
  624.         if(Size)
  625.         {
  626.                 /* Cut off the next slice. */
  627.  
  628.             Length = MIN(BUFFER_SIZE,Size);
  629.  
  630.             Size -= Length;
  631.  
  632.                 /* Left channel available? */
  633.  
  634.             if(Left)
  635.             {
  636.                 CopyMem(Left,BufferInfo[Base].Buffer,Length);
  637.  
  638.                 BufferInfo[Base].Size = Length;
  639.  
  640.                 Left += Length;
  641.             }
  642.  
  643.                 /* Right channel available? */
  644.  
  645.             if(Right)
  646.             {
  647.                 CopyMem(Right,BufferInfo[Base + 2].Buffer,Length);
  648.  
  649.                 BufferInfo[Base + 2].Size = Length;
  650.  
  651.                 Right += Length;
  652.             }
  653.  
  654.                 /* Last slice eaten? */
  655.  
  656.             if(!Size)
  657.             {
  658.                     /* Wait for sounds to terminate. */
  659.  
  660.                 if(Left)
  661.                     WaitIO(SoundRequestLeft);
  662.  
  663.                 if(Right)
  664.                     WaitIO(SoundRequestRight);
  665.  
  666.                     /* Block both channels. */
  667.  
  668.                 SoundControlRequest->ioa_Request.io_Command = CMD_STOP;
  669.  
  670.                 SendIO(SoundControlRequest);
  671.                 WaitIO(SoundControlRequest);
  672.  
  673.                     /* Any data for the left channel? */
  674.  
  675.                 if(Left)
  676.                 {
  677.                     SoundRequestLeft->ioa_Request.io_Command    = CMD_WRITE;
  678.                     SoundRequestLeft->ioa_Request.io_Flags        = ADIOF_PERVOL;
  679.                     SoundRequestLeft->ioa_Period            = SoundInfo->Rate;
  680.                     SoundRequestLeft->ioa_Volume            = SoundInfo->Volume;
  681.                     SoundRequestLeft->ioa_Cycles            = 1;
  682.                     SoundRequestLeft->ioa_Data            = BufferInfo[Base].Buffer;
  683.                     SoundRequestLeft->ioa_Length            = BufferInfo[Base].Size;
  684.  
  685.                         /* Get the left channel going. */
  686.  
  687.                     BeginIO(SoundRequestLeft);
  688.                 }
  689.  
  690.                     /* Any data for the right channel? */
  691.  
  692.                 if(Right)
  693.                 {
  694.                     SoundRequestRight->ioa_Request.io_Command    = CMD_WRITE;
  695.                     SoundRequestRight->ioa_Request.io_Flags        = ADIOF_PERVOL;
  696.                     SoundRequestRight->ioa_Period            = SoundInfo->Rate;
  697.                     SoundRequestRight->ioa_Volume            = SoundInfo->Volume;
  698.                     SoundRequestRight->ioa_Cycles            = 1;
  699.                     SoundRequestRight->ioa_Data            = BufferInfo[Base + 2].Buffer;
  700.                     SoundRequestRight->ioa_Length            = BufferInfo[Base + 2].Size;
  701.  
  702.                         /* Get the right channel going. */
  703.  
  704.                     BeginIO(SoundRequestRight);
  705.                 }
  706.  
  707.                     /* Start up both channels synchronously... */
  708.  
  709.                 SoundControlRequest->ioa_Request.io_Command = CMD_START;
  710.  
  711.                 SendIO(SoundControlRequest);
  712.                 WaitIO(SoundControlRequest);
  713.             }
  714.         }
  715.  
  716.             /* Wait for sounds to terminate. */
  717.  
  718.         if(Left)
  719.             WaitIO(SoundRequestLeft);
  720.  
  721.         if(Right)
  722.             WaitIO(SoundRequestRight);
  723.     }
  724.     while(Size);
  725. }
  726.  
  727.     /* PlaySound(struct SoundInfo *SoundInfo):
  728.      *
  729.      *    Replay a sound.
  730.      */
  731.  
  732. VOID
  733. PlaySound(struct SoundInfo *SoundInfo)
  734. {
  735.     if(SoundInfo->SoundObject)
  736.     {
  737.         struct MsgPort *SoundTimePort;
  738.  
  739.         if(SoundTimePort = CreateMsgPort())
  740.         {
  741.             struct timerequest *SoundTimeRequest;
  742.  
  743.             if(SoundTimeRequest = (struct timerequest *)CreateIORequest(SoundTimePort,sizeof(struct timerequest)))
  744.             {
  745.                 if(!OpenDevice(TIMERNAME,UNIT_VBLANK,SoundTimeRequest,NULL))
  746.                 {
  747.                     SoundTimeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  748.                     SoundTimeRequest->tr_time        = SoundInfo->SoundTime;
  749.  
  750.                     SetSignal(0,PORTMASK(SoundTimePort));
  751.  
  752.                     SendIO(SoundTimeRequest);
  753.  
  754.                     DoMethod(SoundInfo->SoundObject,DTM_TRIGGER,NULL,STM_PLAY,NULL);
  755.  
  756.                     WaitIO(SoundTimeRequest);
  757.  
  758.                     CloseDevice(SoundTimeRequest);
  759.                 }
  760.  
  761.                 DeleteIORequest(SoundTimeRequest);
  762.             }
  763.  
  764.             DeleteMsgPort(SoundTimePort);
  765.         }
  766.     }
  767.     else
  768.     {
  769.         struct BufferInfo *BufferInfo;
  770.  
  771.             /* Allocate sound buffers. */
  772.  
  773.         if(BufferInfo = (struct BufferInfo *)AllocVec(4 * sizeof(struct BufferInfo),MEMF_CHIP))
  774.         {
  775.             struct MsgPort *SoundPort;
  776.  
  777.                 /* Allocate an io replyport. */
  778.  
  779.             if(SoundPort = CreateMsgPort())
  780.             {
  781.                 struct IOAudio *SoundControlRequest;
  782.  
  783.                     /* Allocate the big sound control request. */
  784.  
  785.                 if(SoundControlRequest = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  786.                 {
  787.                     struct IOAudio *SoundRequestLeft;
  788.  
  789.                         /* Allocate the left channel sound request. */
  790.  
  791.                     if(SoundRequestLeft = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  792.                     {
  793.                         struct IOAudio *SoundRequestRight;
  794.  
  795.                             /* Allocate the right channel sound request. */
  796.  
  797.                         if(SoundRequestRight = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  798.                         {
  799.                             STATIC UBYTE TwoChannels[] =
  800.                             {
  801.                                 LEFT0F | RIGHT0F,
  802.                                 LEFT0F | RIGHT1F,
  803.                                 LEFT1F | RIGHT0F,
  804.                                 LEFT1F | RIGHT1F
  805.                             };
  806.  
  807.                             STATIC UBYTE LeftChannel[] =
  808.                             {
  809.                                 LEFT0F,
  810.                                 LEFT1F
  811.                             };
  812.  
  813.                             STATIC UBYTE RightChannel[] =
  814.                             {
  815.                                 RIGHT0F,
  816.                                 RIGHT1F
  817.                             };
  818.  
  819.                             UBYTE    *AllocationMap;
  820.                             LONG     AllocationSize;
  821.  
  822.                                 /* Determine the correct channel
  823.                                  * allocation map.
  824.                                  */
  825.  
  826.                             if(SoundInfo->LeftData)
  827.                             {
  828.                                 if(SoundInfo->RightData)
  829.                                 {
  830.                                     AllocationMap    = TwoChannels;
  831.                                     AllocationSize    = sizeof(TwoChannels);
  832.                                 }
  833.                                 else
  834.                                 {
  835.                                     AllocationMap    = LeftChannel;
  836.                                     AllocationSize    = sizeof(LeftChannel);
  837.                                 }
  838.                             }
  839.                             else
  840.                             {
  841.                                 AllocationMap    = RightChannel;
  842.                                 AllocationSize    = sizeof(RightChannel);
  843.                             }
  844.  
  845.                                 /* Set up for sound channel allocation. */
  846.  
  847.                             SoundControlRequest->ioa_Request.io_Message.mn_Node.ln_Pri    = 127;
  848.                             SoundControlRequest->ioa_Request.io_Command            = ADCMD_ALLOCATE;
  849.                             SoundControlRequest->ioa_Request.io_Flags            = ADIOF_NOWAIT | ADIOF_PERVOL;
  850.                             SoundControlRequest->ioa_Data                    = AllocationMap;
  851.                             SoundControlRequest->ioa_Length                    = AllocationSize;
  852.  
  853.                                 /* Open audio.device, allocating the sound
  854.                                  * channels on the fly.
  855.                                  */
  856.  
  857.                             if(!OpenDevice(AUDIONAME,NULL,SoundControlRequest,NULL))
  858.                             {
  859.                                     /* Clone the sound control request. */
  860.  
  861.                                 CopyMem(SoundControlRequest,SoundRequestLeft,    sizeof(struct IOAudio));
  862.                                 CopyMem(SoundControlRequest,SoundRequestRight,    sizeof(struct IOAudio));
  863.  
  864.                                     /* Separate the channels. */
  865.  
  866.                                 SoundRequestLeft ->ioa_Request.io_Unit = (struct Unit *)((ULONG)SoundRequestLeft ->ioa_Request.io_Unit & (LEFT0F  | LEFT1F));
  867.                                 SoundRequestRight->ioa_Request.io_Unit = (struct Unit *)((ULONG)SoundRequestRight->ioa_Request.io_Unit & (RIGHT0F | RIGHT1F));
  868.  
  869.                                     /* Replay the sound... */
  870.  
  871.                                 ReplaySound(SoundInfo,SoundControlRequest,SoundRequestLeft,SoundRequestRight,BufferInfo);
  872.  
  873.                                     /* Do the big cleanup. */
  874.  
  875.                                 CloseDevice(SoundControlRequest);
  876.                             }
  877.  
  878.                             DeleteIORequest(SoundRequestRight);
  879.                         }
  880.  
  881.                         DeleteIORequest(SoundRequestLeft);
  882.                     }
  883.  
  884.                     DeleteIORequest(SoundControlRequest);
  885.                 }
  886.  
  887.                 DeleteMsgPort(SoundPort);
  888.             }
  889.  
  890.             FreeVec(BufferInfo);
  891.         }
  892.     }
  893. }
  894.  
  895.     /* SoundLoad(LONG Sound,BOOL Warn):
  896.      *
  897.      *    Loads or frees a sound slot.
  898.      */
  899.  
  900. STATIC BOOL
  901. SoundLoad(LONG Sound,BOOL Warn)
  902. {
  903.     struct SoundInfo    **Info = &SoundSlot[Sound];
  904.     STRPTR            Name;
  905.     BOOL            Success = FALSE;
  906.  
  907.         /* Which sound file name are we to pick? */
  908.  
  909.     switch(Sound)
  910.     {
  911.         case SOUND_BELL:
  912.  
  913.             Name = SoundConfig.BellFile;
  914.             break;
  915.  
  916.         case SOUND_CONNECT:
  917.  
  918.             Name = SoundConfig.ConnectFile;
  919.             break;
  920.  
  921.         case SOUND_DISCONNECT:
  922.  
  923.             Name = SoundConfig.DisconnectFile;
  924.             break;
  925.  
  926.         case SOUND_GOODTRANSFER:
  927.  
  928.             Name = SoundConfig.GoodTransferFile;
  929.             break;
  930.  
  931.         case SOUND_BADTRANSFER:
  932.  
  933.             Name = SoundConfig.BadTransferFile;
  934.             break;
  935.  
  936.         case SOUND_RING:
  937.  
  938.             Name = SoundConfig.RingFile;
  939.             break;
  940.  
  941.         case SOUND_VOICE:
  942.  
  943.             Name = SoundConfig.VoiceFile;
  944.             break;
  945.  
  946.         case SOUND_ERROR:
  947.  
  948.             Name = SoundConfig.ErrorNotifyFile;
  949.             break;
  950.     }
  951.  
  952.         /* Is a file name available? */
  953.  
  954.     if(Name[0])
  955.     {
  956.             /* Sound slot already initialized? */
  957.  
  958.         if(*Info)
  959.         {
  960.                 /* Did the file name change? */
  961.  
  962.             if(Stricmp((*Info)->Name,Name))
  963.             {
  964.                     /* Free the sound slot. */
  965.  
  966.                 FreeSound(*Info);
  967.  
  968.                     /* Try to load the sound slot. */
  969.  
  970.                 if(*Info = LoadSound(Name,Warn))
  971.                 {
  972.                         /* Remember the file name. */
  973.  
  974.                     strcpy((*Info)->Name,Name);
  975.  
  976.                     Success = TRUE;
  977.                 }
  978.             }
  979.             else
  980.                 Success = TRUE;
  981.         }
  982.         else
  983.         {
  984.                 /* Try to load the sound slot. */
  985.  
  986.             if(*Info = LoadSound(Name,Warn))
  987.             {
  988.                     /* Remember the file name. */
  989.  
  990.                 strcpy((*Info)->Name,Name);
  991.  
  992.                 Success = TRUE;
  993.             }
  994.         }
  995.     }
  996.     else
  997.     {
  998.             /* Does the slot still contain any sound? */
  999.  
  1000.         if(*Info)
  1001.         {
  1002.                 /* Free the slot. */
  1003.  
  1004.             FreeSound(*Info);
  1005.  
  1006.             *Info = NULL;
  1007.         }
  1008.  
  1009.         Success = TRUE;
  1010.     }
  1011.  
  1012.     return(Success);
  1013. }
  1014.  
  1015.     /* SoundServer(VOID):
  1016.      *
  1017.      *    Replay a sound.
  1018.      */
  1019.  
  1020. STATIC VOID __saveds
  1021. SoundServer(VOID)
  1022. {
  1023.     struct Task *Me;
  1024.  
  1025.     Me = FindTask(NULL);
  1026.  
  1027.         // Wait for wakeup call
  1028.  
  1029.     Wait(SIGBREAKF_CTRL_F);
  1030.  
  1031.         /* Get exclusive access to the sound slots. */
  1032.  
  1033.     ObtainSemaphore(&SoundSemaphore);
  1034.  
  1035.         /* Replay the sound. */
  1036.  
  1037.     PlaySound(SoundSlot[(LONG)Me->tc_UserData]);
  1038.  
  1039.     Forbid();
  1040.  
  1041.         /* Release access to the sound slots. */
  1042.  
  1043.     ReleaseSemaphore(&SoundSemaphore);
  1044. }
  1045.  
  1046.     /* SoundExit():
  1047.      *
  1048.      *    Free allocated sound resources.
  1049.      */
  1050.  
  1051. VOID
  1052. SoundExit()
  1053. {
  1054.     LONG i;
  1055.  
  1056.     if(SoundInitialized)
  1057.         ObtainSemaphore(&SoundSemaphore);
  1058.  
  1059.         /* Free the slots. */
  1060.  
  1061.     for(i = 0 ; i < SOUND_COUNT ; i++)
  1062.     {
  1063.         if(SoundSlot[i])
  1064.         {
  1065.             FreeSound(SoundSlot[i]);
  1066.  
  1067.             SoundSlot[i] = NULL;
  1068.         }
  1069.     }
  1070.  
  1071.     if(SoundInitialized)
  1072.         ReleaseSemaphore(&SoundSemaphore);
  1073. }
  1074.  
  1075.     /* SoundInit():
  1076.      *
  1077.      *    Allocate resources required for sound replaying.
  1078.      */
  1079.  
  1080. VOID
  1081. SoundInit()
  1082. {
  1083.         /* Sound access semaphore available? */
  1084.  
  1085.     if(!SoundInitialized)
  1086.     {
  1087.         InitSemaphore(&SoundSemaphore);
  1088.         SoundInitialized = TRUE;
  1089.     }
  1090.  
  1091.         /* Preload sounds if necessary. */
  1092.  
  1093.     if(SoundConfig.Preload)
  1094.     {
  1095.         LONG i;
  1096.  
  1097.         for(i = 0 ; i < SOUND_COUNT ; i++)
  1098.             SoundLoad(i,TRUE);
  1099.     }
  1100. }
  1101.  
  1102.     /* SoundPlay(LONG Sound):
  1103.      *
  1104.      *    Play a certain sound slot.
  1105.      */
  1106.  
  1107. VOID
  1108. SoundPlay(LONG Sound)
  1109. {
  1110.         /* Sound access semaphore available? */
  1111.  
  1112.     if(SoundInitialized)
  1113.     {
  1114.         if(SoundConfig.Volume)
  1115.         {
  1116.                 /* Check to see if we are currently playing a
  1117.                  * sound.
  1118.                  */
  1119.  
  1120.             if(!AttemptSemaphore(&SoundSemaphore))
  1121.                 return;
  1122.             else
  1123.                 ReleaseSemaphore(&SoundSemaphore);
  1124.  
  1125.                 /* Release any other sound if necessary. */
  1126.  
  1127.             if(!SoundConfig.Preload)
  1128.             {
  1129.                 LONG i;
  1130.  
  1131.                 for(i = 0 ; i < SOUND_COUNT ; i++)
  1132.                 {
  1133.                     if(i != Sound && SoundSlot[i])
  1134.                     {
  1135.                         FreeSound(SoundSlot[i]);
  1136.  
  1137.                         SoundSlot[i] = NULL;
  1138.                     }
  1139.                 }
  1140.             }
  1141.  
  1142.                 /* Load the sound slot. */
  1143.  
  1144.             SoundLoad(Sound,FALSE);
  1145.  
  1146.                 /* Slot filled? */
  1147.  
  1148.             if(SoundSlot[Sound])
  1149.             {
  1150.                 struct Task    *SoundTask;
  1151.                 LONG         Pri = ThisProcess->pr_Task.tc_Node.ln_Pri + 10;
  1152.  
  1153.                     /* Priority raised, check for limit. */
  1154.  
  1155.                 if(Pri > 127)
  1156.                     Pri = 127;
  1157.  
  1158.                     /* Fire off the sound server task. */
  1159.  
  1160.                 if(SoundTask = CreateTask("term Sound Task",Pri,SoundServer,4000))
  1161.                 {
  1162.                     SoundTask->tc_UserData = (APTR)Sound;
  1163.  
  1164.                     Signal(SoundTask,SIGBREAKF_CTRL_F);
  1165.                 }
  1166.             }
  1167.             else
  1168.                 Beep();
  1169.         }
  1170.     }
  1171.     else
  1172.         Beep();
  1173. }
  1174.