home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 600-699 / ff631.lha / KeyBang / Source / KeyBang.c < prev    next >
C/C++ Source or Header  |  1992-04-06  |  19KB  |  661 lines

  1. /******************************************************************************\
  2. *                                    KeyBang                                   *
  3. *                                    -------                                   *
  4. *                                 by Mike Stark                                *
  5. * Revisions:                                                                   *
  6. *   1.0 30 Mar 92 Added patterns, removed floating point math, added intro     *
  7. *                 window, improved input handler and added command options.    *
  8. *   0.9 23 Feb 92 Added the input handler so that keybanging would get the key *
  9. *                 events before intuition.                                     *
  10. *   0.8           Made PAL/NTSC independent.                                   *
  11. *   0.7           Added the ability to play random sounds.                     *
  12. *   0.?           Original version (Shapes in response to intuition events)    *
  13. * Credits:                                                                     *
  14. *     Michael Balzer (balzer@heike.informatik.uni-dortmund.de), the author of  *
  15. *      "Bomber" for a C example of how to use the audio device.             *
  16. *     Carolyn Scheppner of CATS for "OneKey" which is a concise example of how *
  17. *      to install and use an input handler.                                 *
  18. \******************************************************************************/
  19.  
  20. #include "KeyBang.h"
  21. #include "table.h"
  22.  
  23. char *version = "\0$VER: KeyBang 1.0 by Mike Stark (March 30, 1992)";
  24.  
  25. #define VECTORS 30
  26. #define CLOCK 3579545
  27. #define FORM 0x464f524d
  28. #define BODY 0x424f4459
  29. #define VHDR 0x56484452
  30. #define EIGHT_SVX 0x38535658
  31. #define SOUNDDIRNAME "Sounds:"
  32.  
  33. extern void BabyInputHandler();
  34.  
  35. SHORT ColorTable[16] =
  36. {
  37.   0x0000, 0x0eca, 0x0c00, 0x0f60, 0x0090, 0x03f1, 0x000f, 0x02cd, 0x0f0c,
  38.   0x0a0f, 0x0950, 0x0fe0, 0x0fff, 0x0ccc, 0x0888, 0x0444
  39. };
  40.  
  41. #define PATTERNS 6
  42.  
  43. USHORT PatternData[] =
  44. {
  45. /* Solid */
  46.   0xffff,
  47. /* Brick */
  48.   0x0101, 0x0101, 0x0101, 0xff01, 0x0101, 0x0101, 0x0101, 0x01ff,
  49. /* Grid */
  50.   0xffff, 0x0303, 0x0303, 0x0303,
  51. /* Diagonal lines */
  52.   0xf0f0, 0x3c3c, 0x0f0f, 0xc3c3,
  53. /* Other diagonal lines */
  54.   0x0f0f, 0x3c3c, 0xf0f0, 0xc3c3,
  55. /* Other brick pattern */
  56.   0x0300, 0x0300, 0x0300, 0xffff, 0x0003, 0x0003, 0x0003, 0xffff
  57. };
  58.  
  59. struct PatternInfo
  60. {
  61.   int Power;
  62.   USHORT *Data;
  63. } Patterns[PATTERNS] = 
  64. {
  65.   {0, &PatternData[0]},
  66.   {3, &PatternData[1]},
  67.   {2, &PatternData[9]},
  68.   {2, &PatternData[13]},
  69.   {2, &PatternData[17]},
  70.   {3, &PatternData[21]}
  71. };
  72.  
  73. #define MESSAGELINES 8
  74.  
  75. char *Message[] =
  76. {
  77.   "KeyBang 1.0",
  78.   "by Mike Stark",
  79.   "March 30, 1992",
  80.   "",
  81.   "--> Alt-Alt-F5 exits <--",
  82.   "",
  83.   "This program is shareware.",
  84.   "Please read KeyBang.doc."
  85. };
  86.  
  87. char *ScreenTitle = "KeyBang";
  88. struct IntuitionBase *IntuitionBase = NULL;
  89. struct GfxBase *GfxBase = NULL;
  90. struct Screen *BabyScreen = NULL;
  91. struct Window *BabyWindow = NULL, *IntroWindow = NULL;
  92. struct Remember *MemList = NULL;
  93. BYTE *BabyTmpRaster = NULL;
  94. APTR OldWindow;
  95. struct IOAudio *AudioMsg = NULL;
  96. struct MsgPort *IOReplyPort = NULL;
  97. struct MsgPort *KeyPort = NULL;
  98. struct IOStdReq *InputRequest = NULL;
  99. struct Interrupt HandlerInfo;
  100. struct SoundInfo **Sound;
  101. int Depth = 4;
  102. int Sounds = 0;
  103. int HandlerData[2];
  104. int LeftSoundPlaying = FALSE, RightSoundPlaying = FALSE;
  105. int WinX = 640, WinY = 200, XDPM, YDPM;
  106. int Unit[2];
  107. BOOL Audio = FALSE, OneShape = FALSE;
  108.  
  109. main(argc, argv)
  110. int argc;
  111. char **argv;
  112.  
  113. {
  114.   struct MyInputEvent *Message;
  115.   struct IntuiMessage *IMessage;
  116.   struct IOAudio *SoundMsg;
  117.   int Type, XSize, YSize, X, Y, Signal, Sample, SampleUnit;
  118.   BOOL Done, DoAction, Mouse;
  119.   int Count = 0, Seed, Pattern, Colors;
  120.  
  121.   GetOptions(argc, argv);
  122.  
  123.   Initialize();
  124.  
  125.   Colors = 1 << Depth;
  126.  
  127.   Signal = 1 << KeyPort->mp_SigBit;
  128.   Signal |= 1 << IOReplyPort->mp_SigBit;
  129.   Signal |= 1 << BabyWindow->UserPort->mp_SigBit;
  130.  
  131.   Done = FALSE;
  132.   while (!Done)
  133.   {
  134.     DoAction = FALSE;
  135.     Wait(Signal);
  136.     if (Audio)
  137.       while (SoundMsg = (struct IOAudio *)GetMsg(IOReplyPort))
  138.       {
  139.     SampleUnit = (int)SoundMsg->ioa_Request.io_Unit;
  140.     if (SampleUnit & 9)
  141.       RightSoundPlaying = FALSE;
  142.     if (SampleUnit & 6)
  143.       LeftSoundPlaying = FALSE;
  144.         FreeMem(SoundMsg, sizeof(struct IOAudio)); 
  145.       }
  146.     while (Message = (struct MyInputEvent *)GetMsg(KeyPort))
  147.     {
  148.       if (Message->IE.ie_Class == IECLASS_RAWKEY)
  149.       {
  150.     if (!((Message->IE.ie_Code & IECODE_UP_PREFIX) ||
  151.           (Message->IE.ie_Qualifier & IEQUALIFIER_REPEAT)))
  152.     {
  153.       DoAction = TRUE;
  154.       Mouse = FALSE;
  155.     }
  156.     if (Message->IE.ie_Code == 0x45)
  157.     {
  158.       Erase(BabyWindow->RPort);
  159.     }
  160.     if ((Message->IE.ie_Code == 0x54) &&
  161.         ((Message->IE.ie_Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  162.          == (IEQUALIFIER_LALT | IEQUALIFIER_RALT)))
  163.     {
  164.       DoAction = FALSE;
  165.       Done = TRUE;
  166.     }
  167.       }
  168.       FreeMem(Message, sizeof(struct MyInputEvent));
  169.     }
  170.     while (IMessage = (struct IntuiMessage *)GetMsg(BabyWindow->UserPort))
  171.     {
  172.       if (!(IMessage->Code & IECODE_UP_PREFIX))
  173.       {
  174.     Mouse = TRUE;
  175.     X = IMessage->MouseX;  Y = IMessage->MouseY;
  176.     YSize = Random(0) / 505 + 10;
  177.     XSize = 2 * YSize * XDPM / YDPM;
  178.     if (X < XSize) X = XSize;  if (Y < YSize) Y = YSize;
  179.     if (X > WinX - XSize) X = WinX - XSize;
  180.     if (Y > WinY - YSize) Y = WinY - YSize;
  181.     DoAction = TRUE;
  182.       }
  183.       ReplyMsg(IMessage);
  184.     }
  185.     if (DoAction)
  186.     {
  187.       if (IntroWindow)
  188.       {
  189.     CloseWindow(IntroWindow);
  190.     IntroWindow= NULL;
  191.     (void)Random(Seed);
  192.     SetDrMd(BabyWindow->RPort, JAM2);
  193.       }
  194.       if (OneShape) Erase(BabyWindow->RPort);
  195.       Sample = Random(0) * Sounds / 32768;
  196.       if (Audio) MakeSound(Sample);
  197.       if (!Mouse)
  198.       {
  199.     YSize = Random(0) / 505 + 10;
  200.     XSize = 2 * YSize * XDPM / YDPM;
  201.     Y = Random(0) * (WinY - 2 * YSize) / 32768 + YSize;
  202.     X = Random(0) * (WinX - 2 * XSize) / 32768 + XSize;
  203.       }
  204.       Pattern = Random(0) * PATTERNS / 32768;
  205.       SetAfPt(BabyWindow->RPort, Patterns[Pattern].Data, Patterns[Pattern].Power);
  206.       SetOPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
  207.       SetAPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
  208.       SetBPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
  209.       Type = Random(0) * 5 / 32768;
  210.       switch (Type)
  211.       {
  212.     case 0:
  213.          Circle(BabyWindow->RPort, YSize, X, Y);
  214.          break;
  215.     default:
  216.          Polygon(BabyWindow->RPort, Type + 2, YSize, X, Y);
  217.          break;
  218.       }
  219.     }
  220.   }
  221.   CleanUp(FALSE);
  222. }
  223.  
  224. Erase(RPort)
  225. struct RastPort *RPort;
  226.  
  227. /********************\
  228. *       Erase        *
  229. *       -----        *
  230. *      Clear the KeyBang window.  I know that there are more efficient ways of
  231. * doing this but this isn't too bad and that's how I coded it.
  232. \********************/
  233.  
  234. {
  235.   Move(RPort, 0, 0);
  236.   SetDrMd(RPort, JAM1);
  237.   SetAfPt(RPort, Patterns[0].Data, Patterns[0].Power);
  238.   SetOPen(RPort, 0);
  239.   SetAPen(RPort, 0);
  240.   ClearScreen(RPort);
  241.   SetDrMd(RPort, JAM2);
  242. }
  243.  
  244. Polygon(RPort, Vertices, Size, X, Y)
  245. struct RastPort *RPort;
  246. int Size, X, Y;
  247.  
  248. /********************\
  249. *      Polygon       *
  250. *      -------       *
  251. *      Draw a polygon with "Vertices" vertices and "Size" pixels high centered
  252. * at "X", "Y".  Polygons are corrected for the aspect ratio of the screen.  The
  253. * AreaInfo and TmpRas structures of the window into which the polygon is to
  254. * be drawn must be properly initialized.  See Initialize.
  255. \********************/
  256.  
  257. {
  258.   int Phase, XPos, YPos, i;
  259.  
  260.   Phase = Random(0) * SINETABENTRIES / 32768;
  261.   XPos = Size * SineTab[Phase] / 128;
  262.   YPos = Size * SineTab[(Phase + SINETABENTRIES / 4) % SINETABENTRIES] / 128;
  263.   AreaMove(RPort, X + 2 * XPos * XDPM / YDPM, Y + YPos);
  264.   for (i = 1; i < Vertices; i++)
  265.   {
  266.     XPos = Size * SineTab[(i * SINETABENTRIES / Vertices + Phase)
  267.               % SINETABENTRIES] / 128;
  268.     YPos = Size * SineTab[(i * SINETABENTRIES / Vertices + Phase +
  269.                SINETABENTRIES / 4) % SINETABENTRIES] / 128;
  270.     AreaDraw(RPort, X + 2 * XDPM * XPos / YDPM, Y + YPos);
  271.   }
  272.   AreaEnd(RPort);
  273. }
  274.  
  275. int Circle(RPort, Size, X, Y)
  276. struct RastPort *RPort;
  277. int Size, X, Y;
  278.  
  279. /********************\
  280. *       Circle       *
  281. *       ------       *
  282. *      Draw a circle "Size" pixels high centered at "X", "Y".  Circles are
  283. * corrected for the aspect ratio of the screen.  The AreaInfo and TmpRas
  284. * structures of the window into which the circle is to be drawn must be
  285. * properly initialized.  See Initialize.
  286. \********************/
  287.  
  288. {
  289.   AreaEllipse(RPort, X, Y, 2 * Size * XDPM / YDPM, Size);
  290.   AreaEnd(RPort);
  291. }
  292.  
  293.  
  294. Initialize()
  295.  
  296. /********************\
  297. *     Initialize     *
  298. *     ----------     *
  299. *      Allocates all of the resources that are used by the program.  If some
  300. * of the resources are not available, this routine does not return.
  301. \********************/
  302.  
  303. {
  304.   struct NewWindow NewWindow;
  305.   struct NewScreen NewScreen;
  306.   SHORT *VectorTable;
  307.   static UBYTE AudioChannels[] = {3, 5, 10, 12};
  308.   extern struct Library *SysBase;
  309.   int i, Width, Length;
  310.   struct Process *ThisProcess;
  311.  
  312.   /* Open libraries */
  313.  
  314.   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 29);
  315.   if (IntuitionBase == NULL)
  316.     CleanUp(FALSE);
  317.   GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 29);
  318.   if (GfxBase == NULL)
  319.     CleanUp(FALSE);
  320.  
  321.   /* Get display size and aspect ratio from GfxBase */
  322.  
  323.   XDPM = GfxBase->NormalDPMX;
  324.   YDPM = GfxBase->NormalDPMY;
  325.   WinX = GfxBase->NormalDisplayColumns;
  326.   WinY = GfxBase->NormalDisplayRows;
  327.  
  328.   /* Open the screen */
  329.  
  330.   NewScreen.LeftEdge = 0;
  331.   NewScreen.TopEdge = 0;
  332.   NewScreen.Width = WinX;
  333.   NewScreen.Height = WinY;
  334.   NewScreen.Depth = Depth;
  335.   NewScreen.DetailPen = 1;
  336.   NewScreen.BlockPen = 1;
  337.   NewScreen.ViewModes = HIRES;
  338.   NewScreen.Type = CUSTOMSCREEN;
  339.   NewScreen.Font = NULL;
  340.   NewScreen.DefaultTitle = (UBYTE *)ScreenTitle;
  341.   NewScreen.Gadgets = NULL;
  342.   NewScreen.CustomBitMap = NULL;
  343.   if ((BabyScreen = (struct Screen *)OpenScreen(&NewScreen)) == NULL)
  344.     CleanUp(FALSE);
  345.  
  346.   /* Open the window */
  347.  
  348.   NewWindow.LeftEdge = 0;
  349.   NewWindow.TopEdge = 0;
  350.   NewWindow.Width = WinX;
  351.   NewWindow.Height = WinY;
  352.   NewWindow.DetailPen = 1;
  353.   NewWindow.BlockPen = 1;
  354.   NewWindow.IDCMPFlags = MOUSEBUTTONS;
  355.   NewWindow.Flags = SIMPLE_REFRESH | BORDERLESS | ACTIVATE | BACKDROP | RMBTRAP;
  356.   NewWindow.FirstGadget = NULL;
  357.   NewWindow.CheckMark = NULL;
  358.   NewWindow.Title = NULL;
  359.   NewWindow.Screen = BabyScreen;
  360.   NewWindow.BitMap = NULL;
  361.   NewWindow.MinWidth = WinX;
  362.   NewWindow.MinHeight = WinY;
  363.   NewWindow.MaxWidth = WinX;
  364.   NewWindow.MaxHeight = WinY;
  365.   NewWindow.Type = CUSTOMSCREEN;
  366.   LoadRGB4(&BabyScreen->ViewPort, &ColorTable[0], 1 << Depth);
  367.   if ((BabyWindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
  368.     CleanUp(FALSE);
  369.  
  370.   /* Make system requexters come up on this screen */
  371.  
  372.   ThisProcess = (struct Process *)FindTask(0);
  373.   OldWindow = ThisProcess->pr_WindowPtr;
  374.   ThisProcess->pr_WindowPtr = (APTR)BabyWindow;
  375.  
  376.   /* Hide the screen title bar */
  377.  
  378.   ShowTitle(BabyScreen, FALSE);
  379.  
  380.   /* Open the message window */
  381.  
  382.   Width = 0;
  383.   for (i = 0; i < MESSAGELINES; i++)
  384.   {
  385.     Length = TextLength(BabyWindow->RPort, Message[i], strlen(Message[i]));
  386.     if (Length + 16 > Width) Width = Length + 16;
  387.   } 
  388.   NewWindow.LeftEdge = WinX / 2 - Width / 2;
  389.   NewWindow.TopEdge = 30;
  390.   NewWindow.Width = Width;
  391.   NewWindow.Height = 100;
  392.   NewWindow.IDCMPFlags = NULL;
  393.   NewWindow.Flags = SIMPLE_REFRESH;
  394.   NewWindow.Title = (UBYTE *)ScreenTitle;
  395.   NewWindow.MinWidth = Width;
  396.   NewWindow.MinHeight = 100;
  397.   NewWindow.MaxWidth = Width;
  398.   NewWindow.MaxHeight = 100;
  399.   if (IntroWindow = (struct Window *)OpenWindow(&NewWindow))
  400.   {
  401.     SetAPen(IntroWindow->RPort, 1);
  402.     for (i = 0; i < MESSAGELINES; i++)
  403.     {
  404.       Length = TextLength(IntroWindow->RPort, Message[i], strlen(Message[i]));
  405.       Move(IntroWindow->RPort, Width / 2 - Length / 2, 20 + 10 * i);
  406.       Text(IntroWindow->RPort, Message[i], strlen(Message[i]));
  407.     }
  408.   }
  409.   /*  Open the AreaInfo and TmpRas structures used by the drawing routines */
  410.  
  411.   BabyWindow->RPort->TmpRas =
  412.           (struct TmpRas *)AllocRemember(&MemList, sizeof(struct TmpRas), NULL);
  413.   if (!BabyWindow->RPort->TmpRas)
  414.     CleanUp(FALSE);
  415.   if (!(BabyTmpRaster = AllocRaster(WinX, WinY)))
  416.     CleanUp(FALSE);
  417.   InitTmpRas(BabyWindow->RPort->TmpRas, BabyTmpRaster, RASSIZE(WinX, WinY));
  418.   BabyWindow->RPort->AreaInfo =
  419.       (struct AreaInfo *)AllocRemember(&MemList, sizeof(struct AreaInfo), NULL);
  420.   if (!BabyWindow->RPort->AreaInfo)
  421.     CleanUp(FALSE);
  422.   if ((VectorTable = (SHORT *)AllocRemember(&MemList, VECTORS * 5, NULL))== NULL)
  423.     CleanUp(FALSE);
  424.   InitArea(BabyWindow->RPort->AreaInfo, VectorTable, VECTORS);
  425.  
  426.   /* Make the IO reply port for audio and input IO */
  427.  
  428.   if ((IOReplyPort = CreatePort("KeyBangIO", 0)) == NULL)
  429.     CleanUp(FALSE);
  430.  
  431.   /* Make the port to receive messages from the input handler */
  432.  
  433.   if ((KeyPort = CreatePort("KeyBangKeys", 0)) == NULL)
  434.     CleanUp(FALSE);  
  435.  
  436.   /* Open the audio device */
  437.  
  438.   LoadSounds();
  439.  
  440.   if (Sounds)
  441.   {
  442.     AudioMsg = (struct IOAudio *)AllocRemember(&MemList, sizeof(struct IOAudio),
  443.                            MEMF_PUBLIC | MEMF_CLEAR);
  444.     if (AudioMsg == NULL)
  445.       CleanUp(FALSE);
  446.     AudioMsg->ioa_Request.io_Message.mn_ReplyPort = IOReplyPort;
  447.     AudioMsg->ioa_Request.io_Command = ADCMD_ALLOCATE;
  448.     AudioMsg->ioa_Request.io_Flags = ADIOF_NOWAIT;
  449.     AudioMsg->ioa_Data = AudioChannels;
  450.     AudioMsg->ioa_Length = sizeof(AudioChannels);
  451.     if (OpenDevice(AUDIONAME, 0 , AudioMsg, 0) == 0)
  452.     {
  453.       Audio = TRUE;
  454.       Unit[0] = (int)AudioMsg->ioa_Request.io_Unit & 9;
  455.       Unit[1] = (int)AudioMsg->ioa_Request.io_Unit & 6;
  456.     }
  457.   }
  458.  
  459.   /* Open the input device and install the input handler */
  460.  
  461.   if (!(InputRequest = CreateStdIO(IOReplyPort)))
  462.     CleanUp(FALSE);
  463.   if (OpenDevice("input.device", 0, InputRequest, 0))
  464.     CleanUp(FALSE);
  465.   HandlerData[0] = (int)KeyPort;
  466.   HandlerData[1] = (int)SysBase;
  467.   HandlerInfo.is_Data = (APTR)&HandlerData[0];
  468.   HandlerInfo.is_Code = BabyInputHandler;
  469.   HandlerInfo.is_Node.ln_Name = ScreenTitle;
  470.   HandlerInfo.is_Node.ln_Pri = 75;
  471.   InputRequest->io_Command = IND_ADDHANDLER;
  472.   InputRequest->io_Data = (APTR)&HandlerInfo;
  473.   DoIO(InputRequest);
  474. }
  475.  
  476. LoadSounds()
  477.  
  478. /********************\
  479. *     LoadSounds     *
  480. *     ----------     *
  481. *      Look into the sound directory and examine all the files.  Those which
  482. * contain IFF 8SVX samples are loaded into an array so that they can be 
  483. * played by MakeSound.
  484. \********************/
  485.  
  486. {
  487.   int SoundLength;
  488.   struct FileLock *SoundLock;
  489.   struct FileInfoBlock *FileInfoBlock;
  490.   struct FileHandle *File;
  491.   UBYTE *Buffer;
  492.   char FileName[128];
  493.   struct IFFHeader Header;
  494.   struct SampleInfo SampleInfo;
  495.  
  496.   Sound = (struct SoundInfo **)AllocRemember(&MemList, 100 * 4, NULL);
  497.   SoundLock = Lock(SOUNDDIRNAME, ACCESS_READ);
  498.   if (!SoundLock)
  499.     return;
  500.   FileInfoBlock = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), NULL);
  501.   Examine(SoundLock, FileInfoBlock);
  502.   while (ExNext(SoundLock, FileInfoBlock))
  503.   {
  504.     strcpy(FileName, SOUNDDIRNAME);
  505.     strcat(FileName, FileInfoBlock->fib_FileName);
  506.     File = Open(FileName, MODE_OLDFILE);
  507.     if (File)
  508.     {
  509.       Read(File, &Header, 8);
  510.       if (Header.Name == FORM)
  511.       {
  512.     Read(File, &Header, 4);
  513.     if (Header.Name == EIGHT_SVX)
  514.     {
  515.       while (Read(File, &Header, 8) > 0)
  516.       {
  517.         switch (Header.Name)
  518.         {
  519.           case VHDR:
  520.            Read(File, &SampleInfo, Header.Length);
  521.            break;
  522.           case BODY:
  523.            Buffer = (UBYTE *)AllocRemember(&MemList, Header.Length,
  524.                            MEMF_CHIP | MEMF_PUBLIC);
  525.            if (!Buffer) return;
  526.            Read(File, Buffer, Header.Length);
  527.            SoundLength = Header.Length;
  528.            break;
  529.           default:
  530.            Seek(File, Header.Length, OFFSET_CURRENT);
  531.            break;
  532.         }
  533.       }
  534.       Sound[Sounds] =(struct SoundInfo *)AllocRemember(&MemList,
  535.                         sizeof(struct SoundInfo), NULL); 
  536.       if (!Sound[Sounds]) CleanUp(FALSE);
  537.       Sound[Sounds]->Buffer = Buffer;
  538.       Sound[Sounds]->SamplePeriod = CLOCK / SampleInfo.SampleRate;
  539.       Sound[Sounds]->Volume = SampleInfo.Volume / 1024;
  540.       Sound[Sounds]->Length = SoundLength;
  541.       Sounds++;
  542.     }
  543.       }
  544.     }
  545.     Close(File);
  546.   }
  547.   UnLock(SoundLock);
  548.   FreeMem(FileInfoBlock, sizeof(struct FileInfoBlock));
  549. }
  550.  
  551. MakeSound(Sample)
  552. int Sample;
  553.  
  554. /********************\
  555. *     MakeSound      *
  556. *     ---------      *
  557. *    Play the sound "Sample". "Sample" is an index into the array of
  558. * sound samples loaded by LoadSounds.  If one of the two channels opened by
  559. * KeyBang are busy, the sound is played in the other.  If both are busy,
  560. * no sound is played.
  561. \********************/
  562.  
  563. {
  564.   BYTE *SoundData;
  565.   struct IOAudio *SoundMsg;
  566.   int i;
  567.   static int UnitNum;
  568.  
  569.   if (LeftSoundPlaying)
  570.   {
  571.     if (RightSoundPlaying)
  572.       return;
  573.     else
  574.       UnitNum = 0;
  575.   }
  576.   else
  577.   {
  578.     if (RightSoundPlaying)
  579.       UnitNum = 1;
  580.     else
  581.       UnitNum = UnitNum - 2 * UnitNum + 1;
  582.   }
  583.   if (SoundMsg = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC))
  584.   {
  585.     SoundMsg->ioa_Request.io_Message.mn_ReplyPort = IOReplyPort;
  586.     SoundMsg->ioa_Request.io_Device = AudioMsg->ioa_Request.io_Device;
  587.     SoundMsg->ioa_Request.io_Unit = (struct Unit *)Unit[UnitNum];
  588.     SoundMsg->ioa_Request.io_Command = CMD_WRITE;
  589.     SoundMsg->ioa_Request.io_Flags = ADIOF_PERVOL;
  590.     SoundMsg->ioa_AllocKey = AudioMsg->ioa_AllocKey;
  591.     SoundMsg->ioa_Length = Sound[Sample]->Length;
  592.     SoundMsg->ioa_Period = Sound[Sample]->SamplePeriod;
  593.     SoundMsg->ioa_Volume = 64;
  594.     SoundMsg->ioa_Cycles = 1;
  595.     SoundMsg->ioa_Data = Sound[Sample]->Buffer;
  596.     BeginIO(SoundMsg);
  597.     if (Unit[UnitNum] & 9)
  598.       RightSoundPlaying = TRUE;
  599.     if (Unit[UnitNum] & 6)
  600.       LeftSoundPlaying = TRUE;
  601.   }
  602. }
  603.  
  604. CleanUp(Flag)
  605. BOOL Flag;
  606.  
  607. /********************\
  608. *      CleanUp       *
  609. *      -------       *
  610. *      Deallocate all resources.  I have tried to reply to all messages
  611. * which may be waiting on ports before deleting them.
  612. \********************/
  613. {
  614.   struct Message *TempPointer;
  615.   struct Process *ThisProcess;
  616.  
  617.   if (Flag)
  618.     puts("Usage : KeyBang [-colors {2|4|8|16}] [-oneshape]");
  619.   if (InputRequest)
  620.   {
  621.     InputRequest->io_Command = IND_REMHANDLER;
  622.     InputRequest->io_Data = (APTR)&HandlerInfo;
  623.     DoIO(InputRequest);
  624.     CloseDevice(InputRequest);
  625.     DeleteStdIO(InputRequest);
  626.   }
  627.   if (Audio) CloseDevice(AudioMsg);
  628.   if (IOReplyPort)
  629.     DeletePort(IOReplyPort);
  630.   if (KeyPort)
  631.   {
  632.     while (TempPointer = GetMsg(KeyPort))
  633.       FreeMem(TempPointer, sizeof(struct MyInputEvent));
  634.     DeletePort(KeyPort);
  635.   }
  636.   if (BabyTmpRaster) FreeRaster(BabyTmpRaster, WinX, WinY);
  637.   if (IntroWindow) CloseWindow(IntroWindow);
  638.   if (BabyWindow)
  639.   {
  640.     ThisProcess = (struct Process *)FindTask(0);
  641.     ThisProcess->pr_WindowPtr = OldWindow;
  642.     CloseWindow(BabyWindow);
  643.   }
  644.   if (BabyScreen) CloseScreen(BabyScreen);
  645.   if (MemList) FreeRemember(&MemList, TRUE);
  646.   if (GfxBase) CloseLibrary(GfxBase);
  647.   if (IntuitionBase) CloseLibrary(IntuitionBase);
  648.   exit(0);
  649. }
  650.  
  651. int Random(UserSeed)
  652. unsigned long int UserSeed;
  653.  
  654. {
  655.   static unsigned long int Seed;
  656.  
  657.   if (UserSeed) Seed = UserSeed;
  658.   Seed = Seed * 1103515245 + 12345;
  659.   return (unsigned int)(Seed/65536) % 32768;
  660. }
  661.